diff --git a/004ec9e5.42e25d86.js b/004ec9e5.4f0152e2.js similarity index 97% rename from 004ec9e5.42e25d86.js rename to 004ec9e5.4f0152e2.js index 3ac60c9b3b..805f0c6add 100644 --- a/004ec9e5.42e25d86.js +++ b/004ec9e5.4f0152e2.js @@ -1,2 +1,2 @@ -/*! For license information please see 004ec9e5.42e25d86.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{153:function(n,t,e){"use strict";e.r(t);e(425);var r=e(0),u=e.n(r),i=e(442),a=e(513),o=e(427);t.default=function(n){var t=n.metadata,e=n.items,r=t.allTagsPath,c=t.name,l=t.count;return u.a.createElement(i.a,{title:'Guides tagged "'+c+'"',description:'Guide | Tagged "'+c+'"'},u.a.createElement("header",{className:"hero hero--clean"},u.a.createElement("div",{className:"container"},u.a.createElement("h1",null,l," ",function(n,t){return n>1?t+"s":t}(l,"guide"),' tagged with "',c,'"'),u.a.createElement("div",{className:"hero--subtitle"},u.a.createElement(o.a,{href:r},"View All Tags")))),u.a.createElement("main",{className:"container container--s"},u.a.createElement(a.a,{items:e})))}},420:function(n,t,e){var r;!function(){"use strict";var e={}.hasOwnProperty;function u(){for(var n=[],t=0;t1?arguments[1]:void 0)}}),e(74)("find")},442:function(n,t,e){"use strict";e(454);var r=e(0),u=e.n(r),i=e(455),a=e(440),o=e(1),c=(e(443),e(444),e(456),e(427)),l=e(457),f=e(437),s=e.n(f),v=e(458),h=e.n(v),d=e(433),p=e(420),g=e.n(p),D=e(135),_=e.n(D),m=function(){return u.a.createElement("span",{className:g()(_.a.toggle,_.a.moon)})},y=function(){return u.a.createElement("span",{className:g()(_.a.toggle,_.a.sun)})},b=function(n){var t=Object(d.a)().isClient;return u.a.createElement(h.a,Object(o.a)({disabled:!t,icons:{checked:u.a.createElement(m,null),unchecked:u.a.createElement(y,null)}},n))};function E(){var n=Object(d.a)().siteConfig,t=(void 0===n?{}:n).customFields.metadata.latest_post,e=Date.parse(t.date),r=new Date,u=Math.abs(r-e),i=Math.ceil(u/864e5),a=null;return"undefined"!=typeof window&&(a=new Date(parseInt(window.localStorage.getItem("blogViewedAt")||"0"))),i<30&&(!a||a0&&u.a.createElement("div",{className:"row footer__links"},u.a.createElement("div",{className:"col col--5 footer__col"},u.a.createElement("div",{className:"margin-bottom--md"},u.a.createElement(s.a,{className:"navbar__logo",src:h,alt:"Qovery",width:"150",height:"auto"})),u.a.createElement("div",{className:"margin-bottom--md"},u.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),u.a.createElement("div",null,u.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},u.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",u.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},u.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",u.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},u.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",u.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},u.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),c.map((function(n,t){return u.a.createElement("div",{key:t,className:"col footer__col"},null!=n.title?u.a.createElement("h4",{className:"footer__title"},n.title):null,null!=n.items&&Array.isArray(n.items)&&n.items.length>0?u.a.createElement("ul",{className:"footer__items"},n.items.map((function(n,t){return n.html?u.a.createElement("li",{key:t,className:"footer__item",dangerouslySetInnerHTML:{__html:n.html}}):u.a.createElement("li",{key:n.href||n.to,className:"footer__item"},u.a.createElement(R,n))}))):null)}))),(f||a)&&u.a.createElement("div",{className:"text--center"},f&&f.src&&u.a.createElement("div",{className:"margin-bottom--sm"},f.href?u.a.createElement("a",{href:f.href,target:"_blank",rel:"noopener noreferrer",className:L.a.footerLogoLink},u.a.createElement(T,{alt:f.alt,url:v})):u.a.createElement(T,{alt:f.alt,url:v})),u.a.createElement("small",null,a),u.a.createElement("br",null))))},W=e(459),M=e(460),U=e(3);e(138);t.a=function(n){var t=Object(d.a)().siteConfig,e=void 0===t?{}:t,r=e.favicon,o=(e.tagline,e.title),c=e.themeConfig.image,l=e.url,f=n.children,s=n.title,v=n.noFooter,h=n.description,p=n.image,g=n.keywords,D=(n.permalink,n.version),_=s?s+" | "+o:o,m=p||c,y=l+Object(F.a)(m),b=Object(F.a)(r),E=Object(U.h)(),w=E?"https://docs.qovery.com"+(E.pathname.endsWith("/")?E.pathname:E.pathname+"/"):null;return u.a.createElement(M.a,null,u.a.createElement(W.a,null,u.a.createElement(a.a,null,u.a.createElement("html",{lang:"en"}),u.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),_&&u.a.createElement("title",null,_),_&&u.a.createElement("meta",{property:"og:title",content:_}),r&&u.a.createElement("link",{rel:"shortcut icon",href:b}),h&&u.a.createElement("meta",{name:"description",content:h}),h&&u.a.createElement("meta",{property:"og:description",content:h}),D&&u.a.createElement("meta",{name:"docsearch:version",content:D}),g&&g.length&&u.a.createElement("meta",{name:"keywords",content:g.join(",")}),m&&u.a.createElement("meta",{property:"og:image",content:y}),m&&u.a.createElement("meta",{property:"twitter:image",content:y}),m&&u.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+_}),w&&u.a.createElement("meta",{property:"og:url",content:w}),u.a.createElement("meta",{name:"twitter:card",content:"summary"}),w&&u.a.createElement("link",{rel:"canonical",href:w})),u.a.createElement(i.a,null),u.a.createElement(B,null),u.a.createElement("div",{className:"main-wrapper"},f),!v&&u.a.createElement(z,null)))}},447:function(n,t,e){"use strict";var r=e(9),u=e(0),i=e.n(u),a=e(420),o=e.n(a),c=e(433),l=(e(139),e(140)),f=e.n(l);t.a=function(n){return function(t){var e,u=t.id,a=Object(r.a)(t,["id"]),l=Object(c.a)().siteConfig,s=(l=void 0===l?{}:l).themeConfig,v=(s=void 0===s?{}:s).navbar,h=(v=void 0===v?{}:v).hideOnScroll,d=void 0!==h&&h;return u?i.a.createElement(n,a,i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:o()("anchor",(e={},e[f.a.enhancedAnchor]=!d,e)),id:u}),i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+u,title:"Direct link to heading"},"#"),a.children):i.a.createElement(n,a)}}},448:function(n,t,e){(function(n,r){var u;(function(){var i="Expected a function",a="__lodash_placeholder__",o=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],c="[object Arguments]",l="[object Array]",f="[object Boolean]",s="[object Date]",v="[object Error]",h="[object Function]",d="[object GeneratorFunction]",p="[object Map]",g="[object Number]",D="[object Object]",_="[object RegExp]",m="[object Set]",y="[object String]",b="[object Symbol]",E="[object WeakMap]",w="[object ArrayBuffer]",F="[object DataView]",C="[object Float32Array]",k="[object Float64Array]",A="[object Int8Array]",x="[object Int16Array]",j="[object Int32Array]",O="[object Uint8Array]",N="[object Uint16Array]",B="[object Uint32Array]",I=/\b__p \+= '';/g,S=/\b(__p \+=) '' \+/g,L=/(__e\(.*?\)|\b__t\)) \+\n'';/g,R=/&(?:amp|lt|gt|quot|#39);/g,T=/[&<>"']/g,z=RegExp(R.source),W=RegExp(T.source),M=/<%-([\s\S]+?)%>/g,U=/<%([\s\S]+?)%>/g,P=/<%=([\s\S]+?)%>/g,$=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,q=/^\w*$/,V=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,G=/[\\^$.*+?()[\]{}|]/g,Z=RegExp(G.source),K=/^\s+|\s+$/g,H=/^\s+/,Q=/\s+$/,J=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Y=/\{\n\/\* \[wrapped with (.+)\] \*/,X=/,? & /,nn=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,tn=/\\(\\)?/g,en=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,rn=/\w*$/,un=/^[-+]0x[0-9a-f]+$/i,an=/^0b[01]+$/i,on=/^\[object .+?Constructor\]$/,cn=/^0o[0-7]+$/i,ln=/^(?:0|[1-9]\d*)$/,fn=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,sn=/($^)/,vn=/['\n\r\u2028\u2029\\]/g,hn="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",dn="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",pn="[\\ud800-\\udfff]",gn="["+dn+"]",Dn="["+hn+"]",_n="\\d+",mn="[\\u2700-\\u27bf]",yn="[a-z\\xdf-\\xf6\\xf8-\\xff]",bn="[^\\ud800-\\udfff"+dn+_n+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",En="\\ud83c[\\udffb-\\udfff]",wn="[^\\ud800-\\udfff]",Fn="(?:\\ud83c[\\udde6-\\uddff]){2}",Cn="[\\ud800-\\udbff][\\udc00-\\udfff]",kn="[A-Z\\xc0-\\xd6\\xd8-\\xde]",An="(?:"+yn+"|"+bn+")",xn="(?:"+kn+"|"+bn+")",jn="(?:"+Dn+"|"+En+")"+"?",On="[\\ufe0e\\ufe0f]?"+jn+("(?:\\u200d(?:"+[wn,Fn,Cn].join("|")+")[\\ufe0e\\ufe0f]?"+jn+")*"),Nn="(?:"+[mn,Fn,Cn].join("|")+")"+On,Bn="(?:"+[wn+Dn+"?",Dn,Fn,Cn,pn].join("|")+")",In=RegExp("['\u2019]","g"),Sn=RegExp(Dn,"g"),Ln=RegExp(En+"(?="+En+")|"+Bn+On,"g"),Rn=RegExp([kn+"?"+yn+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?="+[gn,kn,"$"].join("|")+")",xn+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?="+[gn,kn+An,"$"].join("|")+")",kn+"?"+An+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?",kn+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",_n,Nn].join("|"),"g"),Tn=RegExp("[\\u200d\\ud800-\\udfff"+hn+"\\ufe0e\\ufe0f]"),zn=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Wn=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Mn=-1,Un={};Un[C]=Un[k]=Un[A]=Un[x]=Un[j]=Un[O]=Un["[object Uint8ClampedArray]"]=Un[N]=Un[B]=!0,Un[c]=Un[l]=Un[w]=Un[f]=Un[F]=Un[s]=Un[v]=Un[h]=Un[p]=Un[g]=Un[D]=Un[_]=Un[m]=Un[y]=Un[E]=!1;var Pn={};Pn[c]=Pn[l]=Pn[w]=Pn[F]=Pn[f]=Pn[s]=Pn[C]=Pn[k]=Pn[A]=Pn[x]=Pn[j]=Pn[p]=Pn[g]=Pn[D]=Pn[_]=Pn[m]=Pn[y]=Pn[b]=Pn[O]=Pn["[object Uint8ClampedArray]"]=Pn[N]=Pn[B]=!0,Pn[v]=Pn[h]=Pn[E]=!1;var $n={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},qn=parseFloat,Vn=parseInt,Gn="object"==typeof n&&n&&n.Object===Object&&n,Zn="object"==typeof self&&self&&self.Object===Object&&self,Kn=Gn||Zn||Function("return this")(),Hn=t&&!t.nodeType&&t,Qn=Hn&&"object"==typeof r&&r&&!r.nodeType&&r,Jn=Qn&&Qn.exports===Hn,Yn=Jn&&Gn.process,Xn=function(){try{var n=Qn&&Qn.require&&Qn.require("util").types;return n||Yn&&Yn.binding&&Yn.binding("util")}catch(t){}}(),nt=Xn&&Xn.isArrayBuffer,tt=Xn&&Xn.isDate,et=Xn&&Xn.isMap,rt=Xn&&Xn.isRegExp,ut=Xn&&Xn.isSet,it=Xn&&Xn.isTypedArray;function at(n,t,e){switch(e.length){case 0:return n.call(t);case 1:return n.call(t,e[0]);case 2:return n.call(t,e[0],e[1]);case 3:return n.call(t,e[0],e[1],e[2])}return n.apply(t,e)}function ot(n,t,e,r){for(var u=-1,i=null==n?0:n.length;++u-1}function ht(n,t,e){for(var r=-1,u=null==n?0:n.length;++r-1;);return e}function Lt(n,t){for(var e=n.length;e--&&Et(t,n[e],0)>-1;);return e}function Rt(n,t){for(var e=n.length,r=0;e--;)n[e]===t&&++r;return r}var Tt=At({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),zt=At({"&":"&","<":"<",">":">",'"':""","'":"'"});function Wt(n){return"\\"+$n[n]}function Mt(n){return Tn.test(n)}function Ut(n){var t=-1,e=Array(n.size);return n.forEach((function(n,r){e[++t]=[r,n]})),e}function Pt(n,t){return function(e){return n(t(e))}}function $t(n,t){for(var e=-1,r=n.length,u=0,i=[];++e",""":'"',"'":"'"});var Ht=function n(t){var e,r=(t=null==t?Kn:Ht.defaults(Kn.Object(),t,Ht.pick(Kn,Wn))).Array,u=t.Date,hn=t.Error,dn=t.Function,pn=t.Math,gn=t.Object,Dn=t.RegExp,_n=t.String,mn=t.TypeError,yn=r.prototype,bn=dn.prototype,En=gn.prototype,wn=t["__core-js_shared__"],Fn=bn.toString,Cn=En.hasOwnProperty,kn=0,An=(e=/[^.]+$/.exec(wn&&wn.keys&&wn.keys.IE_PROTO||""))?"Symbol(src)_1."+e:"",xn=En.toString,jn=Fn.call(gn),On=Kn._,Nn=Dn("^"+Fn.call(Cn).replace(G,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Bn=Jn?t.Buffer:void 0,Ln=t.Symbol,Tn=t.Uint8Array,$n=Bn?Bn.allocUnsafe:void 0,Gn=Pt(gn.getPrototypeOf,gn),Zn=gn.create,Hn=En.propertyIsEnumerable,Qn=yn.splice,Yn=Ln?Ln.isConcatSpreadable:void 0,Xn=Ln?Ln.iterator:void 0,mt=Ln?Ln.toStringTag:void 0,At=function(){try{var n=Xu(gn,"defineProperty");return n({},"",{}),n}catch(t){}}(),Qt=t.clearTimeout!==Kn.clearTimeout&&t.clearTimeout,Jt=u&&u.now!==Kn.Date.now&&u.now,Yt=t.setTimeout!==Kn.setTimeout&&t.setTimeout,Xt=pn.ceil,ne=pn.floor,te=gn.getOwnPropertySymbols,ee=Bn?Bn.isBuffer:void 0,re=t.isFinite,ue=yn.join,ie=Pt(gn.keys,gn),ae=pn.max,oe=pn.min,ce=u.now,le=t.parseInt,fe=pn.random,se=yn.reverse,ve=Xu(t,"DataView"),he=Xu(t,"Map"),de=Xu(t,"Promise"),pe=Xu(t,"Set"),ge=Xu(t,"WeakMap"),De=Xu(gn,"create"),_e=ge&&new ge,me={},ye=ki(ve),be=ki(he),Ee=ki(de),we=ki(pe),Fe=ki(ge),Ce=Ln?Ln.prototype:void 0,ke=Ce?Ce.valueOf:void 0,Ae=Ce?Ce.toString:void 0;function xe(n){if($a(n)&&!Ba(n)&&!(n instanceof Be)){if(n instanceof Ne)return n;if(Cn.call(n,"__wrapped__"))return Ai(n)}return new Ne(n)}var je=function(){function n(){}return function(t){if(!Pa(t))return{};if(Zn)return Zn(t);n.prototype=t;var e=new n;return n.prototype=void 0,e}}();function Oe(){}function Ne(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=void 0}function Be(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Ie(n){var t=-1,e=null==n?0:n.length;for(this.clear();++t=t?n:t)),n}function Qe(n,t,e,r,u,i){var a,o=1&t,l=2&t,v=4&t;if(e&&(a=u?e(n,r,u,i):e(n)),void 0!==a)return a;if(!Pa(n))return n;var E=Ba(n);if(E){if(a=function(n){var t=n.length,e=new n.constructor(t);t&&"string"==typeof n[0]&&Cn.call(n,"index")&&(e.index=n.index,e.input=n.input);return e}(n),!o)return Du(n,a)}else{var I=ei(n),S=I==h||I==d;if(Ra(n))return su(n,o);if(I==D||I==c||S&&!u){if(a=l||S?{}:ui(n),!o)return l?function(n,t){return _u(n,ti(n),t)}(n,function(n,t){return n&&_u(t,bo(t),n)}(a,n)):function(n,t){return _u(n,ni(n),t)}(n,Ge(a,n))}else{if(!Pn[I])return u?n:{};a=function(n,t,e){var r=n.constructor;switch(t){case w:return vu(n);case f:case s:return new r(+n);case F:return function(n,t){var e=t?vu(n.buffer):n.buffer;return new n.constructor(e,n.byteOffset,n.byteLength)}(n,e);case C:case k:case A:case x:case j:case O:case"[object Uint8ClampedArray]":case N:case B:return hu(n,e);case p:return new r;case g:case y:return new r(n);case _:return function(n){var t=new n.constructor(n.source,rn.exec(n));return t.lastIndex=n.lastIndex,t}(n);case m:return new r;case b:return u=n,ke?gn(ke.call(u)):{}}var u}(n,I,o)}}i||(i=new Te);var L=i.get(n);if(L)return L;i.set(n,a),Ka(n)?n.forEach((function(r){a.add(Qe(r,t,e,r,n,i))})):qa(n)&&n.forEach((function(r,u){a.set(u,Qe(r,t,e,u,n,i))}));var R=E?void 0:(v?l?Gu:Vu:l?bo:yo)(n);return ct(R||n,(function(r,u){R&&(r=n[u=r]),$e(a,u,Qe(r,t,e,u,n,i))})),a}function Je(n,t,e){var r=e.length;if(null==n)return!r;for(n=gn(n);r--;){var u=e[r],i=t[u],a=n[u];if(void 0===a&&!(u in n)||!i(a))return!1}return!0}function Ye(n,t,e){if("function"!=typeof n)throw new mn(i);return mi((function(){n.apply(void 0,e)}),t)}function Xe(n,t,e,r){var u=-1,i=vt,a=!0,o=n.length,c=[],l=t.length;if(!o)return c;e&&(t=dt(t,Nt(e))),r?(i=ht,a=!1):t.length>=200&&(i=It,a=!1,t=new Re(t));n:for(;++u-1},Se.prototype.set=function(n,t){var e=this.__data__,r=qe(e,n);return r<0?(++this.size,e.push([n,t])):e[r][1]=t,this},Le.prototype.clear=function(){this.size=0,this.__data__={hash:new Ie,map:new(he||Se),string:new Ie}},Le.prototype.delete=function(n){var t=Ju(this,n).delete(n);return this.size-=t?1:0,t},Le.prototype.get=function(n){return Ju(this,n).get(n)},Le.prototype.has=function(n){return Ju(this,n).has(n)},Le.prototype.set=function(n,t){var e=Ju(this,n),r=e.size;return e.set(n,t),this.size+=e.size==r?0:1,this},Re.prototype.add=Re.prototype.push=function(n){return this.__data__.set(n,"__lodash_hash_undefined__"),this},Re.prototype.has=function(n){return this.__data__.has(n)},Te.prototype.clear=function(){this.__data__=new Se,this.size=0},Te.prototype.delete=function(n){var t=this.__data__,e=t.delete(n);return this.size=t.size,e},Te.prototype.get=function(n){return this.__data__.get(n)},Te.prototype.has=function(n){return this.__data__.has(n)},Te.prototype.set=function(n,t){var e=this.__data__;if(e instanceof Se){var r=e.__data__;if(!he||r.length<199)return r.push([n,t]),this.size=++e.size,this;e=this.__data__=new Le(r)}return e.set(n,t),this.size=e.size,this};var nr=bu(cr),tr=bu(lr,!0);function er(n,t){var e=!0;return nr(n,(function(n,r,u){return e=!!t(n,r,u)})),e}function rr(n,t,e){for(var r=-1,u=n.length;++r0&&e(o)?t>1?ir(o,t-1,e,r,u):pt(u,o):r||(u[u.length]=o)}return u}var ar=Eu(),or=Eu(!0);function cr(n,t){return n&&ar(n,t,yo)}function lr(n,t){return n&&or(n,t,yo)}function fr(n,t){return st(t,(function(t){return Wa(n[t])}))}function sr(n,t){for(var e=0,r=(t=ou(t,n)).length;null!=n&&et}function pr(n,t){return null!=n&&Cn.call(n,t)}function gr(n,t){return null!=n&&t in gn(n)}function Dr(n,t,e){for(var u=e?ht:vt,i=n[0].length,a=n.length,o=a,c=r(a),l=1/0,f=[];o--;){var s=n[o];o&&t&&(s=dt(s,Nt(t))),l=oe(s.length,l),c[o]=!e&&(t||i>=120&&s.length>=120)?new Re(o&&s):void 0}s=n[0];var v=-1,h=c[0];n:for(;++v=o)return c;var l=e[r];return c*("desc"==l?-1:1)}}return n.index-t.index}(n,t,e)}))}function Ir(n,t,e){for(var r=-1,u=t.length,i={};++r-1;)o!==n&&Qn.call(o,c,1),Qn.call(n,c,1);return n}function Lr(n,t){for(var e=n?t.length:0,r=e-1;e--;){var u=t[e];if(e==r||u!==i){var i=u;ai(u)?Qn.call(n,u,1):Xr(n,u)}}return n}function Rr(n,t){return n+ne(fe()*(t-n+1))}function Tr(n,t){var e="";if(!n||t<1||t>9007199254740991)return e;do{t%2&&(e+=n),(t=ne(t/2))&&(n+=n)}while(t);return e}function zr(n,t){return yi(di(n,t,Go),n+"")}function Wr(n){return We(jo(n))}function Mr(n,t){var e=jo(n);return wi(e,He(t,0,e.length))}function Ur(n,t,e,r){if(!Pa(n))return n;for(var u=-1,i=(t=ou(t,n)).length,a=i-1,o=n;null!=o&&++ui?0:i+t),(e=e>i?i:e)<0&&(e+=i),i=t>e?0:e-t>>>0,t>>>=0;for(var a=r(i);++u>>1,a=n[i];null!==a&&!Qa(a)&&(e?a<=t:a=200){var l=t?null:Tu(n);if(l)return qt(l);a=!1,u=It,c=new Re}else c=t?[]:o;n:for(;++r=r?n:Vr(n,t,e)}var fu=Qt||function(n){return Kn.clearTimeout(n)};function su(n,t){if(t)return n.slice();var e=n.length,r=$n?$n(e):new n.constructor(e);return n.copy(r),r}function vu(n){var t=new n.constructor(n.byteLength);return new Tn(t).set(new Tn(n)),t}function hu(n,t){var e=t?vu(n.buffer):n.buffer;return new n.constructor(e,n.byteOffset,n.length)}function du(n,t){if(n!==t){var e=void 0!==n,r=null===n,u=n==n,i=Qa(n),a=void 0!==t,o=null===t,c=t==t,l=Qa(t);if(!o&&!l&&!i&&n>t||i&&a&&c&&!o&&!l||r&&a&&c||!e&&c||!u)return 1;if(!r&&!i&&!l&&n1?e[u-1]:void 0,a=u>2?e[2]:void 0;for(i=n.length>3&&"function"==typeof i?(u--,i):void 0,a&&oi(e[0],e[1],a)&&(i=u<3?void 0:i,u=1),t=gn(t);++r-1?u[i?t[a]:a]:void 0}}function Au(n){return qu((function(t){var e=t.length,r=e,u=Ne.prototype.thru;for(n&&t.reverse();r--;){var a=t[r];if("function"!=typeof a)throw new mn(i);if(u&&!o&&"wrapper"==Ku(a))var o=new Ne([],!0)}for(r=o?r:e;++r1&&m.reverse(),s&&l<_&&(m.length=l),this&&this!==Kn&&this instanceof D&&(C=g||Cu(C)),C.apply(F,m)}}function ju(n,t){return function(e,r){return function(n,t,e,r){return cr(n,(function(n,u,i){t(r,e(n),u,i)})),r}(e,n,t(r),{})}}function Ou(n,t){return function(e,r){var u;if(void 0===e&&void 0===r)return t;if(void 0!==e&&(u=e),void 0!==r){if(void 0===u)return r;"string"==typeof e||"string"==typeof r?(e=Jr(e),r=Jr(r)):(e=Qr(e),r=Qr(r)),u=n(e,r)}return u}}function Nu(n){return qu((function(t){return t=dt(t,Nt(Qu())),zr((function(e){var r=this;return n(t,(function(n){return at(n,r,e)}))}))}))}function Bu(n,t){var e=(t=void 0===t?" ":Jr(t)).length;if(e<2)return e?Tr(t,n):t;var r=Tr(t,Xt(n/Gt(t)));return Mt(t)?lu(Zt(r),0,n).join(""):r.slice(0,n)}function Iu(n){return function(t,e,u){return u&&"number"!=typeof u&&oi(t,e,u)&&(e=u=void 0),t=to(t),void 0===e?(e=t,t=0):e=to(e),function(n,t,e,u){for(var i=-1,a=ae(Xt((t-n)/(e||1)),0),o=r(a);a--;)o[u?a:++i]=n,n+=e;return o}(t,e,u=void 0===u?to))return!1;var l=i.get(n);if(l&&i.get(t))return l==t;var f=-1,s=!0,v=2&e?new Re:void 0;for(i.set(n,t),i.set(t,n);++f-1&&n%1==0&&n1?"& ":"")+t[r],t=t.join(e>2?", ":" "),n.replace(J,"{\n/* [wrapped with "+t+"] */\n")}(r,function(n,t){return ct(o,(function(e){var r="_."+e[0];t&e[1]&&!vt(n,r)&&n.push(r)})),n.sort()}(function(n){var t=n.match(Y);return t?t[1].split(X):[]}(r),e)))}function Ei(n){var t=0,e=0;return function(){var r=ce(),u=16-(r-e);if(e=r,u>0){if(++t>=800)return arguments[0]}else t=0;return n.apply(void 0,arguments)}}function wi(n,t){var e=-1,r=n.length,u=r-1;for(t=void 0===t?r:t;++e1?n[t-1]:void 0;return e="function"==typeof e?(n.pop(),e):void 0,Zi(n,e)}));function na(n){var t=xe(n);return t.__chain__=!0,t}function ta(n,t){return t(n)}var ea=qu((function(n){var t=n.length,e=t?n[0]:0,r=this.__wrapped__,u=function(t){return Ke(t,n)};return!(t>1||this.__actions__.length)&&r instanceof Be&&ai(e)?((r=r.slice(e,+e+(t?1:0))).__actions__.push({func:ta,args:[u],thisArg:void 0}),new Ne(r,this.__chain__).thru((function(n){return t&&!n.length&&n.push(void 0),n}))):this.thru(u)}));var ra=mu((function(n,t,e){Cn.call(n,e)?++n[e]:Ze(n,e,1)}));var ua=ku(Ni),ia=ku(Bi);function aa(n,t){return(Ba(n)?ct:nr)(n,Qu(t,3))}function oa(n,t){return(Ba(n)?lt:tr)(n,Qu(t,3))}var ca=mu((function(n,t,e){Cn.call(n,e)?n[e].push(t):Ze(n,e,[t])}));var la=zr((function(n,t,e){var u=-1,i="function"==typeof t,a=Sa(n)?r(n.length):[];return nr(n,(function(n){a[++u]=i?at(t,n,e):_r(n,t,e)})),a})),fa=mu((function(n,t,e){Ze(n,e,t)}));function sa(n,t){return(Ba(n)?dt:Ar)(n,Qu(t,3))}var va=mu((function(n,t,e){n[e?0:1].push(t)}),(function(){return[[],[]]}));var ha=zr((function(n,t){if(null==n)return[];var e=t.length;return e>1&&oi(n,t[0],t[1])?t=[]:e>2&&oi(t[0],t[1],t[2])&&(t=[t[0]]),Br(n,ir(t,1),[])})),da=Jt||function(){return Kn.Date.now()};function pa(n,t,e){return t=e?void 0:t,Wu(n,128,void 0,void 0,void 0,void 0,t=n&&null==t?n.length:t)}function ga(n,t){var e;if("function"!=typeof t)throw new mn(i);return n=eo(n),function(){return--n>0&&(e=t.apply(this,arguments)),n<=1&&(t=void 0),e}}var Da=zr((function(n,t,e){var r=1;if(e.length){var u=$t(e,Hu(Da));r|=32}return Wu(n,r,t,e,u)})),_a=zr((function(n,t,e){var r=3;if(e.length){var u=$t(e,Hu(_a));r|=32}return Wu(t,r,n,e,u)}));function ma(n,t,e){var r,u,a,o,c,l,f=0,s=!1,v=!1,h=!0;if("function"!=typeof n)throw new mn(i);function d(t){var e=r,i=u;return r=u=void 0,f=t,o=n.apply(i,e)}function p(n){return f=n,c=mi(D,t),s?d(n):o}function g(n){var e=n-l;return void 0===l||e>=t||e<0||v&&n-f>=a}function D(){var n=da();if(g(n))return _(n);c=mi(D,function(n){var e=t-(n-l);return v?oe(e,a-(n-f)):e}(n))}function _(n){return c=void 0,h&&r?d(n):(r=u=void 0,o)}function m(){var n=da(),e=g(n);if(r=arguments,u=this,l=n,e){if(void 0===c)return p(l);if(v)return fu(c),c=mi(D,t),d(l)}return void 0===c&&(c=mi(D,t)),o}return t=uo(t)||0,Pa(e)&&(s=!!e.leading,a=(v="maxWait"in e)?ae(uo(e.maxWait)||0,t):a,h="trailing"in e?!!e.trailing:h),m.cancel=function(){void 0!==c&&fu(c),f=0,r=l=u=c=void 0},m.flush=function(){return void 0===c?o:_(da())},m}var ya=zr((function(n,t){return Ye(n,1,t)})),ba=zr((function(n,t,e){return Ye(n,uo(t)||0,e)}));function Ea(n,t){if("function"!=typeof n||null!=t&&"function"!=typeof t)throw new mn(i);var e=function(){var r=arguments,u=t?t.apply(this,r):r[0],i=e.cache;if(i.has(u))return i.get(u);var a=n.apply(this,r);return e.cache=i.set(u,a)||i,a};return e.cache=new(Ea.Cache||Le),e}function wa(n){if("function"!=typeof n)throw new mn(i);return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}Ea.Cache=Le;var Fa=cu((function(n,t){var e=(t=1==t.length&&Ba(t[0])?dt(t[0],Nt(Qu())):dt(ir(t,1),Nt(Qu()))).length;return zr((function(r){for(var u=-1,i=oe(r.length,e);++u=t})),Na=mr(function(){return arguments}())?mr:function(n){return $a(n)&&Cn.call(n,"callee")&&!Hn.call(n,"callee")},Ba=r.isArray,Ia=nt?Nt(nt):function(n){return $a(n)&&hr(n)==w};function Sa(n){return null!=n&&Ua(n.length)&&!Wa(n)}function La(n){return $a(n)&&Sa(n)}var Ra=ee||ic,Ta=tt?Nt(tt):function(n){return $a(n)&&hr(n)==s};function za(n){if(!$a(n))return!1;var t=hr(n);return t==v||"[object DOMException]"==t||"string"==typeof n.message&&"string"==typeof n.name&&!Ga(n)}function Wa(n){if(!Pa(n))return!1;var t=hr(n);return t==h||t==d||"[object AsyncFunction]"==t||"[object Proxy]"==t}function Ma(n){return"number"==typeof n&&n==eo(n)}function Ua(n){return"number"==typeof n&&n>-1&&n%1==0&&n<=9007199254740991}function Pa(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function $a(n){return null!=n&&"object"==typeof n}var qa=et?Nt(et):function(n){return $a(n)&&ei(n)==p};function Va(n){return"number"==typeof n||$a(n)&&hr(n)==g}function Ga(n){if(!$a(n)||hr(n)!=D)return!1;var t=Gn(n);if(null===t)return!0;var e=Cn.call(t,"constructor")&&t.constructor;return"function"==typeof e&&e instanceof e&&Fn.call(e)==jn}var Za=rt?Nt(rt):function(n){return $a(n)&&hr(n)==_};var Ka=ut?Nt(ut):function(n){return $a(n)&&ei(n)==m};function Ha(n){return"string"==typeof n||!Ba(n)&&$a(n)&&hr(n)==y}function Qa(n){return"symbol"==typeof n||$a(n)&&hr(n)==b}var Ja=it?Nt(it):function(n){return $a(n)&&Ua(n.length)&&!!Un[hr(n)]};var Ya=Su(kr),Xa=Su((function(n,t){return n<=t}));function no(n){if(!n)return[];if(Sa(n))return Ha(n)?Zt(n):Du(n);if(Xn&&n[Xn])return function(n){for(var t,e=[];!(t=n.next()).done;)e.push(t.value);return e}(n[Xn]());var t=ei(n);return(t==p?Ut:t==m?qt:jo)(n)}function to(n){return n?(n=uo(n))===1/0||n===-1/0?17976931348623157e292*(n<0?-1:1):n==n?n:0:0===n?n:0}function eo(n){var t=to(n),e=t%1;return t==t?e?t-e:t:0}function ro(n){return n?He(eo(n),0,4294967295):0}function uo(n){if("number"==typeof n)return n;if(Qa(n))return NaN;if(Pa(n)){var t="function"==typeof n.valueOf?n.valueOf():n;n=Pa(t)?t+"":t}if("string"!=typeof n)return 0===n?n:+n;n=n.replace(K,"");var e=an.test(n);return e||cn.test(n)?Vn(n.slice(2),e?2:8):un.test(n)?NaN:+n}function io(n){return _u(n,bo(n))}function ao(n){return null==n?"":Jr(n)}var oo=yu((function(n,t){if(si(t)||Sa(t))_u(t,yo(t),n);else for(var e in t)Cn.call(t,e)&&$e(n,e,t[e])})),co=yu((function(n,t){_u(t,bo(t),n)})),lo=yu((function(n,t,e,r){_u(t,bo(t),n,r)})),fo=yu((function(n,t,e,r){_u(t,yo(t),n,r)})),so=qu(Ke);var vo=zr((function(n,t){n=gn(n);var e=-1,r=t.length,u=r>2?t[2]:void 0;for(u&&oi(t[0],t[1],u)&&(r=1);++e1),t})),_u(n,Gu(n),e),r&&(e=Qe(e,7,Pu));for(var u=t.length;u--;)Xr(e,t[u]);return e}));var Co=qu((function(n,t){return null==n?{}:function(n,t){return Ir(n,t,(function(t,e){return go(n,e)}))}(n,t)}));function ko(n,t){if(null==n)return{};var e=dt(Gu(n),(function(n){return[n]}));return t=Qu(t),Ir(n,e,(function(n,e){return t(n,e[0])}))}var Ao=zu(yo),xo=zu(bo);function jo(n){return null==n?[]:Bt(n,yo(n))}var Oo=Fu((function(n,t,e){return t=t.toLowerCase(),n+(e?No(t):t)}));function No(n){return Wo(ao(n).toLowerCase())}function Bo(n){return(n=ao(n))&&n.replace(fn,Tt).replace(Sn,"")}var Io=Fu((function(n,t,e){return n+(e?"-":"")+t.toLowerCase()})),So=Fu((function(n,t,e){return n+(e?" ":"")+t.toLowerCase()})),Lo=wu("toLowerCase");var Ro=Fu((function(n,t,e){return n+(e?"_":"")+t.toLowerCase()}));var To=Fu((function(n,t,e){return n+(e?" ":"")+Wo(t)}));var zo=Fu((function(n,t,e){return n+(e?" ":"")+t.toUpperCase()})),Wo=wu("toUpperCase");function Mo(n,t,e){return n=ao(n),void 0===(t=e?void 0:t)?function(n){return zn.test(n)}(n)?function(n){return n.match(Rn)||[]}(n):function(n){return n.match(nn)||[]}(n):n.match(t)||[]}var Uo=zr((function(n,t){try{return at(n,void 0,t)}catch(e){return za(e)?e:new hn(e)}})),Po=qu((function(n,t){return ct(t,(function(t){t=Ci(t),Ze(n,t,Da(n[t],n))})),n}));function $o(n){return function(){return n}}var qo=Au(),Vo=Au(!0);function Go(n){return n}function Zo(n){return wr("function"==typeof n?n:Qe(n,1))}var Ko=zr((function(n,t){return function(e){return _r(e,n,t)}})),Ho=zr((function(n,t){return function(e){return _r(n,e,t)}}));function Qo(n,t,e){var r=yo(t),u=fr(t,r);null!=e||Pa(t)&&(u.length||!r.length)||(e=t,t=n,n=this,u=fr(t,yo(t)));var i=!(Pa(e)&&"chain"in e&&!e.chain),a=Wa(n);return ct(u,(function(e){var r=t[e];n[e]=r,a&&(n.prototype[e]=function(){var t=this.__chain__;if(i||t){var e=n(this.__wrapped__),u=e.__actions__=Du(this.__actions__);return u.push({func:r,args:arguments,thisArg:n}),e.__chain__=t,e}return r.apply(n,pt([this.value()],arguments))})})),n}function Jo(){}var Yo=Nu(dt),Xo=Nu(ft),nc=Nu(_t);function tc(n){return ci(n)?kt(Ci(n)):function(n){return function(t){return sr(t,n)}}(n)}var ec=Iu(),rc=Iu(!0);function uc(){return[]}function ic(){return!1}var ac=Ou((function(n,t){return n+t}),0),oc=Ru("ceil"),cc=Ou((function(n,t){return n/t}),1),lc=Ru("floor");var fc,sc=Ou((function(n,t){return n*t}),1),vc=Ru("round"),hc=Ou((function(n,t){return n-t}),0);return xe.after=function(n,t){if("function"!=typeof t)throw new mn(i);return n=eo(n),function(){if(--n<1)return t.apply(this,arguments)}},xe.ary=pa,xe.assign=oo,xe.assignIn=co,xe.assignInWith=lo,xe.assignWith=fo,xe.at=so,xe.before=ga,xe.bind=Da,xe.bindAll=Po,xe.bindKey=_a,xe.castArray=function(){if(!arguments.length)return[];var n=arguments[0];return Ba(n)?n:[n]},xe.chain=na,xe.chunk=function(n,t,e){t=(e?oi(n,t,e):void 0===t)?1:ae(eo(t),0);var u=null==n?0:n.length;if(!u||t<1)return[];for(var i=0,a=0,o=r(Xt(u/t));iu?0:u+e),(r=void 0===r||r>u?u:eo(r))<0&&(r+=u),r=e>r?0:ro(r);e>>0)?(n=ao(n))&&("string"==typeof t||null!=t&&!Za(t))&&!(t=Jr(t))&&Mt(n)?lu(Zt(n),0,e):n.split(t,e):[]},xe.spread=function(n,t){if("function"!=typeof n)throw new mn(i);return t=null==t?0:ae(eo(t),0),zr((function(e){var r=e[t],u=lu(e,0,t);return r&&pt(u,r),at(n,this,u)}))},xe.tail=function(n){var t=null==n?0:n.length;return t?Vr(n,1,t):[]},xe.take=function(n,t,e){return n&&n.length?Vr(n,0,(t=e||void 0===t?1:eo(t))<0?0:t):[]},xe.takeRight=function(n,t,e){var r=null==n?0:n.length;return r?Vr(n,(t=r-(t=e||void 0===t?1:eo(t)))<0?0:t,r):[]},xe.takeRightWhile=function(n,t){return n&&n.length?tu(n,Qu(t,3),!1,!0):[]},xe.takeWhile=function(n,t){return n&&n.length?tu(n,Qu(t,3)):[]},xe.tap=function(n,t){return t(n),n},xe.throttle=function(n,t,e){var r=!0,u=!0;if("function"!=typeof n)throw new mn(i);return Pa(e)&&(r="leading"in e?!!e.leading:r,u="trailing"in e?!!e.trailing:u),ma(n,t,{leading:r,maxWait:t,trailing:u})},xe.thru=ta,xe.toArray=no,xe.toPairs=Ao,xe.toPairsIn=xo,xe.toPath=function(n){return Ba(n)?dt(n,Ci):Qa(n)?[n]:Du(Fi(ao(n)))},xe.toPlainObject=io,xe.transform=function(n,t,e){var r=Ba(n),u=r||Ra(n)||Ja(n);if(t=Qu(t,4),null==e){var i=n&&n.constructor;e=u?r?new i:[]:Pa(n)&&Wa(i)?je(Gn(n)):{}}return(u?ct:cr)(n,(function(n,r,u){return t(e,n,r,u)})),e},xe.unary=function(n){return pa(n,1)},xe.union=$i,xe.unionBy=qi,xe.unionWith=Vi,xe.uniq=function(n){return n&&n.length?Yr(n):[]},xe.uniqBy=function(n,t){return n&&n.length?Yr(n,Qu(t,2)):[]},xe.uniqWith=function(n,t){return t="function"==typeof t?t:void 0,n&&n.length?Yr(n,void 0,t):[]},xe.unset=function(n,t){return null==n||Xr(n,t)},xe.unzip=Gi,xe.unzipWith=Zi,xe.update=function(n,t,e){return null==n?n:nu(n,t,au(e))},xe.updateWith=function(n,t,e,r){return r="function"==typeof r?r:void 0,null==n?n:nu(n,t,au(e),r)},xe.values=jo,xe.valuesIn=function(n){return null==n?[]:Bt(n,bo(n))},xe.without=Ki,xe.words=Mo,xe.wrap=function(n,t){return Ca(au(t),n)},xe.xor=Hi,xe.xorBy=Qi,xe.xorWith=Ji,xe.zip=Yi,xe.zipObject=function(n,t){return uu(n||[],t||[],$e)},xe.zipObjectDeep=function(n,t){return uu(n||[],t||[],Ur)},xe.zipWith=Xi,xe.entries=Ao,xe.entriesIn=xo,xe.extend=co,xe.extendWith=lo,Qo(xe,xe),xe.add=ac,xe.attempt=Uo,xe.camelCase=Oo,xe.capitalize=No,xe.ceil=oc,xe.clamp=function(n,t,e){return void 0===e&&(e=t,t=void 0),void 0!==e&&(e=(e=uo(e))==e?e:0),void 0!==t&&(t=(t=uo(t))==t?t:0),He(uo(n),t,e)},xe.clone=function(n){return Qe(n,4)},xe.cloneDeep=function(n){return Qe(n,5)},xe.cloneDeepWith=function(n,t){return Qe(n,5,t="function"==typeof t?t:void 0)},xe.cloneWith=function(n,t){return Qe(n,4,t="function"==typeof t?t:void 0)},xe.conformsTo=function(n,t){return null==t||Je(n,t,yo(t))},xe.deburr=Bo,xe.defaultTo=function(n,t){return null==n||n!=n?t:n},xe.divide=cc,xe.endsWith=function(n,t,e){n=ao(n),t=Jr(t);var r=n.length,u=e=void 0===e?r:He(eo(e),0,r);return(e-=t.length)>=0&&n.slice(e,u)==t},xe.eq=xa,xe.escape=function(n){return(n=ao(n))&&W.test(n)?n.replace(T,zt):n},xe.escapeRegExp=function(n){return(n=ao(n))&&Z.test(n)?n.replace(G,"\\$&"):n},xe.every=function(n,t,e){var r=Ba(n)?ft:er;return e&&oi(n,t,e)&&(t=void 0),r(n,Qu(t,3))},xe.find=ua,xe.findIndex=Ni,xe.findKey=function(n,t){return yt(n,Qu(t,3),cr)},xe.findLast=ia,xe.findLastIndex=Bi,xe.findLastKey=function(n,t){return yt(n,Qu(t,3),lr)},xe.floor=lc,xe.forEach=aa,xe.forEachRight=oa,xe.forIn=function(n,t){return null==n?n:ar(n,Qu(t,3),bo)},xe.forInRight=function(n,t){return null==n?n:or(n,Qu(t,3),bo)},xe.forOwn=function(n,t){return n&&cr(n,Qu(t,3))},xe.forOwnRight=function(n,t){return n&&lr(n,Qu(t,3))},xe.get=po,xe.gt=ja,xe.gte=Oa,xe.has=function(n,t){return null!=n&&ri(n,t,pr)},xe.hasIn=go,xe.head=Si,xe.identity=Go,xe.includes=function(n,t,e,r){n=Sa(n)?n:jo(n),e=e&&!r?eo(e):0;var u=n.length;return e<0&&(e=ae(u+e,0)),Ha(n)?e<=u&&n.indexOf(t,e)>-1:!!u&&Et(n,t,e)>-1},xe.indexOf=function(n,t,e){var r=null==n?0:n.length;if(!r)return-1;var u=null==e?0:eo(e);return u<0&&(u=ae(r+u,0)),Et(n,t,u)},xe.inRange=function(n,t,e){return t=to(t),void 0===e?(e=t,t=0):e=to(e),function(n,t,e){return n>=oe(t,e)&&n=-9007199254740991&&n<=9007199254740991},xe.isSet=Ka,xe.isString=Ha,xe.isSymbol=Qa,xe.isTypedArray=Ja,xe.isUndefined=function(n){return void 0===n},xe.isWeakMap=function(n){return $a(n)&&ei(n)==E},xe.isWeakSet=function(n){return $a(n)&&"[object WeakSet]"==hr(n)},xe.join=function(n,t){return null==n?"":ue.call(n,t)},xe.kebabCase=Io,xe.last=zi,xe.lastIndexOf=function(n,t,e){var r=null==n?0:n.length;if(!r)return-1;var u=r;return void 0!==e&&(u=(u=eo(e))<0?ae(r+u,0):oe(u,r-1)),t==t?function(n,t,e){for(var r=e+1;r--;)if(n[r]===t)return r;return r}(n,t,u):bt(n,Ft,u,!0)},xe.lowerCase=So,xe.lowerFirst=Lo,xe.lt=Ya,xe.lte=Xa,xe.max=function(n){return n&&n.length?rr(n,Go,dr):void 0},xe.maxBy=function(n,t){return n&&n.length?rr(n,Qu(t,2),dr):void 0},xe.mean=function(n){return Ct(n,Go)},xe.meanBy=function(n,t){return Ct(n,Qu(t,2))},xe.min=function(n){return n&&n.length?rr(n,Go,kr):void 0},xe.minBy=function(n,t){return n&&n.length?rr(n,Qu(t,2),kr):void 0},xe.stubArray=uc,xe.stubFalse=ic,xe.stubObject=function(){return{}},xe.stubString=function(){return""},xe.stubTrue=function(){return!0},xe.multiply=sc,xe.nth=function(n,t){return n&&n.length?Nr(n,eo(t)):void 0},xe.noConflict=function(){return Kn._===this&&(Kn._=On),this},xe.noop=Jo,xe.now=da,xe.pad=function(n,t,e){n=ao(n);var r=(t=eo(t))?Gt(n):0;if(!t||r>=t)return n;var u=(t-r)/2;return Bu(ne(u),e)+n+Bu(Xt(u),e)},xe.padEnd=function(n,t,e){n=ao(n);var r=(t=eo(t))?Gt(n):0;return t&&rt){var r=n;n=t,t=r}if(e||n%1||t%1){var u=fe();return oe(n+u*(t-n+qn("1e-"+((u+"").length-1))),t)}return Rr(n,t)},xe.reduce=function(n,t,e){var r=Ba(n)?gt:xt,u=arguments.length<3;return r(n,Qu(t,4),e,u,nr)},xe.reduceRight=function(n,t,e){var r=Ba(n)?Dt:xt,u=arguments.length<3;return r(n,Qu(t,4),e,u,tr)},xe.repeat=function(n,t,e){return t=(e?oi(n,t,e):void 0===t)?1:eo(t),Tr(ao(n),t)},xe.replace=function(){var n=arguments,t=ao(n[0]);return n.length<3?t:t.replace(n[1],n[2])},xe.result=function(n,t,e){var r=-1,u=(t=ou(t,n)).length;for(u||(u=1,n=void 0);++r9007199254740991)return[];var e=4294967295,r=oe(n,4294967295);n-=4294967295;for(var u=Ot(r,t=Qu(t));++e=i)return n;var o=e-Gt(r);if(o<1)return r;var c=a?lu(a,0,o).join(""):n.slice(0,o);if(void 0===u)return c+r;if(a&&(o+=c.length-o),Za(u)){if(n.slice(o).search(u)){var l,f=c;for(u.global||(u=Dn(u.source,ao(rn.exec(u))+"g")),u.lastIndex=0;l=u.exec(f);)var s=l.index;c=c.slice(0,void 0===s?o:s)}}else if(n.indexOf(Jr(u),o)!=o){var v=c.lastIndexOf(u);v>-1&&(c=c.slice(0,v))}return c+r},xe.unescape=function(n){return(n=ao(n))&&z.test(n)?n.replace(R,Kt):n},xe.uniqueId=function(n){var t=++kn;return ao(n)+t},xe.upperCase=zo,xe.upperFirst=Wo,xe.each=aa,xe.eachRight=oa,xe.first=Si,Qo(xe,(fc={},cr(xe,(function(n,t){Cn.call(xe.prototype,t)||(fc[t]=n)})),fc),{chain:!1}),xe.VERSION="4.17.15",ct(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(n){xe[n].placeholder=xe})),ct(["drop","take"],(function(n,t){Be.prototype[n]=function(e){e=void 0===e?1:ae(eo(e),0);var r=this.__filtered__&&!t?new Be(this):this.clone();return r.__filtered__?r.__takeCount__=oe(e,r.__takeCount__):r.__views__.push({size:oe(e,4294967295),type:n+(r.__dir__<0?"Right":"")}),r},Be.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}})),ct(["filter","map","takeWhile"],(function(n,t){var e=t+1,r=1==e||3==e;Be.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:Qu(n,3),type:e}),t.__filtered__=t.__filtered__||r,t}})),ct(["head","last"],(function(n,t){var e="take"+(t?"Right":"");Be.prototype[n]=function(){return this[e](1).value()[0]}})),ct(["initial","tail"],(function(n,t){var e="drop"+(t?"":"Right");Be.prototype[n]=function(){return this.__filtered__?new Be(this):this[e](1)}})),Be.prototype.compact=function(){return this.filter(Go)},Be.prototype.find=function(n){return this.filter(n).head()},Be.prototype.findLast=function(n){return this.reverse().find(n)},Be.prototype.invokeMap=zr((function(n,t){return"function"==typeof n?new Be(this):this.map((function(e){return _r(e,n,t)}))})),Be.prototype.reject=function(n){return this.filter(wa(Qu(n)))},Be.prototype.slice=function(n,t){n=eo(n);var e=this;return e.__filtered__&&(n>0||t<0)?new Be(e):(n<0?e=e.takeRight(-n):n&&(e=e.drop(n)),void 0!==t&&(e=(t=eo(t))<0?e.dropRight(-t):e.take(t-n)),e)},Be.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},Be.prototype.toArray=function(){return this.take(4294967295)},cr(Be.prototype,(function(n,t){var e=/^(?:filter|find|map|reject)|While$/.test(t),r=/^(?:head|last)$/.test(t),u=xe[r?"take"+("last"==t?"Right":""):t],i=r||/^find/.test(t);u&&(xe.prototype[t]=function(){var t=this.__wrapped__,a=r?[1]:arguments,o=t instanceof Be,c=a[0],l=o||Ba(t),f=function(n){var t=u.apply(xe,pt([n],a));return r&&s?t[0]:t};l&&e&&"function"==typeof c&&1!=c.length&&(o=l=!1);var s=this.__chain__,v=!!this.__actions__.length,h=i&&!s,d=o&&!v;if(!i&&l){t=d?t:new Be(this);var p=n.apply(t,a);return p.__actions__.push({func:ta,args:[f],thisArg:void 0}),new Ne(p,s)}return h&&d?n.apply(this,a):(p=this.thru(f),h?r?p.value()[0]:p.value():p)})})),ct(["pop","push","shift","sort","splice","unshift"],(function(n){var t=yn[n],e=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",r=/^(?:pop|shift)$/.test(n);xe.prototype[n]=function(){var n=arguments;if(r&&!this.__chain__){var u=this.value();return t.apply(Ba(u)?u:[],n)}return this[e]((function(e){return t.apply(Ba(e)?e:[],n)}))}})),cr(Be.prototype,(function(n,t){var e=xe[t];if(e){var r=e.name+"";Cn.call(me,r)||(me[r]=[]),me[r].push({name:t,func:e})}})),me[xu(void 0,2).name]=[{name:"wrapper",func:void 0}],Be.prototype.clone=function(){var n=new Be(this.__wrapped__);return n.__actions__=Du(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=Du(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Du(this.__views__),n},Be.prototype.reverse=function(){if(this.__filtered__){var n=new Be(this);n.__dir__=-1,n.__filtered__=!0}else(n=this.clone()).__dir__*=-1;return n},Be.prototype.value=function(){var n=this.__wrapped__.value(),t=this.__dir__,e=Ba(n),r=t<0,u=e?n.length:0,i=function(n,t,e){var r=-1,u=e.length;for(;++r=this.__values__.length;return{done:n,value:n?void 0:this.__values__[this.__index__++]}},xe.prototype.plant=function(n){for(var t,e=this;e instanceof Oe;){var r=Ai(e);r.__index__=0,r.__values__=void 0,t?u.__wrapped__=r:t=r;var u=r;e=e.__wrapped__}return u.__wrapped__=n,t},xe.prototype.reverse=function(){var n=this.__wrapped__;if(n instanceof Be){var t=n;return this.__actions__.length&&(t=new Be(this)),(t=t.reverse()).__actions__.push({func:ta,args:[Pi],thisArg:void 0}),new Ne(t,this.__chain__)}return this.thru(Pi)},xe.prototype.toJSON=xe.prototype.valueOf=xe.prototype.value=function(){return eu(this.__wrapped__,this.__actions__)},xe.prototype.first=xe.prototype.head,Xn&&(xe.prototype[Xn]=function(){return this}),xe}();Kn._=Ht,void 0===(u=function(){return Ht}.call(t,e,t,r))||(r.exports=u)}).call(this)}).call(this,e(76),e(453)(n))},451:function(n,t,e){"use strict";var r=e(0),u=Object(r.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=u},452:function(n,t,e){"use strict";e.d(t,"a",(function(){return i}));e(77),e(470),e(436),e(78);var r=e(472),u=e.n(r);function i(n,t){var e=new u.a;return n.map((function(n){var r=n;return"string"==typeof n&&(r={label:n,permalink:"/blog/tags/"+e.slug(n)}),function(n,t){var e=n.label.split(": ",2),r=e[0],u=e[1],i="primary";switch(t){case"blog":case"guides":i=function(n){switch(n){case"domain":return"blue";case"type":return"pink";default:return"primary"}}(r)}return{category:r,count:n.count,label:n.label,permalink:n.permalink,style:i,value:u}}(r,t)}))}},453:function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},462:function(n,t,e){var r=e(30),u=e(54),i=e(27),a=e(26),o=e(463);n.exports=function(n,t){var e=1==n,c=2==n,l=3==n,f=4==n,s=6==n,v=5==n||s,h=t||o;return function(t,o,d){for(var p,g,D=i(t),_=u(D),m=r(o,d,3),y=a(_.length),b=0,E=e?h(t,y):c?h(t,0):void 0;y>b;b++)if((v||b in _)&&(g=m(p=_[b],b,D),n))if(e)E[b]=g;else if(g)switch(n){case 3:return!0;case 5:return p;case 6:return b;case 2:E.push(p)}else if(f)return!1;return s?-1:l||f?f:E}}},463:function(n,t,e){var r=e(464);n.exports=function(n,t){return new(r(n))(t)}},464:function(n,t,e){var r=e(13),u=e(465),i=e(2)("species");n.exports=function(n){var t;return u(n)&&("function"!=typeof(t=n.constructor)||t!==Array&&!u(t.prototype)||(t=void 0),r(t)&&null===(t=t[i])&&(t=void 0)),void 0===t?Array:t}},465:function(n,t,e){var r=e(23);n.exports=Array.isArray||function(n){return"Array"==r(n)}},471:function(n,t,e){"use strict";var r=e(0),u=e.n(r),i=e(427),a=e(420),o=e.n(a);t.a=function(n){var t=n.count,e=n.label,r=n.permalink,a=n.style,c=n.value,l=n.valueOnly;return u.a.createElement(i.a,{to:r+"/",className:o()("badge","badge--rounded","badge--"+a)},l?c:e,t&&u.a.createElement(u.a.Fragment,null," (",t,")"))}},472:function(n,t,e){var r=e(473);n.exports=o;var u=Object.hasOwnProperty,i=/\s/g,a=/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~\u2019]/g;function o(){if(!(this instanceof o))return new o;this.reset()}function c(n,t){return"string"!=typeof n?"":(t||(n=n.toLowerCase()),n.trim().replace(a,"").replace(r(),"").replace(i,"-"))}o.prototype.slug=function(n,t){for(var e=c(n,!0===t),r=e;u.call(this.occurrences,e);)this.occurrences[r]++,e=r+"-"+this.occurrences[r];return this.occurrences[e]=0,e},o.prototype.reset=function(){this.occurrences=Object.create(null)},o.slug=c},473:function(n,t){n.exports=function(){return/[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD79\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED0\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3]|\uD83E[\uDD10-\uDD18\uDD80-\uDD84\uDDC0]|\uD83C\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uD83C\uDDFE\uD83C[\uDDEA\uDDF9]|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDFC\uD83C[\uDDEB\uDDF8]|\uD83C\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uD83C\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF8\uDDFE\uDDFF]|\uD83C\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uD83C\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uD83C\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uD83C\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uD83C\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uD83C\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uD83C\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uD83C\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uD83C\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uD83C\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uD83C\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uD83C\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uD83C\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uD83C\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uD83C\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uD83C\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|[#\*0-9]\u20E3/g}},477:function(n,t,e){"use strict";var r=e(1),u=e(0),i=e.n(u),a=(e(427),e(471)),o=e(420),c=e.n(o),l=e(452),f=e(141),s=e.n(f);t.a=function(n){var t,e=n.block,u=n.colorProfile,o=n.tags,f=n.valuesOnly,v=Object(l.a)(o,u);return i.a.createElement("div",{className:c()(s.a.tags,(t={},t[s.a.tagsBlock]=e,t))},v.map((function(n,t){return i.a.createElement(a.a,Object(r.a)({key:t,valueOnly:f},n))})))}},513:function(n,t,e){"use strict";e(29),e(22),e(21),e(52);var r=e(0),u=e.n(r),i=(e(425),e(436),e(427)),a=e(437),o=e.n(a),c=e(477),l=e(452),f=e(433),s=e(438);e(142);var v=function(n){var t=n.frontMatter,e=n.metadata,r=(n.isGuidePage,Object(s.a)().isDarkTheme),a=e.categories,v=(e.description,e.permalink),h=(e.readingTime,e.seriesPosition),d=e.tags,p=(t.author_github,t.cover_label),g=(t.last_modified_on,t.title),D=Object(l.a)(d,"guides"),_=D.find((function(n){return"domain"==n.category})),m=_?_.value:"default",y=D.find((function(n){return"language"==n.category})),b=y?y.value:null,E=D.find((function(n){return"framework"==n.category})),w=E?E.value:null,F=D.find((function(n){return"technology"==n.category})),C=F?F.value:null,k=D.find((function(n){return"cloud_provider"==n.category})),A=k?k.value:null,x=D.find((function(n){return"provider"==n.category})),j=x?x.value:null,O=D.find((function(n){return"platform"==n.category})),N=O?O.value:null,B=D.find((function(n){return"source"==n.category})),I=B?B.value:null,S=D.find((function(n){return"sink"==n.category})),L=S?S.value:null,R=Object(f.a)().siteConfig.customFields.metadata,T=R.installation,z=R.sources,W=R.sinks,M=R.languages,U=R.frameworks,P=R.technologies,$=R.cloud_providers,q=R.providers,V=T.platforms,G=N&&V[N],Z=I&&z[I],K=L&&W[L],H=b&&M.find((function(n){return n.name===b})),Q=w&&U.find((function(n){return n.name===w})),J=C&&P.find((function(n){return n.name===C})),Y=A&&$.find((function(n){return n.name===A})),X=j&&q.find((function(n){return n.name===j})),nn=null!==(G||Z),tn=null!=K,en=null;Q?en=r?Q.dark_logo_path:Q.logo_path:J?en=r?J.dark_logo_path:J.logo_path:Y?en=r?Y.dark_logo_path:Y.logo_path:X?en=r?X.dark_logo_path:X.logo_path:H?en=r?H.dark_logo_path:H.logo_path:G?en=G.logo_path:Z&&(en=Z.logo_path);var rn=null;return K&&(rn=K.logo_path),u.a.createElement(i.a,{to:v+"/",className:"guide-item"},u.a.createElement("article",null,u.a.createElement("div",{className:"domain-bg domain-bg--"+m+" domain-bg--hover"},u.a.createElement("header",null,u.a.createElement("div",{className:"category"},a[0].name),u.a.createElement("h2",{title:g},h&&h+". ",p||g)),u.a.createElement("footer",null,en&&u.a.createElement(o.a,{src:en,className:"logo"}),!en&&nn&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),rn&&u.a.createElement(o.a,{src:rn,className:"logo"}),!rn&&tn&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),!en&&!rn&&!nn&&!tn&&u.a.createElement(c.a,{colorProfile:"guides",tags:d}),u.a.createElement("div",{className:"action"},"read now")))))},h=e(447),d=e(448),p=e.n(d),g=e(420),D=e.n(g);e(143);function _(n){var t=n.groupLevel,e=n.items,r=n.large,i=n.staggered,a=p()(e).map((function(n){return n.content.metadata.categories[t-1]})).uniqBy("permalink").sortBy("title").keyBy("permalink").value(),o=p.a.groupBy(e,(function(n){return n.content.metadata.categories[t-1].permalink})),c=Object(h.a)("h"+(t+1));return Object.keys(a).map((function(n,t){var e=o[n],l=a[n];return u.a.createElement("section",{key:t},u.a.createElement(c,{id:n},l.title),l.description&&u.a.createElement("div",{className:"sub-title"},l.description),u.a.createElement(m,{items:e,large:r,staggered:i}))}))}function m(n){var t=n.groupLevel,e=n.items,r=n.large,i=n.staggered;if(t)return u.a.createElement(_,{groupLevel:t,items:e});var a,o=(a=e,p.a.sortBy(a,["content.metadata.seriesPosition",function(n){return n.content.metadata.coverLabel.toLowerCase()}]));return u.a.createElement("div",{className:"guides"},u.a.createElement("div",{className:D()("guide-items",{"guide-items--l":r,"guide-items--staggered":i})},o.map((function(n){var t=n.content;return u.a.createElement(v,{key:t.metadata.permalink,frontMatter:t.frontMatter,metadata:t.metadata,truncated:t.metadata.truncated},u.a.createElement(t,null))}))))}t.a=m}}]); \ No newline at end of file +/*! For license information please see 004ec9e5.4f0152e2.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{153:function(n,t,e){"use strict";e.r(t);e(428);var r=e(0),u=e.n(r),i=e(445),a=e(516),o=e(430);t.default=function(n){var t=n.metadata,e=n.items,r=t.allTagsPath,c=t.name,l=t.count;return u.a.createElement(i.a,{title:'Guides tagged "'+c+'"',description:'Guide | Tagged "'+c+'"'},u.a.createElement("header",{className:"hero hero--clean"},u.a.createElement("div",{className:"container"},u.a.createElement("h1",null,l," ",function(n,t){return n>1?t+"s":t}(l,"guide"),' tagged with "',c,'"'),u.a.createElement("div",{className:"hero--subtitle"},u.a.createElement(o.a,{href:r},"View All Tags")))),u.a.createElement("main",{className:"container container--s"},u.a.createElement(a.a,{items:e})))}},423:function(n,t,e){var r;!function(){"use strict";var e={}.hasOwnProperty;function u(){for(var n=[],t=0;t1?arguments[1]:void 0)}}),e(74)("find")},445:function(n,t,e){"use strict";e(457);var r=e(0),u=e.n(r),i=e(458),a=e(443),o=e(1),c=(e(446),e(447),e(459),e(430)),l=e(460),f=e(440),s=e.n(f),v=e(461),h=e.n(v),d=e(436),p=e(423),g=e.n(p),D=e(135),_=e.n(D),m=function(){return u.a.createElement("span",{className:g()(_.a.toggle,_.a.moon)})},y=function(){return u.a.createElement("span",{className:g()(_.a.toggle,_.a.sun)})},b=function(n){var t=Object(d.a)().isClient;return u.a.createElement(h.a,Object(o.a)({disabled:!t,icons:{checked:u.a.createElement(m,null),unchecked:u.a.createElement(y,null)}},n))};function E(){var n=Object(d.a)().siteConfig,t=(void 0===n?{}:n).customFields.metadata.latest_post,e=Date.parse(t.date),r=new Date,u=Math.abs(r-e),i=Math.ceil(u/864e5),a=null;return"undefined"!=typeof window&&(a=new Date(parseInt(window.localStorage.getItem("blogViewedAt")||"0"))),i<30&&(!a||a0&&u.a.createElement("div",{className:"row footer__links"},u.a.createElement("div",{className:"col col--5 footer__col"},u.a.createElement("div",{className:"margin-bottom--md"},u.a.createElement(s.a,{className:"navbar__logo",src:h,alt:"Qovery",width:"150",height:"auto"})),u.a.createElement("div",{className:"margin-bottom--md"},u.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),u.a.createElement("div",null,u.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},u.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",u.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},u.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",u.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},u.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",u.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},u.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),c.map((function(n,t){return u.a.createElement("div",{key:t,className:"col footer__col"},null!=n.title?u.a.createElement("h4",{className:"footer__title"},n.title):null,null!=n.items&&Array.isArray(n.items)&&n.items.length>0?u.a.createElement("ul",{className:"footer__items"},n.items.map((function(n,t){return n.html?u.a.createElement("li",{key:t,className:"footer__item",dangerouslySetInnerHTML:{__html:n.html}}):u.a.createElement("li",{key:n.href||n.to,className:"footer__item"},u.a.createElement(R,n))}))):null)}))),(f||a)&&u.a.createElement("div",{className:"text--center"},f&&f.src&&u.a.createElement("div",{className:"margin-bottom--sm"},f.href?u.a.createElement("a",{href:f.href,target:"_blank",rel:"noopener noreferrer",className:L.a.footerLogoLink},u.a.createElement(T,{alt:f.alt,url:v})):u.a.createElement(T,{alt:f.alt,url:v})),u.a.createElement("small",null,a),u.a.createElement("br",null))))},W=e(462),M=e(463),U=e(3);e(138);t.a=function(n){var t=Object(d.a)().siteConfig,e=void 0===t?{}:t,r=e.favicon,o=(e.tagline,e.title),c=e.themeConfig.image,l=e.url,f=n.children,s=n.title,v=n.noFooter,h=n.description,p=n.image,g=n.keywords,D=(n.permalink,n.version),_=s?s+" | "+o:o,m=p||c,y=l+Object(F.a)(m),b=Object(F.a)(r),E=Object(U.h)(),w=E?"https://docs.qovery.com"+(E.pathname.endsWith("/")?E.pathname:E.pathname+"/"):null;return u.a.createElement(M.a,null,u.a.createElement(W.a,null,u.a.createElement(a.a,null,u.a.createElement("html",{lang:"en"}),u.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),_&&u.a.createElement("title",null,_),_&&u.a.createElement("meta",{property:"og:title",content:_}),r&&u.a.createElement("link",{rel:"shortcut icon",href:b}),h&&u.a.createElement("meta",{name:"description",content:h}),h&&u.a.createElement("meta",{property:"og:description",content:h}),D&&u.a.createElement("meta",{name:"docsearch:version",content:D}),g&&g.length&&u.a.createElement("meta",{name:"keywords",content:g.join(",")}),m&&u.a.createElement("meta",{property:"og:image",content:y}),m&&u.a.createElement("meta",{property:"twitter:image",content:y}),m&&u.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+_}),w&&u.a.createElement("meta",{property:"og:url",content:w}),u.a.createElement("meta",{name:"twitter:card",content:"summary"}),w&&u.a.createElement("link",{rel:"canonical",href:w})),u.a.createElement(i.a,null),u.a.createElement(B,null),u.a.createElement("div",{className:"main-wrapper"},f),!v&&u.a.createElement(z,null)))}},450:function(n,t,e){"use strict";var r=e(9),u=e(0),i=e.n(u),a=e(423),o=e.n(a),c=e(436),l=(e(139),e(140)),f=e.n(l);t.a=function(n){return function(t){var e,u=t.id,a=Object(r.a)(t,["id"]),l=Object(c.a)().siteConfig,s=(l=void 0===l?{}:l).themeConfig,v=(s=void 0===s?{}:s).navbar,h=(v=void 0===v?{}:v).hideOnScroll,d=void 0!==h&&h;return u?i.a.createElement(n,a,i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:o()("anchor",(e={},e[f.a.enhancedAnchor]=!d,e)),id:u}),i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+u,title:"Direct link to heading"},"#"),a.children):i.a.createElement(n,a)}}},451:function(n,t,e){(function(n,r){var u;(function(){var i="Expected a function",a="__lodash_placeholder__",o=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],c="[object Arguments]",l="[object Array]",f="[object Boolean]",s="[object Date]",v="[object Error]",h="[object Function]",d="[object GeneratorFunction]",p="[object Map]",g="[object Number]",D="[object Object]",_="[object RegExp]",m="[object Set]",y="[object String]",b="[object Symbol]",E="[object WeakMap]",w="[object ArrayBuffer]",F="[object DataView]",C="[object Float32Array]",k="[object Float64Array]",A="[object Int8Array]",x="[object Int16Array]",j="[object Int32Array]",O="[object Uint8Array]",N="[object Uint16Array]",B="[object Uint32Array]",I=/\b__p \+= '';/g,S=/\b(__p \+=) '' \+/g,L=/(__e\(.*?\)|\b__t\)) \+\n'';/g,R=/&(?:amp|lt|gt|quot|#39);/g,T=/[&<>"']/g,z=RegExp(R.source),W=RegExp(T.source),M=/<%-([\s\S]+?)%>/g,U=/<%([\s\S]+?)%>/g,P=/<%=([\s\S]+?)%>/g,$=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,q=/^\w*$/,V=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,G=/[\\^$.*+?()[\]{}|]/g,Z=RegExp(G.source),K=/^\s+|\s+$/g,H=/^\s+/,Q=/\s+$/,J=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Y=/\{\n\/\* \[wrapped with (.+)\] \*/,X=/,? & /,nn=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,tn=/\\(\\)?/g,en=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,rn=/\w*$/,un=/^[-+]0x[0-9a-f]+$/i,an=/^0b[01]+$/i,on=/^\[object .+?Constructor\]$/,cn=/^0o[0-7]+$/i,ln=/^(?:0|[1-9]\d*)$/,fn=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,sn=/($^)/,vn=/['\n\r\u2028\u2029\\]/g,hn="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",dn="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",pn="[\\ud800-\\udfff]",gn="["+dn+"]",Dn="["+hn+"]",_n="\\d+",mn="[\\u2700-\\u27bf]",yn="[a-z\\xdf-\\xf6\\xf8-\\xff]",bn="[^\\ud800-\\udfff"+dn+_n+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",En="\\ud83c[\\udffb-\\udfff]",wn="[^\\ud800-\\udfff]",Fn="(?:\\ud83c[\\udde6-\\uddff]){2}",Cn="[\\ud800-\\udbff][\\udc00-\\udfff]",kn="[A-Z\\xc0-\\xd6\\xd8-\\xde]",An="(?:"+yn+"|"+bn+")",xn="(?:"+kn+"|"+bn+")",jn="(?:"+Dn+"|"+En+")"+"?",On="[\\ufe0e\\ufe0f]?"+jn+("(?:\\u200d(?:"+[wn,Fn,Cn].join("|")+")[\\ufe0e\\ufe0f]?"+jn+")*"),Nn="(?:"+[mn,Fn,Cn].join("|")+")"+On,Bn="(?:"+[wn+Dn+"?",Dn,Fn,Cn,pn].join("|")+")",In=RegExp("['\u2019]","g"),Sn=RegExp(Dn,"g"),Ln=RegExp(En+"(?="+En+")|"+Bn+On,"g"),Rn=RegExp([kn+"?"+yn+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?="+[gn,kn,"$"].join("|")+")",xn+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?="+[gn,kn+An,"$"].join("|")+")",kn+"?"+An+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?",kn+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",_n,Nn].join("|"),"g"),Tn=RegExp("[\\u200d\\ud800-\\udfff"+hn+"\\ufe0e\\ufe0f]"),zn=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Wn=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Mn=-1,Un={};Un[C]=Un[k]=Un[A]=Un[x]=Un[j]=Un[O]=Un["[object Uint8ClampedArray]"]=Un[N]=Un[B]=!0,Un[c]=Un[l]=Un[w]=Un[f]=Un[F]=Un[s]=Un[v]=Un[h]=Un[p]=Un[g]=Un[D]=Un[_]=Un[m]=Un[y]=Un[E]=!1;var Pn={};Pn[c]=Pn[l]=Pn[w]=Pn[F]=Pn[f]=Pn[s]=Pn[C]=Pn[k]=Pn[A]=Pn[x]=Pn[j]=Pn[p]=Pn[g]=Pn[D]=Pn[_]=Pn[m]=Pn[y]=Pn[b]=Pn[O]=Pn["[object Uint8ClampedArray]"]=Pn[N]=Pn[B]=!0,Pn[v]=Pn[h]=Pn[E]=!1;var $n={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},qn=parseFloat,Vn=parseInt,Gn="object"==typeof n&&n&&n.Object===Object&&n,Zn="object"==typeof self&&self&&self.Object===Object&&self,Kn=Gn||Zn||Function("return this")(),Hn=t&&!t.nodeType&&t,Qn=Hn&&"object"==typeof r&&r&&!r.nodeType&&r,Jn=Qn&&Qn.exports===Hn,Yn=Jn&&Gn.process,Xn=function(){try{var n=Qn&&Qn.require&&Qn.require("util").types;return n||Yn&&Yn.binding&&Yn.binding("util")}catch(t){}}(),nt=Xn&&Xn.isArrayBuffer,tt=Xn&&Xn.isDate,et=Xn&&Xn.isMap,rt=Xn&&Xn.isRegExp,ut=Xn&&Xn.isSet,it=Xn&&Xn.isTypedArray;function at(n,t,e){switch(e.length){case 0:return n.call(t);case 1:return n.call(t,e[0]);case 2:return n.call(t,e[0],e[1]);case 3:return n.call(t,e[0],e[1],e[2])}return n.apply(t,e)}function ot(n,t,e,r){for(var u=-1,i=null==n?0:n.length;++u-1}function ht(n,t,e){for(var r=-1,u=null==n?0:n.length;++r-1;);return e}function Lt(n,t){for(var e=n.length;e--&&Et(t,n[e],0)>-1;);return e}function Rt(n,t){for(var e=n.length,r=0;e--;)n[e]===t&&++r;return r}var Tt=At({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),zt=At({"&":"&","<":"<",">":">",'"':""","'":"'"});function Wt(n){return"\\"+$n[n]}function Mt(n){return Tn.test(n)}function Ut(n){var t=-1,e=Array(n.size);return n.forEach((function(n,r){e[++t]=[r,n]})),e}function Pt(n,t){return function(e){return n(t(e))}}function $t(n,t){for(var e=-1,r=n.length,u=0,i=[];++e",""":'"',"'":"'"});var Ht=function n(t){var e,r=(t=null==t?Kn:Ht.defaults(Kn.Object(),t,Ht.pick(Kn,Wn))).Array,u=t.Date,hn=t.Error,dn=t.Function,pn=t.Math,gn=t.Object,Dn=t.RegExp,_n=t.String,mn=t.TypeError,yn=r.prototype,bn=dn.prototype,En=gn.prototype,wn=t["__core-js_shared__"],Fn=bn.toString,Cn=En.hasOwnProperty,kn=0,An=(e=/[^.]+$/.exec(wn&&wn.keys&&wn.keys.IE_PROTO||""))?"Symbol(src)_1."+e:"",xn=En.toString,jn=Fn.call(gn),On=Kn._,Nn=Dn("^"+Fn.call(Cn).replace(G,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Bn=Jn?t.Buffer:void 0,Ln=t.Symbol,Tn=t.Uint8Array,$n=Bn?Bn.allocUnsafe:void 0,Gn=Pt(gn.getPrototypeOf,gn),Zn=gn.create,Hn=En.propertyIsEnumerable,Qn=yn.splice,Yn=Ln?Ln.isConcatSpreadable:void 0,Xn=Ln?Ln.iterator:void 0,mt=Ln?Ln.toStringTag:void 0,At=function(){try{var n=Xu(gn,"defineProperty");return n({},"",{}),n}catch(t){}}(),Qt=t.clearTimeout!==Kn.clearTimeout&&t.clearTimeout,Jt=u&&u.now!==Kn.Date.now&&u.now,Yt=t.setTimeout!==Kn.setTimeout&&t.setTimeout,Xt=pn.ceil,ne=pn.floor,te=gn.getOwnPropertySymbols,ee=Bn?Bn.isBuffer:void 0,re=t.isFinite,ue=yn.join,ie=Pt(gn.keys,gn),ae=pn.max,oe=pn.min,ce=u.now,le=t.parseInt,fe=pn.random,se=yn.reverse,ve=Xu(t,"DataView"),he=Xu(t,"Map"),de=Xu(t,"Promise"),pe=Xu(t,"Set"),ge=Xu(t,"WeakMap"),De=Xu(gn,"create"),_e=ge&&new ge,me={},ye=ki(ve),be=ki(he),Ee=ki(de),we=ki(pe),Fe=ki(ge),Ce=Ln?Ln.prototype:void 0,ke=Ce?Ce.valueOf:void 0,Ae=Ce?Ce.toString:void 0;function xe(n){if($a(n)&&!Ba(n)&&!(n instanceof Be)){if(n instanceof Ne)return n;if(Cn.call(n,"__wrapped__"))return Ai(n)}return new Ne(n)}var je=function(){function n(){}return function(t){if(!Pa(t))return{};if(Zn)return Zn(t);n.prototype=t;var e=new n;return n.prototype=void 0,e}}();function Oe(){}function Ne(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=void 0}function Be(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Ie(n){var t=-1,e=null==n?0:n.length;for(this.clear();++t=t?n:t)),n}function Qe(n,t,e,r,u,i){var a,o=1&t,l=2&t,v=4&t;if(e&&(a=u?e(n,r,u,i):e(n)),void 0!==a)return a;if(!Pa(n))return n;var E=Ba(n);if(E){if(a=function(n){var t=n.length,e=new n.constructor(t);t&&"string"==typeof n[0]&&Cn.call(n,"index")&&(e.index=n.index,e.input=n.input);return e}(n),!o)return Du(n,a)}else{var I=ei(n),S=I==h||I==d;if(Ra(n))return su(n,o);if(I==D||I==c||S&&!u){if(a=l||S?{}:ui(n),!o)return l?function(n,t){return _u(n,ti(n),t)}(n,function(n,t){return n&&_u(t,bo(t),n)}(a,n)):function(n,t){return _u(n,ni(n),t)}(n,Ge(a,n))}else{if(!Pn[I])return u?n:{};a=function(n,t,e){var r=n.constructor;switch(t){case w:return vu(n);case f:case s:return new r(+n);case F:return function(n,t){var e=t?vu(n.buffer):n.buffer;return new n.constructor(e,n.byteOffset,n.byteLength)}(n,e);case C:case k:case A:case x:case j:case O:case"[object Uint8ClampedArray]":case N:case B:return hu(n,e);case p:return new r;case g:case y:return new r(n);case _:return function(n){var t=new n.constructor(n.source,rn.exec(n));return t.lastIndex=n.lastIndex,t}(n);case m:return new r;case b:return u=n,ke?gn(ke.call(u)):{}}var u}(n,I,o)}}i||(i=new Te);var L=i.get(n);if(L)return L;i.set(n,a),Ka(n)?n.forEach((function(r){a.add(Qe(r,t,e,r,n,i))})):qa(n)&&n.forEach((function(r,u){a.set(u,Qe(r,t,e,u,n,i))}));var R=E?void 0:(v?l?Gu:Vu:l?bo:yo)(n);return ct(R||n,(function(r,u){R&&(r=n[u=r]),$e(a,u,Qe(r,t,e,u,n,i))})),a}function Je(n,t,e){var r=e.length;if(null==n)return!r;for(n=gn(n);r--;){var u=e[r],i=t[u],a=n[u];if(void 0===a&&!(u in n)||!i(a))return!1}return!0}function Ye(n,t,e){if("function"!=typeof n)throw new mn(i);return mi((function(){n.apply(void 0,e)}),t)}function Xe(n,t,e,r){var u=-1,i=vt,a=!0,o=n.length,c=[],l=t.length;if(!o)return c;e&&(t=dt(t,Nt(e))),r?(i=ht,a=!1):t.length>=200&&(i=It,a=!1,t=new Re(t));n:for(;++u-1},Se.prototype.set=function(n,t){var e=this.__data__,r=qe(e,n);return r<0?(++this.size,e.push([n,t])):e[r][1]=t,this},Le.prototype.clear=function(){this.size=0,this.__data__={hash:new Ie,map:new(he||Se),string:new Ie}},Le.prototype.delete=function(n){var t=Ju(this,n).delete(n);return this.size-=t?1:0,t},Le.prototype.get=function(n){return Ju(this,n).get(n)},Le.prototype.has=function(n){return Ju(this,n).has(n)},Le.prototype.set=function(n,t){var e=Ju(this,n),r=e.size;return e.set(n,t),this.size+=e.size==r?0:1,this},Re.prototype.add=Re.prototype.push=function(n){return this.__data__.set(n,"__lodash_hash_undefined__"),this},Re.prototype.has=function(n){return this.__data__.has(n)},Te.prototype.clear=function(){this.__data__=new Se,this.size=0},Te.prototype.delete=function(n){var t=this.__data__,e=t.delete(n);return this.size=t.size,e},Te.prototype.get=function(n){return this.__data__.get(n)},Te.prototype.has=function(n){return this.__data__.has(n)},Te.prototype.set=function(n,t){var e=this.__data__;if(e instanceof Se){var r=e.__data__;if(!he||r.length<199)return r.push([n,t]),this.size=++e.size,this;e=this.__data__=new Le(r)}return e.set(n,t),this.size=e.size,this};var nr=bu(cr),tr=bu(lr,!0);function er(n,t){var e=!0;return nr(n,(function(n,r,u){return e=!!t(n,r,u)})),e}function rr(n,t,e){for(var r=-1,u=n.length;++r0&&e(o)?t>1?ir(o,t-1,e,r,u):pt(u,o):r||(u[u.length]=o)}return u}var ar=Eu(),or=Eu(!0);function cr(n,t){return n&&ar(n,t,yo)}function lr(n,t){return n&&or(n,t,yo)}function fr(n,t){return st(t,(function(t){return Wa(n[t])}))}function sr(n,t){for(var e=0,r=(t=ou(t,n)).length;null!=n&&et}function pr(n,t){return null!=n&&Cn.call(n,t)}function gr(n,t){return null!=n&&t in gn(n)}function Dr(n,t,e){for(var u=e?ht:vt,i=n[0].length,a=n.length,o=a,c=r(a),l=1/0,f=[];o--;){var s=n[o];o&&t&&(s=dt(s,Nt(t))),l=oe(s.length,l),c[o]=!e&&(t||i>=120&&s.length>=120)?new Re(o&&s):void 0}s=n[0];var v=-1,h=c[0];n:for(;++v=o)return c;var l=e[r];return c*("desc"==l?-1:1)}}return n.index-t.index}(n,t,e)}))}function Ir(n,t,e){for(var r=-1,u=t.length,i={};++r-1;)o!==n&&Qn.call(o,c,1),Qn.call(n,c,1);return n}function Lr(n,t){for(var e=n?t.length:0,r=e-1;e--;){var u=t[e];if(e==r||u!==i){var i=u;ai(u)?Qn.call(n,u,1):Xr(n,u)}}return n}function Rr(n,t){return n+ne(fe()*(t-n+1))}function Tr(n,t){var e="";if(!n||t<1||t>9007199254740991)return e;do{t%2&&(e+=n),(t=ne(t/2))&&(n+=n)}while(t);return e}function zr(n,t){return yi(di(n,t,Go),n+"")}function Wr(n){return We(jo(n))}function Mr(n,t){var e=jo(n);return wi(e,He(t,0,e.length))}function Ur(n,t,e,r){if(!Pa(n))return n;for(var u=-1,i=(t=ou(t,n)).length,a=i-1,o=n;null!=o&&++ui?0:i+t),(e=e>i?i:e)<0&&(e+=i),i=t>e?0:e-t>>>0,t>>>=0;for(var a=r(i);++u>>1,a=n[i];null!==a&&!Qa(a)&&(e?a<=t:a=200){var l=t?null:Tu(n);if(l)return qt(l);a=!1,u=It,c=new Re}else c=t?[]:o;n:for(;++r=r?n:Vr(n,t,e)}var fu=Qt||function(n){return Kn.clearTimeout(n)};function su(n,t){if(t)return n.slice();var e=n.length,r=$n?$n(e):new n.constructor(e);return n.copy(r),r}function vu(n){var t=new n.constructor(n.byteLength);return new Tn(t).set(new Tn(n)),t}function hu(n,t){var e=t?vu(n.buffer):n.buffer;return new n.constructor(e,n.byteOffset,n.length)}function du(n,t){if(n!==t){var e=void 0!==n,r=null===n,u=n==n,i=Qa(n),a=void 0!==t,o=null===t,c=t==t,l=Qa(t);if(!o&&!l&&!i&&n>t||i&&a&&c&&!o&&!l||r&&a&&c||!e&&c||!u)return 1;if(!r&&!i&&!l&&n1?e[u-1]:void 0,a=u>2?e[2]:void 0;for(i=n.length>3&&"function"==typeof i?(u--,i):void 0,a&&oi(e[0],e[1],a)&&(i=u<3?void 0:i,u=1),t=gn(t);++r-1?u[i?t[a]:a]:void 0}}function Au(n){return qu((function(t){var e=t.length,r=e,u=Ne.prototype.thru;for(n&&t.reverse();r--;){var a=t[r];if("function"!=typeof a)throw new mn(i);if(u&&!o&&"wrapper"==Ku(a))var o=new Ne([],!0)}for(r=o?r:e;++r1&&m.reverse(),s&&l<_&&(m.length=l),this&&this!==Kn&&this instanceof D&&(C=g||Cu(C)),C.apply(F,m)}}function ju(n,t){return function(e,r){return function(n,t,e,r){return cr(n,(function(n,u,i){t(r,e(n),u,i)})),r}(e,n,t(r),{})}}function Ou(n,t){return function(e,r){var u;if(void 0===e&&void 0===r)return t;if(void 0!==e&&(u=e),void 0!==r){if(void 0===u)return r;"string"==typeof e||"string"==typeof r?(e=Jr(e),r=Jr(r)):(e=Qr(e),r=Qr(r)),u=n(e,r)}return u}}function Nu(n){return qu((function(t){return t=dt(t,Nt(Qu())),zr((function(e){var r=this;return n(t,(function(n){return at(n,r,e)}))}))}))}function Bu(n,t){var e=(t=void 0===t?" ":Jr(t)).length;if(e<2)return e?Tr(t,n):t;var r=Tr(t,Xt(n/Gt(t)));return Mt(t)?lu(Zt(r),0,n).join(""):r.slice(0,n)}function Iu(n){return function(t,e,u){return u&&"number"!=typeof u&&oi(t,e,u)&&(e=u=void 0),t=to(t),void 0===e?(e=t,t=0):e=to(e),function(n,t,e,u){for(var i=-1,a=ae(Xt((t-n)/(e||1)),0),o=r(a);a--;)o[u?a:++i]=n,n+=e;return o}(t,e,u=void 0===u?to))return!1;var l=i.get(n);if(l&&i.get(t))return l==t;var f=-1,s=!0,v=2&e?new Re:void 0;for(i.set(n,t),i.set(t,n);++f-1&&n%1==0&&n1?"& ":"")+t[r],t=t.join(e>2?", ":" "),n.replace(J,"{\n/* [wrapped with "+t+"] */\n")}(r,function(n,t){return ct(o,(function(e){var r="_."+e[0];t&e[1]&&!vt(n,r)&&n.push(r)})),n.sort()}(function(n){var t=n.match(Y);return t?t[1].split(X):[]}(r),e)))}function Ei(n){var t=0,e=0;return function(){var r=ce(),u=16-(r-e);if(e=r,u>0){if(++t>=800)return arguments[0]}else t=0;return n.apply(void 0,arguments)}}function wi(n,t){var e=-1,r=n.length,u=r-1;for(t=void 0===t?r:t;++e1?n[t-1]:void 0;return e="function"==typeof e?(n.pop(),e):void 0,Zi(n,e)}));function na(n){var t=xe(n);return t.__chain__=!0,t}function ta(n,t){return t(n)}var ea=qu((function(n){var t=n.length,e=t?n[0]:0,r=this.__wrapped__,u=function(t){return Ke(t,n)};return!(t>1||this.__actions__.length)&&r instanceof Be&&ai(e)?((r=r.slice(e,+e+(t?1:0))).__actions__.push({func:ta,args:[u],thisArg:void 0}),new Ne(r,this.__chain__).thru((function(n){return t&&!n.length&&n.push(void 0),n}))):this.thru(u)}));var ra=mu((function(n,t,e){Cn.call(n,e)?++n[e]:Ze(n,e,1)}));var ua=ku(Ni),ia=ku(Bi);function aa(n,t){return(Ba(n)?ct:nr)(n,Qu(t,3))}function oa(n,t){return(Ba(n)?lt:tr)(n,Qu(t,3))}var ca=mu((function(n,t,e){Cn.call(n,e)?n[e].push(t):Ze(n,e,[t])}));var la=zr((function(n,t,e){var u=-1,i="function"==typeof t,a=Sa(n)?r(n.length):[];return nr(n,(function(n){a[++u]=i?at(t,n,e):_r(n,t,e)})),a})),fa=mu((function(n,t,e){Ze(n,e,t)}));function sa(n,t){return(Ba(n)?dt:Ar)(n,Qu(t,3))}var va=mu((function(n,t,e){n[e?0:1].push(t)}),(function(){return[[],[]]}));var ha=zr((function(n,t){if(null==n)return[];var e=t.length;return e>1&&oi(n,t[0],t[1])?t=[]:e>2&&oi(t[0],t[1],t[2])&&(t=[t[0]]),Br(n,ir(t,1),[])})),da=Jt||function(){return Kn.Date.now()};function pa(n,t,e){return t=e?void 0:t,Wu(n,128,void 0,void 0,void 0,void 0,t=n&&null==t?n.length:t)}function ga(n,t){var e;if("function"!=typeof t)throw new mn(i);return n=eo(n),function(){return--n>0&&(e=t.apply(this,arguments)),n<=1&&(t=void 0),e}}var Da=zr((function(n,t,e){var r=1;if(e.length){var u=$t(e,Hu(Da));r|=32}return Wu(n,r,t,e,u)})),_a=zr((function(n,t,e){var r=3;if(e.length){var u=$t(e,Hu(_a));r|=32}return Wu(t,r,n,e,u)}));function ma(n,t,e){var r,u,a,o,c,l,f=0,s=!1,v=!1,h=!0;if("function"!=typeof n)throw new mn(i);function d(t){var e=r,i=u;return r=u=void 0,f=t,o=n.apply(i,e)}function p(n){return f=n,c=mi(D,t),s?d(n):o}function g(n){var e=n-l;return void 0===l||e>=t||e<0||v&&n-f>=a}function D(){var n=da();if(g(n))return _(n);c=mi(D,function(n){var e=t-(n-l);return v?oe(e,a-(n-f)):e}(n))}function _(n){return c=void 0,h&&r?d(n):(r=u=void 0,o)}function m(){var n=da(),e=g(n);if(r=arguments,u=this,l=n,e){if(void 0===c)return p(l);if(v)return fu(c),c=mi(D,t),d(l)}return void 0===c&&(c=mi(D,t)),o}return t=uo(t)||0,Pa(e)&&(s=!!e.leading,a=(v="maxWait"in e)?ae(uo(e.maxWait)||0,t):a,h="trailing"in e?!!e.trailing:h),m.cancel=function(){void 0!==c&&fu(c),f=0,r=l=u=c=void 0},m.flush=function(){return void 0===c?o:_(da())},m}var ya=zr((function(n,t){return Ye(n,1,t)})),ba=zr((function(n,t,e){return Ye(n,uo(t)||0,e)}));function Ea(n,t){if("function"!=typeof n||null!=t&&"function"!=typeof t)throw new mn(i);var e=function(){var r=arguments,u=t?t.apply(this,r):r[0],i=e.cache;if(i.has(u))return i.get(u);var a=n.apply(this,r);return e.cache=i.set(u,a)||i,a};return e.cache=new(Ea.Cache||Le),e}function wa(n){if("function"!=typeof n)throw new mn(i);return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}Ea.Cache=Le;var Fa=cu((function(n,t){var e=(t=1==t.length&&Ba(t[0])?dt(t[0],Nt(Qu())):dt(ir(t,1),Nt(Qu()))).length;return zr((function(r){for(var u=-1,i=oe(r.length,e);++u=t})),Na=mr(function(){return arguments}())?mr:function(n){return $a(n)&&Cn.call(n,"callee")&&!Hn.call(n,"callee")},Ba=r.isArray,Ia=nt?Nt(nt):function(n){return $a(n)&&hr(n)==w};function Sa(n){return null!=n&&Ua(n.length)&&!Wa(n)}function La(n){return $a(n)&&Sa(n)}var Ra=ee||ic,Ta=tt?Nt(tt):function(n){return $a(n)&&hr(n)==s};function za(n){if(!$a(n))return!1;var t=hr(n);return t==v||"[object DOMException]"==t||"string"==typeof n.message&&"string"==typeof n.name&&!Ga(n)}function Wa(n){if(!Pa(n))return!1;var t=hr(n);return t==h||t==d||"[object AsyncFunction]"==t||"[object Proxy]"==t}function Ma(n){return"number"==typeof n&&n==eo(n)}function Ua(n){return"number"==typeof n&&n>-1&&n%1==0&&n<=9007199254740991}function Pa(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function $a(n){return null!=n&&"object"==typeof n}var qa=et?Nt(et):function(n){return $a(n)&&ei(n)==p};function Va(n){return"number"==typeof n||$a(n)&&hr(n)==g}function Ga(n){if(!$a(n)||hr(n)!=D)return!1;var t=Gn(n);if(null===t)return!0;var e=Cn.call(t,"constructor")&&t.constructor;return"function"==typeof e&&e instanceof e&&Fn.call(e)==jn}var Za=rt?Nt(rt):function(n){return $a(n)&&hr(n)==_};var Ka=ut?Nt(ut):function(n){return $a(n)&&ei(n)==m};function Ha(n){return"string"==typeof n||!Ba(n)&&$a(n)&&hr(n)==y}function Qa(n){return"symbol"==typeof n||$a(n)&&hr(n)==b}var Ja=it?Nt(it):function(n){return $a(n)&&Ua(n.length)&&!!Un[hr(n)]};var Ya=Su(kr),Xa=Su((function(n,t){return n<=t}));function no(n){if(!n)return[];if(Sa(n))return Ha(n)?Zt(n):Du(n);if(Xn&&n[Xn])return function(n){for(var t,e=[];!(t=n.next()).done;)e.push(t.value);return e}(n[Xn]());var t=ei(n);return(t==p?Ut:t==m?qt:jo)(n)}function to(n){return n?(n=uo(n))===1/0||n===-1/0?17976931348623157e292*(n<0?-1:1):n==n?n:0:0===n?n:0}function eo(n){var t=to(n),e=t%1;return t==t?e?t-e:t:0}function ro(n){return n?He(eo(n),0,4294967295):0}function uo(n){if("number"==typeof n)return n;if(Qa(n))return NaN;if(Pa(n)){var t="function"==typeof n.valueOf?n.valueOf():n;n=Pa(t)?t+"":t}if("string"!=typeof n)return 0===n?n:+n;n=n.replace(K,"");var e=an.test(n);return e||cn.test(n)?Vn(n.slice(2),e?2:8):un.test(n)?NaN:+n}function io(n){return _u(n,bo(n))}function ao(n){return null==n?"":Jr(n)}var oo=yu((function(n,t){if(si(t)||Sa(t))_u(t,yo(t),n);else for(var e in t)Cn.call(t,e)&&$e(n,e,t[e])})),co=yu((function(n,t){_u(t,bo(t),n)})),lo=yu((function(n,t,e,r){_u(t,bo(t),n,r)})),fo=yu((function(n,t,e,r){_u(t,yo(t),n,r)})),so=qu(Ke);var vo=zr((function(n,t){n=gn(n);var e=-1,r=t.length,u=r>2?t[2]:void 0;for(u&&oi(t[0],t[1],u)&&(r=1);++e1),t})),_u(n,Gu(n),e),r&&(e=Qe(e,7,Pu));for(var u=t.length;u--;)Xr(e,t[u]);return e}));var Co=qu((function(n,t){return null==n?{}:function(n,t){return Ir(n,t,(function(t,e){return go(n,e)}))}(n,t)}));function ko(n,t){if(null==n)return{};var e=dt(Gu(n),(function(n){return[n]}));return t=Qu(t),Ir(n,e,(function(n,e){return t(n,e[0])}))}var Ao=zu(yo),xo=zu(bo);function jo(n){return null==n?[]:Bt(n,yo(n))}var Oo=Fu((function(n,t,e){return t=t.toLowerCase(),n+(e?No(t):t)}));function No(n){return Wo(ao(n).toLowerCase())}function Bo(n){return(n=ao(n))&&n.replace(fn,Tt).replace(Sn,"")}var Io=Fu((function(n,t,e){return n+(e?"-":"")+t.toLowerCase()})),So=Fu((function(n,t,e){return n+(e?" ":"")+t.toLowerCase()})),Lo=wu("toLowerCase");var Ro=Fu((function(n,t,e){return n+(e?"_":"")+t.toLowerCase()}));var To=Fu((function(n,t,e){return n+(e?" ":"")+Wo(t)}));var zo=Fu((function(n,t,e){return n+(e?" ":"")+t.toUpperCase()})),Wo=wu("toUpperCase");function Mo(n,t,e){return n=ao(n),void 0===(t=e?void 0:t)?function(n){return zn.test(n)}(n)?function(n){return n.match(Rn)||[]}(n):function(n){return n.match(nn)||[]}(n):n.match(t)||[]}var Uo=zr((function(n,t){try{return at(n,void 0,t)}catch(e){return za(e)?e:new hn(e)}})),Po=qu((function(n,t){return ct(t,(function(t){t=Ci(t),Ze(n,t,Da(n[t],n))})),n}));function $o(n){return function(){return n}}var qo=Au(),Vo=Au(!0);function Go(n){return n}function Zo(n){return wr("function"==typeof n?n:Qe(n,1))}var Ko=zr((function(n,t){return function(e){return _r(e,n,t)}})),Ho=zr((function(n,t){return function(e){return _r(n,e,t)}}));function Qo(n,t,e){var r=yo(t),u=fr(t,r);null!=e||Pa(t)&&(u.length||!r.length)||(e=t,t=n,n=this,u=fr(t,yo(t)));var i=!(Pa(e)&&"chain"in e&&!e.chain),a=Wa(n);return ct(u,(function(e){var r=t[e];n[e]=r,a&&(n.prototype[e]=function(){var t=this.__chain__;if(i||t){var e=n(this.__wrapped__),u=e.__actions__=Du(this.__actions__);return u.push({func:r,args:arguments,thisArg:n}),e.__chain__=t,e}return r.apply(n,pt([this.value()],arguments))})})),n}function Jo(){}var Yo=Nu(dt),Xo=Nu(ft),nc=Nu(_t);function tc(n){return ci(n)?kt(Ci(n)):function(n){return function(t){return sr(t,n)}}(n)}var ec=Iu(),rc=Iu(!0);function uc(){return[]}function ic(){return!1}var ac=Ou((function(n,t){return n+t}),0),oc=Ru("ceil"),cc=Ou((function(n,t){return n/t}),1),lc=Ru("floor");var fc,sc=Ou((function(n,t){return n*t}),1),vc=Ru("round"),hc=Ou((function(n,t){return n-t}),0);return xe.after=function(n,t){if("function"!=typeof t)throw new mn(i);return n=eo(n),function(){if(--n<1)return t.apply(this,arguments)}},xe.ary=pa,xe.assign=oo,xe.assignIn=co,xe.assignInWith=lo,xe.assignWith=fo,xe.at=so,xe.before=ga,xe.bind=Da,xe.bindAll=Po,xe.bindKey=_a,xe.castArray=function(){if(!arguments.length)return[];var n=arguments[0];return Ba(n)?n:[n]},xe.chain=na,xe.chunk=function(n,t,e){t=(e?oi(n,t,e):void 0===t)?1:ae(eo(t),0);var u=null==n?0:n.length;if(!u||t<1)return[];for(var i=0,a=0,o=r(Xt(u/t));iu?0:u+e),(r=void 0===r||r>u?u:eo(r))<0&&(r+=u),r=e>r?0:ro(r);e>>0)?(n=ao(n))&&("string"==typeof t||null!=t&&!Za(t))&&!(t=Jr(t))&&Mt(n)?lu(Zt(n),0,e):n.split(t,e):[]},xe.spread=function(n,t){if("function"!=typeof n)throw new mn(i);return t=null==t?0:ae(eo(t),0),zr((function(e){var r=e[t],u=lu(e,0,t);return r&&pt(u,r),at(n,this,u)}))},xe.tail=function(n){var t=null==n?0:n.length;return t?Vr(n,1,t):[]},xe.take=function(n,t,e){return n&&n.length?Vr(n,0,(t=e||void 0===t?1:eo(t))<0?0:t):[]},xe.takeRight=function(n,t,e){var r=null==n?0:n.length;return r?Vr(n,(t=r-(t=e||void 0===t?1:eo(t)))<0?0:t,r):[]},xe.takeRightWhile=function(n,t){return n&&n.length?tu(n,Qu(t,3),!1,!0):[]},xe.takeWhile=function(n,t){return n&&n.length?tu(n,Qu(t,3)):[]},xe.tap=function(n,t){return t(n),n},xe.throttle=function(n,t,e){var r=!0,u=!0;if("function"!=typeof n)throw new mn(i);return Pa(e)&&(r="leading"in e?!!e.leading:r,u="trailing"in e?!!e.trailing:u),ma(n,t,{leading:r,maxWait:t,trailing:u})},xe.thru=ta,xe.toArray=no,xe.toPairs=Ao,xe.toPairsIn=xo,xe.toPath=function(n){return Ba(n)?dt(n,Ci):Qa(n)?[n]:Du(Fi(ao(n)))},xe.toPlainObject=io,xe.transform=function(n,t,e){var r=Ba(n),u=r||Ra(n)||Ja(n);if(t=Qu(t,4),null==e){var i=n&&n.constructor;e=u?r?new i:[]:Pa(n)&&Wa(i)?je(Gn(n)):{}}return(u?ct:cr)(n,(function(n,r,u){return t(e,n,r,u)})),e},xe.unary=function(n){return pa(n,1)},xe.union=$i,xe.unionBy=qi,xe.unionWith=Vi,xe.uniq=function(n){return n&&n.length?Yr(n):[]},xe.uniqBy=function(n,t){return n&&n.length?Yr(n,Qu(t,2)):[]},xe.uniqWith=function(n,t){return t="function"==typeof t?t:void 0,n&&n.length?Yr(n,void 0,t):[]},xe.unset=function(n,t){return null==n||Xr(n,t)},xe.unzip=Gi,xe.unzipWith=Zi,xe.update=function(n,t,e){return null==n?n:nu(n,t,au(e))},xe.updateWith=function(n,t,e,r){return r="function"==typeof r?r:void 0,null==n?n:nu(n,t,au(e),r)},xe.values=jo,xe.valuesIn=function(n){return null==n?[]:Bt(n,bo(n))},xe.without=Ki,xe.words=Mo,xe.wrap=function(n,t){return Ca(au(t),n)},xe.xor=Hi,xe.xorBy=Qi,xe.xorWith=Ji,xe.zip=Yi,xe.zipObject=function(n,t){return uu(n||[],t||[],$e)},xe.zipObjectDeep=function(n,t){return uu(n||[],t||[],Ur)},xe.zipWith=Xi,xe.entries=Ao,xe.entriesIn=xo,xe.extend=co,xe.extendWith=lo,Qo(xe,xe),xe.add=ac,xe.attempt=Uo,xe.camelCase=Oo,xe.capitalize=No,xe.ceil=oc,xe.clamp=function(n,t,e){return void 0===e&&(e=t,t=void 0),void 0!==e&&(e=(e=uo(e))==e?e:0),void 0!==t&&(t=(t=uo(t))==t?t:0),He(uo(n),t,e)},xe.clone=function(n){return Qe(n,4)},xe.cloneDeep=function(n){return Qe(n,5)},xe.cloneDeepWith=function(n,t){return Qe(n,5,t="function"==typeof t?t:void 0)},xe.cloneWith=function(n,t){return Qe(n,4,t="function"==typeof t?t:void 0)},xe.conformsTo=function(n,t){return null==t||Je(n,t,yo(t))},xe.deburr=Bo,xe.defaultTo=function(n,t){return null==n||n!=n?t:n},xe.divide=cc,xe.endsWith=function(n,t,e){n=ao(n),t=Jr(t);var r=n.length,u=e=void 0===e?r:He(eo(e),0,r);return(e-=t.length)>=0&&n.slice(e,u)==t},xe.eq=xa,xe.escape=function(n){return(n=ao(n))&&W.test(n)?n.replace(T,zt):n},xe.escapeRegExp=function(n){return(n=ao(n))&&Z.test(n)?n.replace(G,"\\$&"):n},xe.every=function(n,t,e){var r=Ba(n)?ft:er;return e&&oi(n,t,e)&&(t=void 0),r(n,Qu(t,3))},xe.find=ua,xe.findIndex=Ni,xe.findKey=function(n,t){return yt(n,Qu(t,3),cr)},xe.findLast=ia,xe.findLastIndex=Bi,xe.findLastKey=function(n,t){return yt(n,Qu(t,3),lr)},xe.floor=lc,xe.forEach=aa,xe.forEachRight=oa,xe.forIn=function(n,t){return null==n?n:ar(n,Qu(t,3),bo)},xe.forInRight=function(n,t){return null==n?n:or(n,Qu(t,3),bo)},xe.forOwn=function(n,t){return n&&cr(n,Qu(t,3))},xe.forOwnRight=function(n,t){return n&&lr(n,Qu(t,3))},xe.get=po,xe.gt=ja,xe.gte=Oa,xe.has=function(n,t){return null!=n&&ri(n,t,pr)},xe.hasIn=go,xe.head=Si,xe.identity=Go,xe.includes=function(n,t,e,r){n=Sa(n)?n:jo(n),e=e&&!r?eo(e):0;var u=n.length;return e<0&&(e=ae(u+e,0)),Ha(n)?e<=u&&n.indexOf(t,e)>-1:!!u&&Et(n,t,e)>-1},xe.indexOf=function(n,t,e){var r=null==n?0:n.length;if(!r)return-1;var u=null==e?0:eo(e);return u<0&&(u=ae(r+u,0)),Et(n,t,u)},xe.inRange=function(n,t,e){return t=to(t),void 0===e?(e=t,t=0):e=to(e),function(n,t,e){return n>=oe(t,e)&&n=-9007199254740991&&n<=9007199254740991},xe.isSet=Ka,xe.isString=Ha,xe.isSymbol=Qa,xe.isTypedArray=Ja,xe.isUndefined=function(n){return void 0===n},xe.isWeakMap=function(n){return $a(n)&&ei(n)==E},xe.isWeakSet=function(n){return $a(n)&&"[object WeakSet]"==hr(n)},xe.join=function(n,t){return null==n?"":ue.call(n,t)},xe.kebabCase=Io,xe.last=zi,xe.lastIndexOf=function(n,t,e){var r=null==n?0:n.length;if(!r)return-1;var u=r;return void 0!==e&&(u=(u=eo(e))<0?ae(r+u,0):oe(u,r-1)),t==t?function(n,t,e){for(var r=e+1;r--;)if(n[r]===t)return r;return r}(n,t,u):bt(n,Ft,u,!0)},xe.lowerCase=So,xe.lowerFirst=Lo,xe.lt=Ya,xe.lte=Xa,xe.max=function(n){return n&&n.length?rr(n,Go,dr):void 0},xe.maxBy=function(n,t){return n&&n.length?rr(n,Qu(t,2),dr):void 0},xe.mean=function(n){return Ct(n,Go)},xe.meanBy=function(n,t){return Ct(n,Qu(t,2))},xe.min=function(n){return n&&n.length?rr(n,Go,kr):void 0},xe.minBy=function(n,t){return n&&n.length?rr(n,Qu(t,2),kr):void 0},xe.stubArray=uc,xe.stubFalse=ic,xe.stubObject=function(){return{}},xe.stubString=function(){return""},xe.stubTrue=function(){return!0},xe.multiply=sc,xe.nth=function(n,t){return n&&n.length?Nr(n,eo(t)):void 0},xe.noConflict=function(){return Kn._===this&&(Kn._=On),this},xe.noop=Jo,xe.now=da,xe.pad=function(n,t,e){n=ao(n);var r=(t=eo(t))?Gt(n):0;if(!t||r>=t)return n;var u=(t-r)/2;return Bu(ne(u),e)+n+Bu(Xt(u),e)},xe.padEnd=function(n,t,e){n=ao(n);var r=(t=eo(t))?Gt(n):0;return t&&rt){var r=n;n=t,t=r}if(e||n%1||t%1){var u=fe();return oe(n+u*(t-n+qn("1e-"+((u+"").length-1))),t)}return Rr(n,t)},xe.reduce=function(n,t,e){var r=Ba(n)?gt:xt,u=arguments.length<3;return r(n,Qu(t,4),e,u,nr)},xe.reduceRight=function(n,t,e){var r=Ba(n)?Dt:xt,u=arguments.length<3;return r(n,Qu(t,4),e,u,tr)},xe.repeat=function(n,t,e){return t=(e?oi(n,t,e):void 0===t)?1:eo(t),Tr(ao(n),t)},xe.replace=function(){var n=arguments,t=ao(n[0]);return n.length<3?t:t.replace(n[1],n[2])},xe.result=function(n,t,e){var r=-1,u=(t=ou(t,n)).length;for(u||(u=1,n=void 0);++r9007199254740991)return[];var e=4294967295,r=oe(n,4294967295);n-=4294967295;for(var u=Ot(r,t=Qu(t));++e=i)return n;var o=e-Gt(r);if(o<1)return r;var c=a?lu(a,0,o).join(""):n.slice(0,o);if(void 0===u)return c+r;if(a&&(o+=c.length-o),Za(u)){if(n.slice(o).search(u)){var l,f=c;for(u.global||(u=Dn(u.source,ao(rn.exec(u))+"g")),u.lastIndex=0;l=u.exec(f);)var s=l.index;c=c.slice(0,void 0===s?o:s)}}else if(n.indexOf(Jr(u),o)!=o){var v=c.lastIndexOf(u);v>-1&&(c=c.slice(0,v))}return c+r},xe.unescape=function(n){return(n=ao(n))&&z.test(n)?n.replace(R,Kt):n},xe.uniqueId=function(n){var t=++kn;return ao(n)+t},xe.upperCase=zo,xe.upperFirst=Wo,xe.each=aa,xe.eachRight=oa,xe.first=Si,Qo(xe,(fc={},cr(xe,(function(n,t){Cn.call(xe.prototype,t)||(fc[t]=n)})),fc),{chain:!1}),xe.VERSION="4.17.15",ct(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(n){xe[n].placeholder=xe})),ct(["drop","take"],(function(n,t){Be.prototype[n]=function(e){e=void 0===e?1:ae(eo(e),0);var r=this.__filtered__&&!t?new Be(this):this.clone();return r.__filtered__?r.__takeCount__=oe(e,r.__takeCount__):r.__views__.push({size:oe(e,4294967295),type:n+(r.__dir__<0?"Right":"")}),r},Be.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}})),ct(["filter","map","takeWhile"],(function(n,t){var e=t+1,r=1==e||3==e;Be.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:Qu(n,3),type:e}),t.__filtered__=t.__filtered__||r,t}})),ct(["head","last"],(function(n,t){var e="take"+(t?"Right":"");Be.prototype[n]=function(){return this[e](1).value()[0]}})),ct(["initial","tail"],(function(n,t){var e="drop"+(t?"":"Right");Be.prototype[n]=function(){return this.__filtered__?new Be(this):this[e](1)}})),Be.prototype.compact=function(){return this.filter(Go)},Be.prototype.find=function(n){return this.filter(n).head()},Be.prototype.findLast=function(n){return this.reverse().find(n)},Be.prototype.invokeMap=zr((function(n,t){return"function"==typeof n?new Be(this):this.map((function(e){return _r(e,n,t)}))})),Be.prototype.reject=function(n){return this.filter(wa(Qu(n)))},Be.prototype.slice=function(n,t){n=eo(n);var e=this;return e.__filtered__&&(n>0||t<0)?new Be(e):(n<0?e=e.takeRight(-n):n&&(e=e.drop(n)),void 0!==t&&(e=(t=eo(t))<0?e.dropRight(-t):e.take(t-n)),e)},Be.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},Be.prototype.toArray=function(){return this.take(4294967295)},cr(Be.prototype,(function(n,t){var e=/^(?:filter|find|map|reject)|While$/.test(t),r=/^(?:head|last)$/.test(t),u=xe[r?"take"+("last"==t?"Right":""):t],i=r||/^find/.test(t);u&&(xe.prototype[t]=function(){var t=this.__wrapped__,a=r?[1]:arguments,o=t instanceof Be,c=a[0],l=o||Ba(t),f=function(n){var t=u.apply(xe,pt([n],a));return r&&s?t[0]:t};l&&e&&"function"==typeof c&&1!=c.length&&(o=l=!1);var s=this.__chain__,v=!!this.__actions__.length,h=i&&!s,d=o&&!v;if(!i&&l){t=d?t:new Be(this);var p=n.apply(t,a);return p.__actions__.push({func:ta,args:[f],thisArg:void 0}),new Ne(p,s)}return h&&d?n.apply(this,a):(p=this.thru(f),h?r?p.value()[0]:p.value():p)})})),ct(["pop","push","shift","sort","splice","unshift"],(function(n){var t=yn[n],e=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",r=/^(?:pop|shift)$/.test(n);xe.prototype[n]=function(){var n=arguments;if(r&&!this.__chain__){var u=this.value();return t.apply(Ba(u)?u:[],n)}return this[e]((function(e){return t.apply(Ba(e)?e:[],n)}))}})),cr(Be.prototype,(function(n,t){var e=xe[t];if(e){var r=e.name+"";Cn.call(me,r)||(me[r]=[]),me[r].push({name:t,func:e})}})),me[xu(void 0,2).name]=[{name:"wrapper",func:void 0}],Be.prototype.clone=function(){var n=new Be(this.__wrapped__);return n.__actions__=Du(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=Du(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Du(this.__views__),n},Be.prototype.reverse=function(){if(this.__filtered__){var n=new Be(this);n.__dir__=-1,n.__filtered__=!0}else(n=this.clone()).__dir__*=-1;return n},Be.prototype.value=function(){var n=this.__wrapped__.value(),t=this.__dir__,e=Ba(n),r=t<0,u=e?n.length:0,i=function(n,t,e){var r=-1,u=e.length;for(;++r=this.__values__.length;return{done:n,value:n?void 0:this.__values__[this.__index__++]}},xe.prototype.plant=function(n){for(var t,e=this;e instanceof Oe;){var r=Ai(e);r.__index__=0,r.__values__=void 0,t?u.__wrapped__=r:t=r;var u=r;e=e.__wrapped__}return u.__wrapped__=n,t},xe.prototype.reverse=function(){var n=this.__wrapped__;if(n instanceof Be){var t=n;return this.__actions__.length&&(t=new Be(this)),(t=t.reverse()).__actions__.push({func:ta,args:[Pi],thisArg:void 0}),new Ne(t,this.__chain__)}return this.thru(Pi)},xe.prototype.toJSON=xe.prototype.valueOf=xe.prototype.value=function(){return eu(this.__wrapped__,this.__actions__)},xe.prototype.first=xe.prototype.head,Xn&&(xe.prototype[Xn]=function(){return this}),xe}();Kn._=Ht,void 0===(u=function(){return Ht}.call(t,e,t,r))||(r.exports=u)}).call(this)}).call(this,e(76),e(456)(n))},454:function(n,t,e){"use strict";var r=e(0),u=Object(r.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=u},455:function(n,t,e){"use strict";e.d(t,"a",(function(){return i}));e(77),e(473),e(439),e(78);var r=e(475),u=e.n(r);function i(n,t){var e=new u.a;return n.map((function(n){var r=n;return"string"==typeof n&&(r={label:n,permalink:"/blog/tags/"+e.slug(n)}),function(n,t){var e=n.label.split(": ",2),r=e[0],u=e[1],i="primary";switch(t){case"blog":case"guides":i=function(n){switch(n){case"domain":return"blue";case"type":return"pink";default:return"primary"}}(r)}return{category:r,count:n.count,label:n.label,permalink:n.permalink,style:i,value:u}}(r,t)}))}},456:function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},465:function(n,t,e){var r=e(30),u=e(54),i=e(27),a=e(26),o=e(466);n.exports=function(n,t){var e=1==n,c=2==n,l=3==n,f=4==n,s=6==n,v=5==n||s,h=t||o;return function(t,o,d){for(var p,g,D=i(t),_=u(D),m=r(o,d,3),y=a(_.length),b=0,E=e?h(t,y):c?h(t,0):void 0;y>b;b++)if((v||b in _)&&(g=m(p=_[b],b,D),n))if(e)E[b]=g;else if(g)switch(n){case 3:return!0;case 5:return p;case 6:return b;case 2:E.push(p)}else if(f)return!1;return s?-1:l||f?f:E}}},466:function(n,t,e){var r=e(467);n.exports=function(n,t){return new(r(n))(t)}},467:function(n,t,e){var r=e(13),u=e(468),i=e(2)("species");n.exports=function(n){var t;return u(n)&&("function"!=typeof(t=n.constructor)||t!==Array&&!u(t.prototype)||(t=void 0),r(t)&&null===(t=t[i])&&(t=void 0)),void 0===t?Array:t}},468:function(n,t,e){var r=e(23);n.exports=Array.isArray||function(n){return"Array"==r(n)}},474:function(n,t,e){"use strict";var r=e(0),u=e.n(r),i=e(430),a=e(423),o=e.n(a);t.a=function(n){var t=n.count,e=n.label,r=n.permalink,a=n.style,c=n.value,l=n.valueOnly;return u.a.createElement(i.a,{to:r+"/",className:o()("badge","badge--rounded","badge--"+a)},l?c:e,t&&u.a.createElement(u.a.Fragment,null," (",t,")"))}},475:function(n,t,e){var r=e(476);n.exports=o;var u=Object.hasOwnProperty,i=/\s/g,a=/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~\u2019]/g;function o(){if(!(this instanceof o))return new o;this.reset()}function c(n,t){return"string"!=typeof n?"":(t||(n=n.toLowerCase()),n.trim().replace(a,"").replace(r(),"").replace(i,"-"))}o.prototype.slug=function(n,t){for(var e=c(n,!0===t),r=e;u.call(this.occurrences,e);)this.occurrences[r]++,e=r+"-"+this.occurrences[r];return this.occurrences[e]=0,e},o.prototype.reset=function(){this.occurrences=Object.create(null)},o.slug=c},476:function(n,t){n.exports=function(){return/[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD79\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED0\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3]|\uD83E[\uDD10-\uDD18\uDD80-\uDD84\uDDC0]|\uD83C\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uD83C\uDDFE\uD83C[\uDDEA\uDDF9]|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDFC\uD83C[\uDDEB\uDDF8]|\uD83C\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uD83C\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF8\uDDFE\uDDFF]|\uD83C\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uD83C\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uD83C\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uD83C\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uD83C\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uD83C\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uD83C\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uD83C\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uD83C\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uD83C\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uD83C\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uD83C\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uD83C\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uD83C\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uD83C\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uD83C\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|[#\*0-9]\u20E3/g}},480:function(n,t,e){"use strict";var r=e(1),u=e(0),i=e.n(u),a=(e(430),e(474)),o=e(423),c=e.n(o),l=e(455),f=e(141),s=e.n(f);t.a=function(n){var t,e=n.block,u=n.colorProfile,o=n.tags,f=n.valuesOnly,v=Object(l.a)(o,u);return i.a.createElement("div",{className:c()(s.a.tags,(t={},t[s.a.tagsBlock]=e,t))},v.map((function(n,t){return i.a.createElement(a.a,Object(r.a)({key:t,valueOnly:f},n))})))}},516:function(n,t,e){"use strict";e(29),e(22),e(21),e(52);var r=e(0),u=e.n(r),i=(e(428),e(439),e(430)),a=e(440),o=e.n(a),c=e(480),l=e(455),f=e(436),s=e(441);e(142);var v=function(n){var t=n.frontMatter,e=n.metadata,r=(n.isGuidePage,Object(s.a)().isDarkTheme),a=e.categories,v=(e.description,e.permalink),h=(e.readingTime,e.seriesPosition),d=e.tags,p=(t.author_github,t.cover_label),g=(t.last_modified_on,t.title),D=Object(l.a)(d,"guides"),_=D.find((function(n){return"domain"==n.category})),m=_?_.value:"default",y=D.find((function(n){return"language"==n.category})),b=y?y.value:null,E=D.find((function(n){return"framework"==n.category})),w=E?E.value:null,F=D.find((function(n){return"technology"==n.category})),C=F?F.value:null,k=D.find((function(n){return"cloud_provider"==n.category})),A=k?k.value:null,x=D.find((function(n){return"provider"==n.category})),j=x?x.value:null,O=D.find((function(n){return"platform"==n.category})),N=O?O.value:null,B=D.find((function(n){return"source"==n.category})),I=B?B.value:null,S=D.find((function(n){return"sink"==n.category})),L=S?S.value:null,R=Object(f.a)().siteConfig.customFields.metadata,T=R.installation,z=R.sources,W=R.sinks,M=R.languages,U=R.frameworks,P=R.technologies,$=R.cloud_providers,q=R.providers,V=T.platforms,G=N&&V[N],Z=I&&z[I],K=L&&W[L],H=b&&M.find((function(n){return n.name===b})),Q=w&&U.find((function(n){return n.name===w})),J=C&&P.find((function(n){return n.name===C})),Y=A&&$.find((function(n){return n.name===A})),X=j&&q.find((function(n){return n.name===j})),nn=null!==(G||Z),tn=null!=K,en=null;Q?en=r?Q.dark_logo_path:Q.logo_path:J?en=r?J.dark_logo_path:J.logo_path:Y?en=r?Y.dark_logo_path:Y.logo_path:X?en=r?X.dark_logo_path:X.logo_path:H?en=r?H.dark_logo_path:H.logo_path:G?en=G.logo_path:Z&&(en=Z.logo_path);var rn=null;return K&&(rn=K.logo_path),u.a.createElement(i.a,{to:v+"/",className:"guide-item"},u.a.createElement("article",null,u.a.createElement("div",{className:"domain-bg domain-bg--"+m+" domain-bg--hover"},u.a.createElement("header",null,u.a.createElement("div",{className:"category"},a[0].name),u.a.createElement("h2",{title:g},h&&h+". ",p||g)),u.a.createElement("footer",null,en&&u.a.createElement(o.a,{src:en,className:"logo"}),!en&&nn&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),rn&&u.a.createElement(o.a,{src:rn,className:"logo"}),!rn&&tn&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),!en&&!rn&&!nn&&!tn&&u.a.createElement(c.a,{colorProfile:"guides",tags:d}),u.a.createElement("div",{className:"action"},"read now")))))},h=e(450),d=e(451),p=e.n(d),g=e(423),D=e.n(g);e(143);function _(n){var t=n.groupLevel,e=n.items,r=n.large,i=n.staggered,a=p()(e).map((function(n){return n.content.metadata.categories[t-1]})).uniqBy("permalink").sortBy("title").keyBy("permalink").value(),o=p.a.groupBy(e,(function(n){return n.content.metadata.categories[t-1].permalink})),c=Object(h.a)("h"+(t+1));return Object.keys(a).map((function(n,t){var e=o[n],l=a[n];return u.a.createElement("section",{key:t},u.a.createElement(c,{id:n},l.title),l.description&&u.a.createElement("div",{className:"sub-title"},l.description),u.a.createElement(m,{items:e,large:r,staggered:i}))}))}function m(n){var t=n.groupLevel,e=n.items,r=n.large,i=n.staggered;if(t)return u.a.createElement(_,{groupLevel:t,items:e});var a,o=(a=e,p.a.sortBy(a,["content.metadata.seriesPosition",function(n){return n.content.metadata.coverLabel.toLowerCase()}]));return u.a.createElement("div",{className:"guides"},u.a.createElement("div",{className:D()("guide-items",{"guide-items--l":r,"guide-items--staggered":i})},o.map((function(n){var t=n.content;return u.a.createElement(v,{key:t.metadata.permalink,frontMatter:t.frontMatter,metadata:t.metadata,truncated:t.metadata.truncated},u.a.createElement(t,null))}))))}t.a=m}}]); \ No newline at end of file diff --git a/004ec9e5.42e25d86.js.LICENSE.txt b/004ec9e5.4f0152e2.js.LICENSE.txt similarity index 100% rename from 004ec9e5.42e25d86.js.LICENSE.txt rename to 004ec9e5.4f0152e2.js.LICENSE.txt diff --git a/02ec211a.dcf47fdc.js b/02ec211a.dcf47fdc.js new file mode 100644 index 0000000000..a807beb99b --- /dev/null +++ b/02ec211a.dcf47fdc.js @@ -0,0 +1,2 @@ +/*! For license information please see 02ec211a.dcf47fdc.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{154:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return m}));var o=n(1),a=n(9),i=(n(0),n(425)),r=n(434),l=(n(431),n(424)),c=n(429),s={last_modified_on:"2023-12-19",title:"Helm",description:"Learn how to configure your Helm on Qovery"},u={id:"using-qovery/configuration/helm",title:"Helm",description:"Learn how to configure your Helm on Qovery",source:"@site/docs/using-qovery/configuration/helm.md",permalink:"/docs/using-qovery/configuration/helm",sidebar:"docs",previous:{title:"Application",permalink:"/docs/using-qovery/configuration/application"},next:{title:"Databases",permalink:"/docs/using-qovery/configuration/database"}},b=[{value:"Deploying from a Git Repository",id:"deploying-from-a-git-repository",children:[]},{value:"Deploying from a Helm Repository",id:"deploying-from-a-helm-repository",children:[]},{value:"Create a Helm",id:"create-a-helm",children:[]},{value:"Deployment Management",id:"deployment-management",children:[]},{value:"Configuration",id:"configuration",children:[{value:"General",id:"general",children:[]},{value:"Values",id:"values",children:[]},{value:"Ports",id:"ports",children:[]},{value:"Domains",id:"domains",children:[]}]},{value:"Connecting from the internet",id:"connecting-from-the-internet",children:[{value:"Qovery provided domains",id:"qovery-provided-domains",children:[]},{value:"Custom domains",id:"custom-domains",children:[]}]},{value:"Logs",id:"logs",children:[]},{value:"Clone",id:"clone",children:[]},{value:"Delete a Helm",id:"delete-a-helm",children:[]}],p={rightToc:b};function m(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(c.a,{name:"documentation",mdxType:"Assumptions"},Object(i.b)("p",null,"You have created an ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment"),".")),Object(i.b)("p",null,"A ",Object(i.b)("strong",{parentName:"p"},"helm")," is one of the service types that can be deployed within an ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment"),". Via the helm service you can deploy any helm chart from a git repository or helm repository directly on the kubernetes cluster."),Object(i.b)("p",null,"Qovery allows you to create and deploy helms from two different sources: Git Repository or Helm Repository"),Object(i.b)("h2",{id:"deploying-from-a-git-repository"},"Deploying from a Git Repository"),Object(i.b)("p",null,"In this configuration, Qovery will pull the chart from the chosen repository and install it on your kubernetes cluster."),Object(i.b)("h2",{id:"deploying-from-a-helm-repository"},"Deploying from a Helm Repository"),Object(i.b)("p",null,"In this configuration, Qovery will pull the chosen helm repository a chart and install it on your kubernetes cluster."),Object(i.b)("p",null,"To improve security and avoid deploying charts from non-authorized repositories, we have decided to restrict the list of Helm Repositories you can use during the setup process. Only an administrator with the right permissions can manage it from the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"Helm Repository Management page")),Object(i.b)("h2",{id:"create-a-helm"},"Create a Helm"),Object(i.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,'Go into the chosen environment and press the "New Service" button and then the "Create helm" button')),Object(i.b)("li",null,Object(i.b)("p",null,"Select the following fields:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Helm chart Name: give a name to your helm"),Object(i.b)("li",{parentName:"ul"},"Description (Optional): write a text to describe your helm service"),Object(i.b)("li",{parentName:"ul"},"Helm chart Source: Chose between Git Repository or Helm Repository, depending on the source location of your application")),Object(i.b)("p",null,"If you want to deploy a helm from a Git Repository you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Git Repository: Select the git provider and the git repository hosting your code (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Branch: Select branch that Qovery should use to deploy your helm"),Object(i.b)("li",{parentName:"ul"},"Root Helm Path: base folder in which the helm chart resides in your repository")),Object(i.b)("p",null,"If you want to deploy a helm from a Helm Repository you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Helm repository: select the helm repository storing the helm chart. Note: only pre-configured registry are available in this list, check the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"Helm Repository Management page")," for more information.")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Chart name: the name of the helm to be deployed with this application (example: jenkins)")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Chart version: the version of the chart to be deployed with this application (example: 1.0.0). ")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Helm arguments: specify the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://helm.sh/docs/helm/helm_install/#options"}),"helm arguments")," to be used during the helm install/upgrade.")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Helm timeout: specify the value to wait for Kubernetes commands to complete. This defaults to 5mins.")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Allow cluster-wide resources: Allow this chart to deploy resources outside of the environment namespace. You must have the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/members-rbac/"}),"full-access permissions")," on the cluster, the right is present by default in ",Object(i.b)("inlineCode",{parentName:"p"},"Admin"),", ",Object(i.b)("inlineCode",{parentName:"p"},"Devops")," and ",Object(i.b)("inlineCode",{parentName:"p"},"Owner")," roles. Example: if you want to create a new CRD or a new ClusterRole, check this flag."))),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Auto Deploy ")),Object(i.b)("p",null,"Available only if you have selected a git repository as helm source.\nSee the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section.")),Object(i.b)("li",null,Object(i.b)("p",null,"By default, the ",Object(i.b)("inlineCode",{parentName:"p"},"values.yaml")," next to your ",Object(i.b)("inlineCode",{parentName:"p"},"chart.yaml")," is used. But you can override it with another file.\nSelect the following field:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"File source: Chose between Git Repository or Raw YAML, depending on the source location of your values file. Git repository source is ",Object(i.b)("strong",{parentName:"li"},"recommended")," as the raw yaml is not versioned.")),Object(i.b)("p",null,"If you want to override it from another already existing values file from a Git Repository (it can be the same as the one hosting the helm chart) you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Git Repository: Select the git provider and git repository hosting your values override (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Branch: Select branch that Qovery should use to deploy your helm"),Object(i.b)("li",{parentName:"ul"},"Overrides path: the path of the values files (example: ci/values_ci.yaml). You can specify multiple paths by separating them with a semi-colon.")),Object(i.b)("p",null,"If you want to override it with a raw yaml you will have to click on ",Object(i.b)("inlineCode",{parentName:"p"},"Create override"),". A new editor modal will be opened, to let you write your yaml override. The default values.yaml content will be displayed on the right to help you to respect the structure."),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"You can override values in the arguments section with the ",Object(i.b)("inlineCode",{parentName:"p"},"--set")," option.")),Object(i.b)("p",null,"You can use the Qovery environment variables as overrides by using the placeholder \u201cqovery.env.\u201d (Example: qovery.env.DB_URL. Qovery will manage the replacement of those placeholders at deployment time.")),Object(i.b)("li",null,Object(i.b)("p",null,"if you want to specify one by one your overrides, you can pass them as arguments. These will be passed to the helm command via the ",Object(i.b)("inlineCode",{parentName:"p"},"--set"),", ",Object(i.b)("inlineCode",{parentName:"p"},"--set-string")," or ",Object(i.b)("inlineCode",{parentName:"p"},"--set-json")," arguments:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Variable: the variable name"),Object(i.b)("li",{parentName:"ul"},"Value type: ",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"Select ",Object(i.b)("inlineCode",{parentName:"li"},"Generic")," to pass configuration from the command line"),Object(i.b)("li",{parentName:"ul"},"Select ",Object(i.b)("inlineCode",{parentName:"li"},"String")," if you want to pass a string type (and avoid weird numeric conversions like 021341 interpreted as a number and thus the 0 is removed)"),Object(i.b)("li",{parentName:"ul"},"Select ",Object(i.b)("inlineCode",{parentName:"li"},"Json")," to set json values (scalars/objects/arrays) from the command line"))),Object(i.b)("li",{parentName:"ul"},"Value")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"You can combine override as file and override as argument but, in case of collision, the priority will be given to the override as argument."))),Object(i.b)("li",null,Object(i.b)("p",null,"You can now expose publicly one or more ports for your services defined in the helm chart by specifying:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Service name: this is the kubernetes service name in your helm chart"),Object(i.b)("li",{parentName:"ul"},"Namespace (only if Allow cluster-wide resources was enabled): this is the kubernetes namespace used by your helm chart to deploy the pods behind the chosen service"),Object(i.b)("li",{parentName:"ul"},"Service port: this is the port exposed internally by your service"),Object(i.b)("li",{parentName:"ul"},"Protocol: you can select the protocol used by your service. Today Qovery supports the following protocols:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"HTTPS (Select this protocol if you need to run Websockets)"),Object(i.b)("li",{parentName:"ul"},"gRPC"))),Object(i.b)("li",{parentName:"ul"},"External port: it is the port that can be used to access this service over the internet (when exposed publicly). Note that for HTTP and gRPC the port is set by default to 443."),Object(i.b)("li",{parentName:"ul"},"Port Name: it is the name assigned to the port. When multiple ports are exposed publicly, its value is used to route the traffic to the right port based on the called subdomain (which will contain the port name value). Since each port is exposed on the port 443, having a different subdomain is the only way to have multiple ports exposed over the internet. If not set, the default value is ",Object(i.b)("inlineCode",{parentName:"li"},"p")," (see ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"#qovery-provided-domains"}),"Qovery Provided Domain section")," for more information)")),Object(i.b)("p",null,"By default services are accessible only from inside your namespace(s). You can expose them publicly, making them accessible over the public network via a dedicated public domain that will be assigned to your application by Qovery during the deployment (See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"#qovery-provided-domains"}),"Qovery Provided Domains section"),"). Note that HTTPS/gRPC ports are always exposed over the port 443."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/helm/helm_creation_port.png",alt:"Helm Ports"})),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Important Informations")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Connections on public ports are automatically closed after 60 seconds. If you want to implement long living connection (like for websockets) please make sure to use the rigth ingress timeouts in the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/advanced-settings/#network-settings"}),"advanced settings section")))),Object(i.b)("li",null,Object(i.b)("p",null,"You will find a recap of your helm setup and you can now decide to:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Go back to one of the previous steps and change your helm settings (1)"),Object(i.b)("li",{parentName:"ul"},"Create your helm without deploying it (2)"),Object(i.b)("li",{parentName:"ul"},"Create and deploy your helm (3)")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/helm/helm_creation_recap.png",alt:"Helm"}))))),Object(i.b)("h2",{id:"deployment-management"},"Deployment Management"),Object(i.b)("p",null,"Have a look at the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/"}),"Deployment Management")," section for more information."),Object(i.b)("h2",{id:"configuration"},"Configuration"),Object(i.b)("p",null,"Once created, you can access the configuration of a helm at any time via the Settings tab available on the helm section"),Object(i.b)("p",null,"You can find below the description of each of the tabs available in this section"),Object(i.b)("h3",{id:"general"},"General"),Object(i.b)("p",null,"General settings section allows you to set up the name and the source of your helm (git repository or helm repository) ."),Object(i.b)("h4",{id:"git-repository"},"Git Repository"),Object(i.b)("p",null,"If your heml is from a git repository, within this section you can:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Modify the git provider where your code is stored (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Modify the branch that Qovery should use for deploying your application"),Object(i.b)("li",{parentName:"ul"},"Modify ",Object(i.b)("inlineCode",{parentName:"li"},"Root Helm Path")," - base folder in which the helm chart resides in your repository")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Qovery supports mono repositories. ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/advanced/monorepository/"}),"See our advanced guide for more details."))),Object(i.b)(l.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"If your repository contains private submodules using SSH protocol, you will need to add a secret beginning with GIT",Object(i.b)("em",{parentName:"p"},"SSH_KEY"),", containing a private SSH key with access rights to your sumbodules repositories."),Object(i.b)("p",null,"Secret names examples:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITHUB"),Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITLAB"),Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_MYAPP"))),Object(i.b)("h4",{id:"helm-repository"},"Helm Repository"),Object(i.b)("p",null,"If your helm is deployed from a helm repository, within this section you can modify:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Helm repository: select the helm repository storing the helm chart. Note: only pre-configured registry are available in this list, check the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"Helm Repository Management page")," for more information."),Object(i.b)("li",{parentName:"ul"},"Chart name: the name of the helm to be deployed with this application (example: jenkins)"),Object(i.b)("li",{parentName:"ul"},"Chart version: the version of the chart to be deployed with this application (example: 1.0.0). ")),Object(i.b)("h4",{id:"arguments"},"Arguments"),Object(i.b)("p",null,"For both kind of helm source, within this section yoiu can modify:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Helm arguments: specify the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"https://helm.sh/docs/intro/using_helm/#helpful-options-for-installupgraderollback"}),"helm arguments")," to be used during the helm install/upgrade."),Object(i.b)("li",{parentName:"ul"},"Helm timeout: specify the value to wait for Kubernetes commands to complete. This defaults to 5mins.")),Object(i.b)("h4",{id:"auto-deploy"},"Auto Deploy"),Object(i.b)("p",null,"See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section."),Object(i.b)("h3",{id:"values"},"Values"),Object(i.b)("p",null,"Within this section you can modify the values override.\nSelect the following field:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"File source: Chose between Git Repository or Raw YAML, depending on the source location of your values file")),Object(i.b)("p",null,"If you want to override it from another already existing values file from a Git Repository you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Git Repository: Select the git provider and git repository hosting your code (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Branch: Select branch that Qovery should use to deploy your helm"),Object(i.b)("li",{parentName:"ul"},"Overrides path: the path of the values files (example: ci/values_ci.yaml). You can specify multiple paths by separating them with a semi-colon.")),Object(i.b)("p",null,"If you want to override it with a raw yaml you will have to click on ",Object(i.b)("inlineCode",{parentName:"p"},"Create override"),". A new editor modal will be opened, to let you write your yaml override. The default values.yaml content will be displayed on the right to help you to respect the structure."),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"You can override values in the arguments section with the ",Object(i.b)("inlineCode",{parentName:"p"},"--set")," option.")),Object(i.b)("h3",{id:"ports"},"Ports"),Object(i.b)("p",null,"Within this section you can define the port exposed publicly.\nYou can edit the existing ports or declare new ones by specifying:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Service name: this is the kubernetes service name in your helm chart"),Object(i.b)("li",{parentName:"ul"},"Namespace (only if Allow cluster-wide resources was enabled): this is the kubernetes namespace used by your helm chart to deploy the pods behind the chosen service"),Object(i.b)("li",{parentName:"ul"},"Service port: this is the port exposed internally by your service for the other services"),Object(i.b)("li",{parentName:"ul"},"Protocol: you can select the protocol used by your service. Today Qovery supports the following protocols:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"HTTPS (Select this protocol if you need to run Websockets)"),Object(i.b)("li",{parentName:"ul"},"gRPC"))),Object(i.b)("li",{parentName:"ul"},"External port: it is the port that can be used to access this service over the internet (when exposed publicly). Note that for HTTP and gRPC the port is set by default to 443."),Object(i.b)("li",{parentName:"ul"},"Port Name: it is the name assigned to the port. When multiple ports are exposed publicly, its value is used to route the traffic to the right port based on the called subdomain (which will contain the port name value). Since each port is exposed on the port 443, having a different subdomain is the only way to have multiple ports exposed over the internet. If not set, the default value is ",Object(i.b)("inlineCode",{parentName:"li"},"p")," (see ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"#qovery-provided-domains"}),"Qovery Provided Domain section")," for more information)")),Object(i.b)("h4",{id:"important-informations"},"Important Informations"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Connections on public ports are automatically closed after 60 seconds. If you want to implement long living connection (like for websockets) please make sure to use the rigth ingress timeouts in the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/advanced-settings/#network-settings"}),"advanced settings section"))),Object(i.b)("h3",{id:"domains"},"Domains"),Object(i.b)("p",null,"Within this section you can customize the domain used to reach your helm services. "),Object(i.b)("p",null,"You can customize the domain of your helm services in different ways, depending on what you want to achieve:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"You want to use your own domain for your helm services"),Object(i.b)("li",{parentName:"ul"},"You want to modify the subdomain assigned to your helm services by Qovery (i.e. change ",Object(i.b)("inlineCode",{parentName:"li"},"p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh")," into ",Object(i.b)("inlineCode",{parentName:"li"},"my-app-domain.za8ad0657.bool.sh"),").")),Object(i.b)("p",null,"In both cases, you can assign the new custom domain to your helm services press the ",Object(i.b)("inlineCode",{parentName:"p"},"Add Domain")," button. "),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-16.png",alt:"Application Domains"})),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"This configuration will be ",Object(i.b)("strong",{parentName:"p"},"automatically removed")," on every cloned environment or preview environment in order to avoid domain collision.")),Object(i.b)("h4",{id:"configuring-your-own-domain"},"Configuring your own domain"),Object(i.b)("p",null,"Once the domain is added within the Qovery console (Example: mydomain.com), you need to configure within your DNS two ",Object(i.b)("inlineCode",{parentName:"p"},"CNAME")," records pointing to the domain provided by Qovery, as shown in the UI (example: mydomain.com CNAME za7cc1b71-z4b8474b3-gtw.zc531a994.rustrocks.cloud and *.mydomain.com CNAME za7cc1b71-z4b8474b3-gtw.zc531a994.rustrocks.cloud). "),Object(i.b)("p",null,"Having a wildcard domain (example: *.mydomain.com) configured on your DNS will avoid you to modify the Qovery setup every time you want to add a new subdomain. If ",Object(i.b)("inlineCode",{parentName:"p"},"wildcard")," is not supported by your DNS provider, you will have to configure each subdomain manually."),Object(i.b)("p",null,"If the service needs to expose more than one port publicly, you can define a dedicated subdomain to redirect the traffic on the right port by setting the \u201cPort Name\u201d value within the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"#ports"}),"port settings"),"."),Object(i.b)("p",null,"From this point, Qovery will automatically handle the TLS/SSL certificate creation and renewal for the configured domain."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/custom-domain.png",alt:"Custom Domain"})),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Special case - CDN in proxy mode ")),Object(i.b)("p",null,"If your service is behind a CDN using a ",Object(i.b)("inlineCode",{parentName:"p"},"proxy mode"),' (i.e. the traffic is routed through the CDN to Qovery), make sure to disable the option "Generate certificate" on the domain setup. Since the certificate of your domain is directly managed by the CDN, Qovery won\'t be able to do that for you and it will raise warnings on your application status.'),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/cdn-proxy.png",alt:"CDN Proxy"})),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/setting-custom-domain/"}),"We prepared a guide and video tutorial that explains how to set up your custom domain."))),Object(i.b)("h4",{id:"change-the-auto-assigned-sub-domain"},"Change the auto assigned sub-domain"),Object(i.b)("p",null,"You can specify a different sub-domain for your helm services as long as it belongs to the assigned cluster domain (see ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"#qovery-provided-domains"}),"Qovery provided domains"),").\nExample: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"your current domain is zdf72de71-z709e1a85-gtw.za8ad0659.bool.sh (so your assigned cluster domain is ",Object(i.b)("inlineCode",{parentName:"li"},"za8ad0659.bool.sh"),")"),Object(i.b)("li",{parentName:"ul"},"you can enter a new custom domain ",Object(i.b)("inlineCode",{parentName:"li"},"myfrontend.za8ad0659.bool.sh")," (since it is a subdomain of the cluster domain)")),Object(i.b)("p",null,"The helm services will now be accessible from both the default and the new custom domain."),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Qovery does not check collision in the domain declaration. Make sure you assign a unique subdomain within your cluster.")),Object(i.b)("h2",{id:"connecting-from-the-internet"},"Connecting from the internet"),Object(i.b)("p",null,"Your helm services can be reached from the internet by publicly exposing at least one of its ports (See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"#ports"}),"Ports")," section to know more). Once this is done, Qovery will generate for you a domain to reach your application from the internet. You can also customize the domain assigned to your application and manage by yourself this assignment via the ",Object(i.b)("inlineCode",{parentName:"p"},"Domain")," section."),Object(i.b)("h3",{id:"qovery-provided-domains"},"Qovery provided domains"),Object(i.b)("p",null,"For each port publicly exposed, a domain is automatically assigned by Qovery to your helm services. Qovery will manage for you the networking and the TLS configuration for these domains. "),Object(i.b)("p",null,"Example: ",Object(i.b)("inlineCode",{parentName:"p"},"p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh")," or ",Object(i.b)("inlineCode",{parentName:"p"},"-p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh")," for helm services."),Object(i.b)("p",null,"Note:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"each service deployed on the same cluster will have the same root domain assigned (example: ",Object(i.b)("inlineCode",{parentName:"li"},"za8ad0657.bool.sh"),")"),Object(i.b)("li",{parentName:"ul"},"the first characters of the domain (before the ",Object(i.b)("inlineCode",{parentName:"li"},"-"),") is based on the portName given to the port associated with this domain (See the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"#ports"}),"port section"),")"),Object(i.b)("li",{parentName:"ul"},"a default domain (without the portName) is assigned to the ",Object(i.b)("inlineCode",{parentName:"li"},"default port"),"(See the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"#ports"}),"port section"),"). Example ",Object(i.b)("inlineCode",{parentName:"li"},"zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh"))),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Special Case - Preview Environment"),"\nFor each port exposed publicly, an additional domain will be created with the following pattern ",Object(i.b)("inlineCode",{parentName:"p"},"portName-prId-srvName-envSourceName.cluster_domain"),":"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"portName: is the port name, as explained above"),Object(i.b)("li",{parentName:"ul"},"prID: is the id of the PR that has generated the preview environment"),Object(i.b)("li",{parentName:"ul"},"srvName: is the name of the service"),Object(i.b)("li",{parentName:"ul"},"envSourceName: is the name of the blueprint environment that has created the current preview environment")),Object(i.b)("p",null,"domain example: ",Object(i.b)("inlineCode",{parentName:"p"},"p80-123-frontend-blueprint.za8ad0657.bool.sh")),Object(i.b)("h3",{id:"custom-domains"},"Custom domains"),Object(i.b)("p",null,"If you prefer to assign your own domain to the helm services, have a look at the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"#domains"}),"Domain section")," to know more."),Object(i.b)("h2",{id:"logs"},"Logs"),Object(i.b)("p",null,"To learn how to display your helm logs, navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#live-logs"}),"logs section")),Object(i.b)("h2",{id:"clone"},"Clone"),Object(i.b)("p",null,"You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/clone_service.png",alt:"Clone Service"})),Object(i.b)("p",null,"The target environment can be the same as the current environment or even another one in a completely different project."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Important information ")),Object(i.b)("p",null,"Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"same environment:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"))),Object(i.b)("li",{parentName:"ul"},"another environment:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"),Object(i.b)("li",{parentName:"ul"},"environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)"),Object(i.b)("li",{parentName:"ul"},"deployment pipeline: stage setup is not copied (since the target stage might not exist)"),Object(i.b)("li",{parentName:"ul"},"number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)")))),Object(i.b)("p",null,"Please check the configuration of the new service before deploying it."),Object(i.b)("h2",{id:"delete-a-helm"},"Delete a Helm"),Object(i.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Choose your helm")),Object(i.b)("li",null,Object(i.b)("p",null,"In the helm overview, click on the ",Object(i.b)("inlineCode",{parentName:"p"},"3 dots")," button and remove the helm.")))))}m.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},b=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,r=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),b=u(n),m=o,d=b["".concat(r,".").concat(m)]||b[m]||p[m]||i;return n?a.a.createElement(d,l({ref:t},s,{components:n})):a.a.createElement(d,l({ref:t},s))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:o,r[1]=l;for(var s=2;s1?arguments[1]:void 0,n),c=r>2?arguments[2]:void 0,s=void 0===c?n:a(c,n);s>l;)t[l++]=e;return t}},428:function(e,t,n){var o=n(28).f,a=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in a||n(10)&&o(a,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var o=n(0),a=n.n(o),i=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var o=n(1),a=n(0),i=n.n(a),r=n(39),l=n(432),c=n(20),s=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,u=n||c,b=Object(l.a)(u),p=Object(a.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!m&&b&&window.docusaurus.prefetch(u),function(){m&&t&&t.disconnect()}}),[u,m,b]),u&&b?i.a.createElement(r.b,Object(o.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,o;m&&e&&b&&(n=e,o=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:u})):i.a.createElement("a",Object(o.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var o=n(0),a=n.n(o),i=n(430),r=n(423),l=n.n(r);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,r=e.leftIcon,c=e.rightIcon,s=e.size,u=e.target,b=e.to,p=l()("jump-to","jump-to--"+s,n),m=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},r&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+r})),a.a.createElement("div",{className:"jump-to--main"},o?a.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return u?a.a.createElement("a",{href:b,target:u,className:p},m):a.a.createElement(i.a,{to:b,className:p},m)}},432:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},433:function(e,t,n){"use strict";var o=n(435),a=n(51);function i(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(a),i,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[i(t,e),"[",o,"]"].join(""):[i(t,e),"[",i(o,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var a=e[o];if(void 0===a)return"";if(null===a)return i(o,t);if(Array.isArray(a)){var r=[];return a.slice().forEach((function(e){void 0!==e&&r.push(n(o,e,r.length))})),r.join("&")}return i(o,t)+"="+i(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var o=n(0),a=n.n(o),i=(n(423),n(433)),r=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,c={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+r.a.stringify(c),u=Object(o.useState)(null),b=u[0],p=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/03d003d1.b98d0d01.js.LICENSE.txt b/02ec211a.dcf47fdc.js.LICENSE.txt similarity index 100% rename from 03d003d1.b98d0d01.js.LICENSE.txt rename to 02ec211a.dcf47fdc.js.LICENSE.txt diff --git a/03d003d1.b98d0d01.js b/03d003d1.cd4985dd.js similarity index 93% rename from 03d003d1.b98d0d01.js rename to 03d003d1.cd4985dd.js index abac3f8f69..004808efac 100644 --- a/03d003d1.b98d0d01.js +++ b/03d003d1.cd4985dd.js @@ -1,2 +1,2 @@ -/*! For license information please see 03d003d1.b98d0d01.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{154:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),o=(n(0),n(422)),i=(n(431),n(426),n(421),{last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Continuous Integration",description:"Learn how to integrate your Continuous Integration (CI) platform with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),c={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Continuous Integration",description:"Learn how to integrate your Continuous Integration (CI) platform with Qovery",permalink:"/guides/advanced/continuous-integration",readingTime:"2 min read",source:"@site/guides/advanced/continuous-integration.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Continuous Integration",truncated:!1,prevItem:{title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",permalink:"/guides/tutorial/build-e2e-testing-ephemeral-environments"},nextItem:{title:"Costs Control",permalink:"/guides/advanced/costs-control"}},u=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:u};function l(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery integrates with all existing Continuous Integration platforms. We have a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/"}),"guide for the most popular CI platforms"),". However, even if you don't find your CI platform, ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"you can see here")," that integrating Qovery into a CI is just a matter of:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Adding a new step into your CI pipeline"),Object(o.b)("li",{parentName:"ol"},"Installing the Qovery CLI"),Object(o.b)("li",{parentName:"ol"},"Running the ",Object(o.b)("inlineCode",{parentName:"li"},"qovery deploy ...")," commands")),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to integrate Qovery into your CI platform:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-integrate-qovery-with-github-actions/"}),"Step-by-step guide to integrate GitHub Actions")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-integrate-qovery-with-github-actions/"}),"Step-by-step guide to learn how to integrate GitHub Actions with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"Integrate GitHub Actions")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"Learn how to integrate GitHub Actions with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/gitlab-ci/"}),"Integrate GitLab CI")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/gitlab-ci/"}),"Learn how to integrate GitLab CI with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/circle-ci/"}),"Integrate Circle CI")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/circle-ci/"}),"Learn how to integrate Circle CI with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/jenkins/"}),"Integrate Jenkins")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/jenkins/"}),"Learn how to integrate Jenkins with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=github%20actions"}),'Forum "GitHub Actions"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=github%20actions"}),'List "GitHub Actions" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=gitlab%25ci"}),'Forum "GitLab CI"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=gitlab%20ci"}),'List "GitLab CI" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=circle%20ci"}),'Forum "Circle CI"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=circle%20ci"}),'List "Circle CI" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=jenkins"}),'Forum "Jenkins"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=jenkins"}),'List "Jenkins" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}l.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},b=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),b=l(n),m=r,d=b["".concat(i,".").concat(m)]||b[m]||p[m]||o;return n?a.a.createElement(d,c({ref:t},s,{components:n})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:a(u,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),b=l[0],p=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 03d003d1.cd4985dd.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{155:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),o=(n(0),n(425)),i=(n(434),n(429),n(424),{last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Continuous Integration",description:"Learn how to integrate your Continuous Integration (CI) platform with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),c={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Continuous Integration",description:"Learn how to integrate your Continuous Integration (CI) platform with Qovery",permalink:"/guides/advanced/continuous-integration",readingTime:"2 min read",source:"@site/guides/advanced/continuous-integration.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Continuous Integration",truncated:!1,prevItem:{title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",permalink:"/guides/tutorial/build-e2e-testing-ephemeral-environments"},nextItem:{title:"Costs Control",permalink:"/guides/advanced/costs-control"}},u=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:u};function l(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery integrates with all existing Continuous Integration platforms. We have a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/"}),"guide for the most popular CI platforms"),". However, even if you don't find your CI platform, ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"you can see here")," that integrating Qovery into a CI is just a matter of:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Adding a new step into your CI pipeline"),Object(o.b)("li",{parentName:"ol"},"Installing the Qovery CLI"),Object(o.b)("li",{parentName:"ol"},"Running the ",Object(o.b)("inlineCode",{parentName:"li"},"qovery deploy ...")," commands")),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to integrate Qovery into your CI platform:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-integrate-qovery-with-github-actions/"}),"Step-by-step guide to integrate GitHub Actions")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-integrate-qovery-with-github-actions/"}),"Step-by-step guide to learn how to integrate GitHub Actions with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"Integrate GitHub Actions")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"Learn how to integrate GitHub Actions with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/gitlab-ci/"}),"Integrate GitLab CI")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/gitlab-ci/"}),"Learn how to integrate GitLab CI with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/circle-ci/"}),"Integrate Circle CI")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/circle-ci/"}),"Learn how to integrate Circle CI with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/jenkins/"}),"Integrate Jenkins")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/jenkins/"}),"Learn how to integrate Jenkins with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=github%20actions"}),'Forum "GitHub Actions"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=github%20actions"}),'List "GitHub Actions" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=gitlab%25ci"}),'Forum "GitLab CI"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=gitlab%20ci"}),'List "GitLab CI" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=circle%20ci"}),'Forum "Circle CI"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=circle%20ci"}),'List "Circle CI" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=jenkins"}),'Forum "Jenkins"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=jenkins"}),'List "Jenkins" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}l.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},b=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),b=l(n),m=r,d=b["".concat(i,".").concat(m)]||b[m]||p[m]||o;return n?a.a.createElement(d,c({ref:t},s,{components:n})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:a(u,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),b=l[0],p=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/05049f86.79450b0f.js.LICENSE.txt b/03d003d1.cd4985dd.js.LICENSE.txt similarity index 100% rename from 05049f86.79450b0f.js.LICENSE.txt rename to 03d003d1.cd4985dd.js.LICENSE.txt diff --git a/03dbc155.c9c0fa5f.js b/03dbc155.57dfe7e9.js similarity index 97% rename from 03dbc155.c9c0fa5f.js rename to 03dbc155.57dfe7e9.js index 4a598418c4..e270c70db6 100644 --- a/03dbc155.c9c0fa5f.js +++ b/03dbc155.57dfe7e9.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{155:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return u})),a.d(t,"metadata",(function(){return s})),a.d(t,"rightToc",(function(){return p})),a.d(t,"default",(function(){return m}));var o=a(1),n=a(9),r=(a(0),a(422)),l=a(421),i=a(441),c=a(434),b=a(426),u={last_modified_on:"2023-05-29",$schema:"/.meta/.schemas/guides.json",title:"Migrate your application from Heroku to AWS",description:"Guide on how to migrate all your applications from Heroku to AWS with your databases",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Migrate your application from Heroku to AWS",description:"Guide on how to migrate all your applications from Heroku to AWS with your databases",permalink:"/guides/tutorial/migrate-your-application-from-heroku-to-aws",readingTime:"13 min read",source:"@site/guides/tutorial/migrate-your-application-from-heroku-to-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Migrate your application from Heroku to AWS",truncated:!1,prevItem:{title:"Microservices",permalink:"/guides/advanced/microservices"},nextItem:{title:"Migration",permalink:"/guides/advanced/migration"}},p=[{value:"Migration Steps",id:"migration-steps",children:[]},{value:"1. Create your Dockerfile or Use Buildpacks",id:"1-create-your-dockerfile-or-use-buildpacks",children:[{value:"Choose your Dockerfile template",id:"choose-your-dockerfile-template",children:[]},{value:"Test your Dockerfile",id:"test-your-dockerfile",children:[]},{value:"Environment variables at the build time",id:"environment-variables-at-the-build-time",children:[]},{value:"Add your Dockerfile to Git",id:"add-your-dockerfile-to-git",children:[]},{value:"Loop",id:"loop",children:[]},{value:"Limitations",id:"limitations",children:[]}]},{value:"2. Create resources on Qovery",id:"2-create-resources-on-qovery",children:[{value:"Application",id:"application",children:[]},{value:"Database",id:"database",children:[]}]},{value:"3. Configure your Environment Variables and Secrets",id:"3-configure-your-environment-variables-and-secrets",children:[{value:"Connect your frontend app to your backend app",id:"connect-your-frontend-app-to-your-backend-app",children:[]},{value:"Connect your backend app to your database",id:"connect-your-backend-app-to-your-database",children:[]}]},{value:"4. Copy data from your Heroku databases to your AWS databases",id:"4-copy-data-from-your-heroku-databases-to-your-aws-databases",children:[]},{value:"5. Deploy your apps!",id:"5-deploy-your-apps",children:[]},{value:"FAQ by Heroku users",id:"faq-by-heroku-users",children:[{value:"How to create a custom domain?",id:"how-to-create-a-custom-domain",children:[]},{value:"How to monitor my apps?",id:"how-to-monitor-my-apps",children:[]},{value:"Do you have Heroku "Review App" equivalent?",id:"do-you-have-heroku-review-app-equivalent",children:[]},{value:"How to rollback?",id:"how-to-rollback",children:[]},{value:"How auto-scaling works?",id:"how-auto-scaling-works",children:[]},{value:"How to manage database migration?",id:"how-to-manage-database-migration",children:[]},{value:"Is it possible to get a shell / connect to my app?",id:"is-it-possible-to-get-a-shell--connect-to-my-app",children:[]},{value:"Can I use Terraform and Infrastructure as Code?",id:"can-i-use-terraform-and-infrastructure-as-code",children:[]},{value:"How can I connect my app to MongoDB Atlas?",id:"how-can-i-connect-my-app-to-mongodb-atlas",children:[]},{value:"How can I connect my app to an AWS service not managed by Qovery?",id:"how-can-i-connect-my-app-to-an-aws-service-not-managed-by-qovery",children:[]}]},{value:"Wrapping up",id:"wrapping-up",children:[]}],d={rightToc:p};function m(e){var t=e.components,a=Object(n.a)(e,["components"]);return Object(r.b)("wrapper",Object(o.a)({},d,a,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"This guide describes how to migrate your application running on Heroku to AWS with Qovery. It covers all required steps you need to take to deploy your application on AWS and transfer your data from Heroku Postgres to the database managed by AWS via Qovery."),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Please contact us via ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum")," if you experience any problem while migrating from Heroku to AWS with Qovery.")),Object(r.b)(b.a,{name:"guide",mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You are familiar with Heroku basics, have a Heroku account and access to Heroku CLI"),Object(r.b)("li",{parentName:"ul"},"You have ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"https://start.qovery.com"}),"sign in on Qovery")),Object(r.b)("li",{parentName:"ul"},"You have ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/cloud-provider/guide-amazon-web-services/"}),"set up your AWS account")," with Qovery"))),Object(r.b)("h2",{id:"migration-steps"},"Migration Steps"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#1-create-your-dockerfile-or-use-buildpacks"}),"Use Buildpacks or Create your Dockerfile")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#2-create-resources-on-qovery"}),"Create resources on Qovery")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#3-configure-your-environment-variables-and-secrets"}),"Configure Environment Variables and Secrets")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#4-copy-data-from-your-heroku-databases-to-your-aws-databases"}),"Copy data from your Heroku databases to your AWS databases")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#5-deploy-your-apps-"}),"Deploy your apps")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#faq-by-heroku-users"}),"FAQ by Heroku users"))),Object(r.b)("h2",{id:"1-create-your-dockerfile-or-use-buildpacks"},"1. Create your Dockerfile or Use Buildpacks"),Object(r.b)("p",null,"Qovery supports two ways to build and run your application coming from Heroku:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Buildpacks"),Object(r.b)("li",{parentName:"ol"},"Docker")),Object(r.b)("p",null,"Both options build a container image that is runnable by a container engine (E.g. Docker). Qovery runs containers on Kubernetes."),Object(r.b)("p",null,"Choose the option that better fits you:"),Object(r.b)(c.a,{centered:!0,className:"rounded",defaultValue:"buildpacks",placeholder:"Use Buildpacks or Create your Dockerfile",select:!1,size:null,values:[{group:"Platforms",label:"Use Buildpacks",value:"buildpacks"},{group:"Platforms",label:"Create your Dockerfile",value:"dockerfile"}],mdxType:"Tabs"},Object(r.b)(i.a,{value:"dockerfile",mdxType:"TabItem"},Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Are you familiar with Dockerfile? If not, I do recommend reading ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/how-to-write-a-dockerfile/"}),"this article"),".")),Object(r.b)("p",null,"Here we will create our Dockerfiles to build and run our applications. Qovery will handle the build and the run of your applications, but need to have at least a Dockerfile to do it."),Object(r.b)("h3",{id:"choose-your-dockerfile-template"},"Choose your Dockerfile template"),Object(r.b)("p",null,"To get started,"),Object(r.b)("h4",{id:"find-dockerfile-template"},"Find Dockerfile template"),Object(r.b)("p",null,"Pick one Dockerfile template according to the programming language or framework you are using for your app:"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Your framework or language is missing? Open a thread on ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum"),", and we will provide you one.")),Object(r.b)(c.a,{centered:!1,className:"square",defaultValue:"rails",select:!1,size:null,values:[{group:"Files",label:"Rails",value:"rails"},{group:"Files",label:"NodeJS",value:"nodejs"},{group:"Files",label:"React",value:"react"},{group:"Files",label:"VueJS",value:"vuejs"},{group:"Files",label:"NextJS",value:"nextjs"},{group:"Files",label:"Golang",value:"golang"},{group:"Files",label:"Flask",value:"flask"},{group:"Files",label:"Django",value:"django"},{group:"Files",label:"Laravel",value:"laravel"},{group:"Files",label:"Symfony",value:"symfony"},{group:"Files",label:"Spring",value:"spring"},{group:"Files",label:"Rust",value:"rust"}],mdxType:"Tabs"},Object(r.b)(i.a,{value:"rails",mdxType:"TabItem"},Object(r.b)("p",null,"Here is the Dockerfile for your Rails application listening on the PORT 3000"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Dockerfile"',title:'"Dockerfile"'}),'# syntax=docker/dockerfile:1\nFROM ruby:2.7\nRUN apt-get update -qq && apt-get install -y nodejs postgresql-client\nWORKDIR /myapp\nCOPY Gemfile Gemfile\nCOPY Gemfile.lock Gemfile.lock\nRUN bundle install\n\nCOPY . .\n\nEXPOSE 3000\n\n# Configure the main process to run when running the image\nCMD ["rails", "server", "-b", "0.0.0.0", "-p", "3000"]\n')),Object(r.b)("details",null,Object(r.b)("summary",null,"Dockerfile for Sidekiq"),Object(r.b)("p",null,"Here is the Dockerfile for your Rails app running as a worker mode with Sidekiq."),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"There is no listening port since it is consuming resources from a queuing system (E.g. Redis)")),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Dockerfile for Sidekiq"',title:'"Dockerfile',for:!0,'Sidekiq"':!0}),'# syntax=docker/dockerfile:1\nFROM ruby:2.7\nRUN apt-get update -qq && apt-get install -y nodejs postgresql-client # add mysql client if you need to\nWORKDIR /myapp\nCOPY Gemfile Gemfile\nCOPY Gemfile.lock Gemfile.lock\nRUN bundle install\n\nCOPY . .\n\nCMD ["bundle", "exec", "sidekiq"]\n')))),Object(r.b)(i.a,{value:"nodejs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"react",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"vuejs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"nextjs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"golang",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"flask",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"django",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"laravel",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"symfony",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"spring",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"rust",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n")))),Object(r.b)("h4",{id:"copy-template"},"Copy template"),Object(r.b)("p",null,"Copy your Dockerfile at the root of your project. By convention, you can name your file ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile"),". If you already have a Dockerfile, feel free to name it ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile.qovery"),". If you are using multiple Dockerfile for Qovery, feel free to give a name like ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile-sidekiq.qovery"),"."),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Read ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/t/904"}),"this forum post")," to know how to use the same Dockerfile with different CMD parameters.")),Object(r.b)("p",null,"For our example of migrating a Rails app and a Rails Sidekiq app, I will have at the root of my project a ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile.qovery")," and a ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile-sidekiq.qovery"),"."),Object(r.b)("h3",{id:"test-your-dockerfile"},"Test your Dockerfile"),Object(r.b)(b.a,{mdxType:"Assumptions"},Object(r.b)("p",null,"You need to ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.docker.com/get-docker/"}),"install Docker")," to test your Dockerfile")),Object(r.b)("p",null,"To test your Dockerfile we will locally our container. You just need to run the following commands:"),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Don't forget the ",Object(r.b)("inlineCode",{parentName:"p"},".")," (dot) at the end of the ",Object(r.b)("inlineCode",{parentName:"p"},"docker build")," command.")),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"docker build -f Dockerfile.qovery .\n")),Object(r.b)("p",null,"If everything goes well you should get the finale image ID at the end of the output."),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"[+] Building 19.0s (16/16) FINISHED\n => [internal] load build definition from Dockerfile 0.0s\n => => transferring dockerfile: 37B 0.0s\n => [internal] load .dockerignore 0.0s\n ...\n => [7/7] COPY . . 0.2s\n => exporting to image 0.0s\n => exporting layers 0.4s\n => writing image sha256:a0f90a6ec8bc4036a7b268479a0c0773ca324ba2de11fdef31309650743f4055 0.0s\n")),Object(r.b)("p",null,"To run your image you can run:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"docker run a0f90a6ec8bc4036a7b268479a0c0773ca324ba2de11fdef31309650743f4055\n")),Object(r.b)("p",null,"If your app required a database to starts, then it can be normal that it fails to start. Otherwise, if your app is supposed to start and does not, then you will need to fix the issue and rebuild your app with ",Object(r.b)("inlineCode",{parentName:"p"},"docker build -f Dockerfile.qovery .")),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"This step is one of the most complex, but once you successfully build your application with Docker, your app will run anywhere (not only on AWS with Qovery).")),Object(r.b)("p",null,"Any error while building your container image? 2 solutions:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},'Read the error message and try to understand from where the problem is coming from. You can "Google" the error if it is not related to your code.'),Object(r.b)("li",{parentName:"ol"},"Open a thread on ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"https://discuss.qovery.com/"}),"our forum")," if you don't find the answer there, we will be happy to assist you.")),Object(r.b)("h3",{id:"environment-variables-at-the-build-time"},"Environment variables at the build time"),Object(r.b)("p",null,"Does your app use some environment variables at the build time? Then you will need to modify your Dockerfile to includes the environment variables. Let's imagine your app uses the environment variable ",Object(r.b)("inlineCode",{parentName:"p"},"CONTENT_API_KEY"),", then you will need to add the following instructions in your Dockerfile:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Dockerfile with environment variables"',title:'"Dockerfile',with:!0,environment:!0,'variables"':!0}),"...\nARG CONTENT_API_KEY\nENV CONTENT_API_KEY $CONTENT_API_KEY\n...\n")),Object(r.b)("p",null,"The value of the ",Object(r.b)("inlineCode",{parentName:"p"},"CONTENT_API_KEY")," environment variable will be taken from the specified environment variables in Qovery."),Object(r.b)(l.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Qovery injects Environment Variables and Secrets at the build and run time of your app.")),Object(r.b)("h3",{id:"add-your-dockerfile-to-git"},"Add your Dockerfile to Git"),Object(r.b)("p",null,"Now, add your new Dockerfile to git with the following commands:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),'git add Dockerfile.qovery\ngit commit -m "Add Qovery Dockerfile"\ngit push origin\n')),Object(r.b)("h3",{id:"loop"},"Loop"),Object(r.b)("p",null,"If you have multiple applications to deploy, create a Dockerfile for each of them.")),Object(r.b)(i.a,{value:"buildpacks",mdxType:"TabItem"},Object(r.b)("p",null,Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://buildpacks.io/"}),"Buildpacks")," automatically detects the language and the framework your application is using. Buildpacks builds and runs your app. Here is the list of ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#option-1-buildpacks"}),"supported languages and frameworks"),"."),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"We do recommend using Docker to keep the full control of what's going on behind the scene. Buildpacks is a great technology but difficult to debug when something goes wrong. You can try deploying your apps on AWS with Qovery with Buildpacks, if you do not succeed, we do recommend switching for Docker.")),Object(r.b)("h3",{id:"limitations"},"Limitations"),Object(r.b)("p",null,"Here are some limitations due to our Buildpacks implementation:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Qovery Buildpacks does not support Procfile with multiple commands at the moment."),Object(r.b)("li",{parentName:"ul"},"Qovery does not support custom Buildpacks.")),Object(r.b)("p",null,"Those limitations will be solved in the coming months."))),Object(r.b)("h2",{id:"2-create-resources-on-qovery"},"2. Create resources on Qovery"),Object(r.b)("h3",{id:"application"},"Application"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Are you a new Qovery user? Watch ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"this tutorial")," to learn how to deploy your first app.")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/9246ae68c68f42debc3d5183d2b4f7f8",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Steps:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Connect to the ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"https://start.qovery.com"}),"Qovery console"),"."),Object(r.b)("li",{parentName:"ol"},"Create your ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization")," and your ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/project/"}),"Project"),"."),Object(r.b)("li",{parentName:"ol"},"Create an environment with the name ",Object(r.b)("inlineCode",{parentName:"li"},"production")," (it can be changed after)."),Object(r.b)("li",{parentName:"ol"},"Create an application and give it a name (you can give the name of your repo if you have no idea)"),Object(r.b)("li",{parentName:"ol"},"Select your app repository from your GitHub, GitLab or Bitbucket."),Object(r.b)("li",{parentName:"ol"},"Select the branch you want to deploy."),Object(r.b)("li",{parentName:"ol"},"Select the Build mode for ",Object(r.b)("inlineCode",{parentName:"li"},"Buildpacks")," or ",Object(r.b)("inlineCode",{parentName:"li"},"Dockerfile")," according to what you want."),Object(r.b)("li",{parentName:"ol"},"Specify the local listening port of your application."),Object(r.b)("li",{parentName:"ol"},'Click on "create"')),Object(r.b)("p",null,"Congrats! Your application is created \ud83c\udf89"),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,'Your application is created but not deployed yet! You can configure the vCPU, Memory, Environment Variables... before deploying it. If you want to deploy it before finishing the configuration you can click on "Actions" > "Deploy".')),Object(r.b)("p",null,"If you deploy an app from a mono-repository, we have a must-read guide for you ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/advanced/monorepository/"}),"here"),"."),Object(r.b)("h3",{id:"database"},"Database"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Are you a new Qovery user? Watch ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"this tutorial")," to learn how to deploy your database.")),Object(r.b)("p",null,"Here are the steps to deploy your database:"),Object(r.b)(b.a,{mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have created an application before"))),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/d7e10be0e5964f6799b158dc631bbbd1",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Steps:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Go to your ",Object(r.b)("inlineCode",{parentName:"li"},"production")," environment."),Object(r.b)("li",{parentName:"ol"},'Add your database by clicking on "Add" > "Database".'),Object(r.b)("li",{parentName:"ol"},"Select the database (PostgreSQL, MySQL, MongoDB, Redis..) and the version you want to deploy."),Object(r.b)("li",{parentName:"ol"},"Select ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/database/#general"}),"Managed or Container mode")," for your database."),Object(r.b)("li",{parentName:"ol"},"Select ",Object(r.b)("inlineCode",{parentName:"li"},"Public")," accessibility (set ",Object(r.b)("inlineCode",{parentName:"li"},"Private")," if you don't want to restore your data from an existing Heroku database).")),Object(r.b)("p",null,"Congrats! Your database is created as well \ud83c\udf89"),Object(r.b)("p",null,"If you use MongoDB Atlas, or an existing database on AWS that you want to connect to your application deployed by Qovery. Check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"our tutorial about VPC peering")," and how to securely connect to your existing database."),Object(r.b)("h2",{id:"3-configure-your-environment-variables-and-secrets"},"3. Configure your Environment Variables and Secrets"),Object(r.b)(l.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Qovery supports Doppler integration - it's the easiest way to migrate your Environment Variables and Secrets from Heroku to Qovery. ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/secret-manager/doppler/"}),"More info here"),".")),Object(r.b)("p",null,"Qovery makes the difference between an environment variable and a secret. Basically, a Secret is similar to an Environment Variable but the value is encrypted and can't be revealed. Both are injected as environment variables during the build and the run of your applications. ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"More info here")),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"I recommend reading our ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/managing-environment-variables/"}),"Getting Started with Environment Variables")," guide.")),Object(r.b)("p",null,"To extract your environment variables from Heroku, we recommend using the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://devcenter.heroku.com/articles/heroku-cli"}),"Heroku CLI")," and exporting all the environment variables and secrets in an .env (dot env) file. Qovery supports the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli/"}),"import of a dot env file")," via the Qovery web interface and the Qovery CLI."),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"If you use Buildpacks for one of your app AND you have indicated a local listening port of your application, you will need to add an environment variable ",Object(r.b)("inlineCode",{parentName:"p"},"PORT")," with the value of your port to make your application starting properly. Otherwise, Qovery will fail to deploy your app!")),Object(r.b)("p",null,Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://devcenter.heroku.com/articles/config-vars#view-current-config-var-values"}),"Export your environment variable via the Heroku CLI")," with the command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"# To install Heroku CLI: https://devcenter.heroku.com/articles/heroku-cli\nheroku config\n\nGREETINGS: hello world\nSTRIPE_API_KEY: xxx-yyy-zzz\nIS_PRODUCTION: true\n")),Object(r.b)("p",null,"Then you can create your environment variables via the web interface (watch the video below)"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/50899d7fa3d84a418f0db69f54f970d3",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Or via the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI"),":"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Import Heroku environment variables with the Qovery CLI"',title:'"Import',Heroku:!0,environment:!0,variables:!0,with:!0,the:!0,Qovery:!0,'CLI"':!0}),"# auth yourself\nqovery auth\n\n# selection the app where you want to import your environment variables\nqovery context set\n\n# import your Heroku environment variables\nheroku config --app --json | \\\n qovery env parse --heroku-json > heroku.env && \\\n qovery env import heroku.env && \\\n rm heroku.env\n\nQovery: dot env file to import: 'heroku.env'\n? Do you want to import Environment Variables or Secrets? Environment Variables\n? What environment variables do you want to import? [Use arrows to move, space to select, to all, to none, type to filter]\n [x] GREETINGS=hello world\n [ ] STRIPE_API_KEY=xxx-yyy-zzz\n> [x] IS_PRODUCTION=true\n\nQovery: \u2705 Environment Variables successfully imported!\n")),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Import sensitive data (E.g. API keys, credentials...) as ",Object(r.b)("inlineCode",{parentName:"p"},"Secret")," and not ",Object(r.b)("inlineCode",{parentName:"p"},"Environment Variable"),".")),Object(r.b)("h3",{id:"connect-your-frontend-app-to-your-backend-app"},"Connect your frontend app to your backend app"),Object(r.b)("p",null,"To connect your frontend app your backend app we will create an ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#alias-environment-variable"}),"environment variable alias"),"."),Object(r.b)("p",null,"Here is how to create a frontend app:"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/bafbbda93bd64d04afb3189bf4a1a201",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"And now how to connect your frontend app with your backend app:"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/f820925f2175465f9271b97ef414bb42",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"You can also take a look at ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/t/918"}),"this forum reply")," to learn how to do it."),Object(r.b)("h3",{id:"connect-your-backend-app-to-your-database"},"Connect your backend app to your database"),Object(r.b)("p",null,"Same as connecting your frontend app to your backend app, you can create an environment variable alias ",Object(r.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," for the ",Object(r.b)("em",{parentName:"p"},"built-in")," secret finishing with ",Object(r.b)("inlineCode",{parentName:"p"},"_DATABASE_URL_INTERNAL"),"."),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Create an alias on ",Object(r.b)("inlineCode",{parentName:"p"},"_DATABASE_URL_INTERNAL")," and not ",Object(r.b)("inlineCode",{parentName:"p"},"_DATABASE_URL"))),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/59f8368eb3c14796a807c7e39e9c0ab0",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"4-copy-data-from-your-heroku-databases-to-your-aws-databases"},"4. Copy data from your Heroku databases to your AWS databases"),Object(r.b)("p",null,Object(r.b)("em",{parentName:"p"},"Coming soon with ",Object(r.b)("a",Object(o.a)({parentName:"em"},{href:"https://www.replibyte.com"}),"Replibyte"))),Object(r.b)("h2",{id:"5-deploy-your-apps"},"5. Deploy your apps!"),Object(r.b)("p",null,"We are finally ready to deploy my applications on AWS!"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/0589d2f2aa4149edb605dc23f4efd23d",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Watch the final result \ud83d\ude0e"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/da31c21f9c104eae9270e4c4db59055e",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"faq-by-heroku-users"},"FAQ by Heroku users"),Object(r.b)("h3",{id:"how-to-create-a-custom-domain"},"How to create a custom domain?"),Object(r.b)("p",null,"Check out the documentation on ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/setting-custom-domain/"}),"how to configure your custom domain"),"."),Object(r.b)("h3",{id:"how-to-monitor-my-apps"},"How to monitor my apps?"),Object(r.b)("p",null,"We do recommend using ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://www.datadoghq.com"}),"Datadog")," or any other monitoring products for monitoring your apps deployed by Qovery. Check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/"}),"our tutorial on how to install Datadog"),"."),Object(r.b)("h3",{id:"do-you-have-heroku-review-app-equivalent"},'Do you have Heroku "Review App" equivalent?'),Object(r.b)("p",null,"Yes, it's what we call ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#preview-environment"}),"Preview Environment")),Object(r.b)("h3",{id:"how-to-rollback"},"How to rollback?"),Object(r.b)("p",null,"Check out the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deployment-actions/#deploy-other-version"}),"app rollback documentation")),Object(r.b)("h3",{id:"how-auto-scaling-works"},"How auto-scaling works?"),Object(r.b)("p",null,"Check out the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#auto-scaling"}),"app auto-scaling documentation")),Object(r.b)("h3",{id:"how-to-manage-database-migration"},"How to manage database migration?"),Object(r.b)("p",null,"Check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/t/951"}),"our forum reply")),Object(r.b)("h3",{id:"is-it-possible-to-get-a-shell--connect-to-my-app"},"Is it possible to get a shell / connect to my app?"),Object(r.b)("p",null,"Yes, with the Qovery CLI and the command ",Object(r.b)("inlineCode",{parentName:"p"},"qovery shell"),". ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#shell"}),"Check out the documentation"),"."),Object(r.b)("h3",{id:"can-i-use-terraform-and-infrastructure-as-code"},"Can I use Terraform and Infrastructure as Code?"),Object(r.b)("p",null,"Absolutely, we have a ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"Qovery Terraform provider")," available."),Object(r.b)("h3",{id:"how-can-i-connect-my-app-to-mongodb-atlas"},"How can I connect my app to MongoDB Atlas?"),Object(r.b)("p",null,"If you use MongoDB Atlas check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"our tutorial about VPC peering")," and how to securely connect to your existing MongoDB Atlas database."),Object(r.b)("h3",{id:"how-can-i-connect-my-app-to-an-aws-service-not-managed-by-qovery"},"How can I connect my app to an AWS service not managed by Qovery?"),Object(r.b)("p",null,"If you want to connect your app to an AWS service not managed by Qovery, check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"our tutorial about VPC peering")," and how to securely connect to this AWS service."),Object(r.b)("hr",null),Object(r.b)("p",null,"If you have a common question about Qovery, we have a more general ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/useful-resources/faq/"}),"FAQ section")," available."),Object(r.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(r.b)("p",null,"Congrats! You have migrated from Heroku to AWS. Feel free to check out our ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"forum")," and open a thread if you have any question."))}m.isMDXComponent=!0},421:function(e,t,a){"use strict";a(423);var o=a(0),n=a.n(o),r=a(420),l=a.n(r);a(132);t.a=function(e){var t=e.children,a=e.classNames,o=e.fill,r=e.icon,i=e.type,c=null;switch(i){case"danger":c="alert-triangle";break;case"success":c="check-circle";break;case"warning":c="alert-triangle";break;default:c="info"}return n.a.createElement("div",{className:l()(a,"alert","alert--"+i,{"alert--fill":o,"alert--icon":!1!==r}),role:"alert"},!1!==r&&n.a.createElement("i",{className:l()("feather","icon-"+(r||c))}),t)}},425:function(e,t,a){var o=a(28).f,n=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in n||a(10)&&o(n,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var o=a(0),n=a.n(o),r=a(421);t.a=function(e){var t=e.children,a=e.name;return n.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},434:function(e,t,a){"use strict";var o=a(1),n=(a(439),a(436),a(52),a(29),a(22),a(21),a(0)),r=a.n(n),l=a(446),i=a(420),c=a.n(i),b=a(428),u=a.n(b),s=a(445),p=37,d=39;function m(e){var t=e.block,a=e.centered,o=e.changeSelectedValue,n=e.className,l=e.handleKeydown,i=e.style,b=e.values,u=e.selectedValue,s=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:c()("tabs",n,{"tabs--block":t}),style:i},b.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":u===t,className:c()("tab-item",{"tab-item--active":u===t}),key:t,ref:function(e){return s.push(e)},onKeyDown:function(e){return l(s,e.target,e)},onFocus:function(){return o(t)},onClick:function(){return o(t)}},a)}))))}function h(e){var t=e.placeholder,a=e.selectedValue,o=e.changeSelectedValue,n=e.size,i=e.values,c=i;if(c[0].group){var b=_.groupBy(c,"group");c=Object.keys(b).map((function(e){return{label:e,options:b[e]}}))}return r.a.createElement(l.a,{className:"react-select-container react-select--"+n,classNamePrefix:"react-select",options:c,isClearable:a,placeholder:t,value:i.find((function(e){return e.value==a})),onChange:function(e){return o(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,a=e.defaultValue,l=e.groupId,i=e.label,c=e.placeholder,b=e.select,y=e.size,f=(e.style,e.values),O=e.urlKey,j=Object(s.a)(),g=j.tabGroupChoices,v=j.setTabGroupChoices,w=Object(n.useState)(a),k=w[0],N=w[1];if(null!=l){var T=g[l];null!=T&&T!==k&&N(T)}var C=function(e){N(e),null!=l&&v(l,e)},D=[],A=function(e,t,a){switch(a.keyCode){case d:!function(e,t){var a=e.indexOf(t)+1;e[a]?e[a].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var a=e.indexOf(t)-1;e[a]?e[a].focus():e[e.length-1].focus()}(e,t)}};return Object(n.useEffect)((function(){if("undefined"!=typeof window&&window.location&&O){var e=u.a.parse(window.location.search);e[O]&&N(e[O])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(y||"md")},i&&r.a.createElement("div",{className:"margin-vert--sm"},i),f.length>1&&(b?r.a.createElement(h,Object(o.a)({changeSelectedValue:C,handleKeydown:A,placeholder:c,selectedValue:k,size:y,tabRefs:D},e)):r.a.createElement(m,Object(o.a)({changeSelectedValue:C,handleKeydown:A,selectedValue:k,tabRefs:D},e)))),n.Children.toArray(t).filter((function(e){return e.props.value===k}))[0])}},441:function(e,t,a){"use strict";var o=a(0),n=a.n(o);t.a=function(e){return n.a.createElement(n.a.Fragment,null,e.children)}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{156:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return u})),a.d(t,"metadata",(function(){return s})),a.d(t,"rightToc",(function(){return p})),a.d(t,"default",(function(){return m}));var o=a(1),n=a(9),r=(a(0),a(425)),l=a(424),i=a(444),c=a(437),b=a(429),u={last_modified_on:"2023-05-29",$schema:"/.meta/.schemas/guides.json",title:"Migrate your application from Heroku to AWS",description:"Guide on how to migrate all your applications from Heroku to AWS with your databases",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Migrate your application from Heroku to AWS",description:"Guide on how to migrate all your applications from Heroku to AWS with your databases",permalink:"/guides/tutorial/migrate-your-application-from-heroku-to-aws",readingTime:"13 min read",source:"@site/guides/tutorial/migrate-your-application-from-heroku-to-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Migrate your application from Heroku to AWS",truncated:!1,prevItem:{title:"Microservices",permalink:"/guides/advanced/microservices"},nextItem:{title:"Migration",permalink:"/guides/advanced/migration"}},p=[{value:"Migration Steps",id:"migration-steps",children:[]},{value:"1. Create your Dockerfile or Use Buildpacks",id:"1-create-your-dockerfile-or-use-buildpacks",children:[{value:"Choose your Dockerfile template",id:"choose-your-dockerfile-template",children:[]},{value:"Test your Dockerfile",id:"test-your-dockerfile",children:[]},{value:"Environment variables at the build time",id:"environment-variables-at-the-build-time",children:[]},{value:"Add your Dockerfile to Git",id:"add-your-dockerfile-to-git",children:[]},{value:"Loop",id:"loop",children:[]},{value:"Limitations",id:"limitations",children:[]}]},{value:"2. Create resources on Qovery",id:"2-create-resources-on-qovery",children:[{value:"Application",id:"application",children:[]},{value:"Database",id:"database",children:[]}]},{value:"3. Configure your Environment Variables and Secrets",id:"3-configure-your-environment-variables-and-secrets",children:[{value:"Connect your frontend app to your backend app",id:"connect-your-frontend-app-to-your-backend-app",children:[]},{value:"Connect your backend app to your database",id:"connect-your-backend-app-to-your-database",children:[]}]},{value:"4. Copy data from your Heroku databases to your AWS databases",id:"4-copy-data-from-your-heroku-databases-to-your-aws-databases",children:[]},{value:"5. Deploy your apps!",id:"5-deploy-your-apps",children:[]},{value:"FAQ by Heroku users",id:"faq-by-heroku-users",children:[{value:"How to create a custom domain?",id:"how-to-create-a-custom-domain",children:[]},{value:"How to monitor my apps?",id:"how-to-monitor-my-apps",children:[]},{value:"Do you have Heroku "Review App" equivalent?",id:"do-you-have-heroku-review-app-equivalent",children:[]},{value:"How to rollback?",id:"how-to-rollback",children:[]},{value:"How auto-scaling works?",id:"how-auto-scaling-works",children:[]},{value:"How to manage database migration?",id:"how-to-manage-database-migration",children:[]},{value:"Is it possible to get a shell / connect to my app?",id:"is-it-possible-to-get-a-shell--connect-to-my-app",children:[]},{value:"Can I use Terraform and Infrastructure as Code?",id:"can-i-use-terraform-and-infrastructure-as-code",children:[]},{value:"How can I connect my app to MongoDB Atlas?",id:"how-can-i-connect-my-app-to-mongodb-atlas",children:[]},{value:"How can I connect my app to an AWS service not managed by Qovery?",id:"how-can-i-connect-my-app-to-an-aws-service-not-managed-by-qovery",children:[]}]},{value:"Wrapping up",id:"wrapping-up",children:[]}],d={rightToc:p};function m(e){var t=e.components,a=Object(n.a)(e,["components"]);return Object(r.b)("wrapper",Object(o.a)({},d,a,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"This guide describes how to migrate your application running on Heroku to AWS with Qovery. It covers all required steps you need to take to deploy your application on AWS and transfer your data from Heroku Postgres to the database managed by AWS via Qovery."),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Please contact us via ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum")," if you experience any problem while migrating from Heroku to AWS with Qovery.")),Object(r.b)(b.a,{name:"guide",mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You are familiar with Heroku basics, have a Heroku account and access to Heroku CLI"),Object(r.b)("li",{parentName:"ul"},"You have ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"https://start.qovery.com"}),"sign in on Qovery")),Object(r.b)("li",{parentName:"ul"},"You have ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/cloud-provider/guide-amazon-web-services/"}),"set up your AWS account")," with Qovery"))),Object(r.b)("h2",{id:"migration-steps"},"Migration Steps"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#1-create-your-dockerfile-or-use-buildpacks"}),"Use Buildpacks or Create your Dockerfile")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#2-create-resources-on-qovery"}),"Create resources on Qovery")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#3-configure-your-environment-variables-and-secrets"}),"Configure Environment Variables and Secrets")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#4-copy-data-from-your-heroku-databases-to-your-aws-databases"}),"Copy data from your Heroku databases to your AWS databases")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#5-deploy-your-apps-"}),"Deploy your apps")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#faq-by-heroku-users"}),"FAQ by Heroku users"))),Object(r.b)("h2",{id:"1-create-your-dockerfile-or-use-buildpacks"},"1. Create your Dockerfile or Use Buildpacks"),Object(r.b)("p",null,"Qovery supports two ways to build and run your application coming from Heroku:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Buildpacks"),Object(r.b)("li",{parentName:"ol"},"Docker")),Object(r.b)("p",null,"Both options build a container image that is runnable by a container engine (E.g. Docker). Qovery runs containers on Kubernetes."),Object(r.b)("p",null,"Choose the option that better fits you:"),Object(r.b)(c.a,{centered:!0,className:"rounded",defaultValue:"buildpacks",placeholder:"Use Buildpacks or Create your Dockerfile",select:!1,size:null,values:[{group:"Platforms",label:"Use Buildpacks",value:"buildpacks"},{group:"Platforms",label:"Create your Dockerfile",value:"dockerfile"}],mdxType:"Tabs"},Object(r.b)(i.a,{value:"dockerfile",mdxType:"TabItem"},Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Are you familiar with Dockerfile? If not, I do recommend reading ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/how-to-write-a-dockerfile/"}),"this article"),".")),Object(r.b)("p",null,"Here we will create our Dockerfiles to build and run our applications. Qovery will handle the build and the run of your applications, but need to have at least a Dockerfile to do it."),Object(r.b)("h3",{id:"choose-your-dockerfile-template"},"Choose your Dockerfile template"),Object(r.b)("p",null,"To get started,"),Object(r.b)("h4",{id:"find-dockerfile-template"},"Find Dockerfile template"),Object(r.b)("p",null,"Pick one Dockerfile template according to the programming language or framework you are using for your app:"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Your framework or language is missing? Open a thread on ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum"),", and we will provide you one.")),Object(r.b)(c.a,{centered:!1,className:"square",defaultValue:"rails",select:!1,size:null,values:[{group:"Files",label:"Rails",value:"rails"},{group:"Files",label:"NodeJS",value:"nodejs"},{group:"Files",label:"React",value:"react"},{group:"Files",label:"VueJS",value:"vuejs"},{group:"Files",label:"NextJS",value:"nextjs"},{group:"Files",label:"Golang",value:"golang"},{group:"Files",label:"Flask",value:"flask"},{group:"Files",label:"Django",value:"django"},{group:"Files",label:"Laravel",value:"laravel"},{group:"Files",label:"Symfony",value:"symfony"},{group:"Files",label:"Spring",value:"spring"},{group:"Files",label:"Rust",value:"rust"}],mdxType:"Tabs"},Object(r.b)(i.a,{value:"rails",mdxType:"TabItem"},Object(r.b)("p",null,"Here is the Dockerfile for your Rails application listening on the PORT 3000"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Dockerfile"',title:'"Dockerfile"'}),'# syntax=docker/dockerfile:1\nFROM ruby:2.7\nRUN apt-get update -qq && apt-get install -y nodejs postgresql-client\nWORKDIR /myapp\nCOPY Gemfile Gemfile\nCOPY Gemfile.lock Gemfile.lock\nRUN bundle install\n\nCOPY . .\n\nEXPOSE 3000\n\n# Configure the main process to run when running the image\nCMD ["rails", "server", "-b", "0.0.0.0", "-p", "3000"]\n')),Object(r.b)("details",null,Object(r.b)("summary",null,"Dockerfile for Sidekiq"),Object(r.b)("p",null,"Here is the Dockerfile for your Rails app running as a worker mode with Sidekiq."),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"There is no listening port since it is consuming resources from a queuing system (E.g. Redis)")),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Dockerfile for Sidekiq"',title:'"Dockerfile',for:!0,'Sidekiq"':!0}),'# syntax=docker/dockerfile:1\nFROM ruby:2.7\nRUN apt-get update -qq && apt-get install -y nodejs postgresql-client # add mysql client if you need to\nWORKDIR /myapp\nCOPY Gemfile Gemfile\nCOPY Gemfile.lock Gemfile.lock\nRUN bundle install\n\nCOPY . .\n\nCMD ["bundle", "exec", "sidekiq"]\n')))),Object(r.b)(i.a,{value:"nodejs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"react",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"vuejs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"nextjs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"golang",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"flask",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"django",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"laravel",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"symfony",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"spring",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"rust",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n")))),Object(r.b)("h4",{id:"copy-template"},"Copy template"),Object(r.b)("p",null,"Copy your Dockerfile at the root of your project. By convention, you can name your file ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile"),". If you already have a Dockerfile, feel free to name it ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile.qovery"),". If you are using multiple Dockerfile for Qovery, feel free to give a name like ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile-sidekiq.qovery"),"."),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Read ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/t/904"}),"this forum post")," to know how to use the same Dockerfile with different CMD parameters.")),Object(r.b)("p",null,"For our example of migrating a Rails app and a Rails Sidekiq app, I will have at the root of my project a ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile.qovery")," and a ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile-sidekiq.qovery"),"."),Object(r.b)("h3",{id:"test-your-dockerfile"},"Test your Dockerfile"),Object(r.b)(b.a,{mdxType:"Assumptions"},Object(r.b)("p",null,"You need to ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.docker.com/get-docker/"}),"install Docker")," to test your Dockerfile")),Object(r.b)("p",null,"To test your Dockerfile we will locally our container. You just need to run the following commands:"),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Don't forget the ",Object(r.b)("inlineCode",{parentName:"p"},".")," (dot) at the end of the ",Object(r.b)("inlineCode",{parentName:"p"},"docker build")," command.")),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"docker build -f Dockerfile.qovery .\n")),Object(r.b)("p",null,"If everything goes well you should get the finale image ID at the end of the output."),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"[+] Building 19.0s (16/16) FINISHED\n => [internal] load build definition from Dockerfile 0.0s\n => => transferring dockerfile: 37B 0.0s\n => [internal] load .dockerignore 0.0s\n ...\n => [7/7] COPY . . 0.2s\n => exporting to image 0.0s\n => exporting layers 0.4s\n => writing image sha256:a0f90a6ec8bc4036a7b268479a0c0773ca324ba2de11fdef31309650743f4055 0.0s\n")),Object(r.b)("p",null,"To run your image you can run:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"docker run a0f90a6ec8bc4036a7b268479a0c0773ca324ba2de11fdef31309650743f4055\n")),Object(r.b)("p",null,"If your app required a database to starts, then it can be normal that it fails to start. Otherwise, if your app is supposed to start and does not, then you will need to fix the issue and rebuild your app with ",Object(r.b)("inlineCode",{parentName:"p"},"docker build -f Dockerfile.qovery .")),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"This step is one of the most complex, but once you successfully build your application with Docker, your app will run anywhere (not only on AWS with Qovery).")),Object(r.b)("p",null,"Any error while building your container image? 2 solutions:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},'Read the error message and try to understand from where the problem is coming from. You can "Google" the error if it is not related to your code.'),Object(r.b)("li",{parentName:"ol"},"Open a thread on ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"https://discuss.qovery.com/"}),"our forum")," if you don't find the answer there, we will be happy to assist you.")),Object(r.b)("h3",{id:"environment-variables-at-the-build-time"},"Environment variables at the build time"),Object(r.b)("p",null,"Does your app use some environment variables at the build time? Then you will need to modify your Dockerfile to includes the environment variables. Let's imagine your app uses the environment variable ",Object(r.b)("inlineCode",{parentName:"p"},"CONTENT_API_KEY"),", then you will need to add the following instructions in your Dockerfile:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Dockerfile with environment variables"',title:'"Dockerfile',with:!0,environment:!0,'variables"':!0}),"...\nARG CONTENT_API_KEY\nENV CONTENT_API_KEY $CONTENT_API_KEY\n...\n")),Object(r.b)("p",null,"The value of the ",Object(r.b)("inlineCode",{parentName:"p"},"CONTENT_API_KEY")," environment variable will be taken from the specified environment variables in Qovery."),Object(r.b)(l.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Qovery injects Environment Variables and Secrets at the build and run time of your app.")),Object(r.b)("h3",{id:"add-your-dockerfile-to-git"},"Add your Dockerfile to Git"),Object(r.b)("p",null,"Now, add your new Dockerfile to git with the following commands:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),'git add Dockerfile.qovery\ngit commit -m "Add Qovery Dockerfile"\ngit push origin\n')),Object(r.b)("h3",{id:"loop"},"Loop"),Object(r.b)("p",null,"If you have multiple applications to deploy, create a Dockerfile for each of them.")),Object(r.b)(i.a,{value:"buildpacks",mdxType:"TabItem"},Object(r.b)("p",null,Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://buildpacks.io/"}),"Buildpacks")," automatically detects the language and the framework your application is using. Buildpacks builds and runs your app. Here is the list of ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#option-1-buildpacks"}),"supported languages and frameworks"),"."),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"We do recommend using Docker to keep the full control of what's going on behind the scene. Buildpacks is a great technology but difficult to debug when something goes wrong. You can try deploying your apps on AWS with Qovery with Buildpacks, if you do not succeed, we do recommend switching for Docker.")),Object(r.b)("h3",{id:"limitations"},"Limitations"),Object(r.b)("p",null,"Here are some limitations due to our Buildpacks implementation:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Qovery Buildpacks does not support Procfile with multiple commands at the moment."),Object(r.b)("li",{parentName:"ul"},"Qovery does not support custom Buildpacks.")),Object(r.b)("p",null,"Those limitations will be solved in the coming months."))),Object(r.b)("h2",{id:"2-create-resources-on-qovery"},"2. Create resources on Qovery"),Object(r.b)("h3",{id:"application"},"Application"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Are you a new Qovery user? Watch ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"this tutorial")," to learn how to deploy your first app.")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/9246ae68c68f42debc3d5183d2b4f7f8",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Steps:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Connect to the ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"https://start.qovery.com"}),"Qovery console"),"."),Object(r.b)("li",{parentName:"ol"},"Create your ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization")," and your ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/project/"}),"Project"),"."),Object(r.b)("li",{parentName:"ol"},"Create an environment with the name ",Object(r.b)("inlineCode",{parentName:"li"},"production")," (it can be changed after)."),Object(r.b)("li",{parentName:"ol"},"Create an application and give it a name (you can give the name of your repo if you have no idea)"),Object(r.b)("li",{parentName:"ol"},"Select your app repository from your GitHub, GitLab or Bitbucket."),Object(r.b)("li",{parentName:"ol"},"Select the branch you want to deploy."),Object(r.b)("li",{parentName:"ol"},"Select the Build mode for ",Object(r.b)("inlineCode",{parentName:"li"},"Buildpacks")," or ",Object(r.b)("inlineCode",{parentName:"li"},"Dockerfile")," according to what you want."),Object(r.b)("li",{parentName:"ol"},"Specify the local listening port of your application."),Object(r.b)("li",{parentName:"ol"},'Click on "create"')),Object(r.b)("p",null,"Congrats! Your application is created \ud83c\udf89"),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,'Your application is created but not deployed yet! You can configure the vCPU, Memory, Environment Variables... before deploying it. If you want to deploy it before finishing the configuration you can click on "Actions" > "Deploy".')),Object(r.b)("p",null,"If you deploy an app from a mono-repository, we have a must-read guide for you ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/advanced/monorepository/"}),"here"),"."),Object(r.b)("h3",{id:"database"},"Database"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Are you a new Qovery user? Watch ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"this tutorial")," to learn how to deploy your database.")),Object(r.b)("p",null,"Here are the steps to deploy your database:"),Object(r.b)(b.a,{mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have created an application before"))),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/d7e10be0e5964f6799b158dc631bbbd1",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Steps:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Go to your ",Object(r.b)("inlineCode",{parentName:"li"},"production")," environment."),Object(r.b)("li",{parentName:"ol"},'Add your database by clicking on "Add" > "Database".'),Object(r.b)("li",{parentName:"ol"},"Select the database (PostgreSQL, MySQL, MongoDB, Redis..) and the version you want to deploy."),Object(r.b)("li",{parentName:"ol"},"Select ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/database/#general"}),"Managed or Container mode")," for your database."),Object(r.b)("li",{parentName:"ol"},"Select ",Object(r.b)("inlineCode",{parentName:"li"},"Public")," accessibility (set ",Object(r.b)("inlineCode",{parentName:"li"},"Private")," if you don't want to restore your data from an existing Heroku database).")),Object(r.b)("p",null,"Congrats! Your database is created as well \ud83c\udf89"),Object(r.b)("p",null,"If you use MongoDB Atlas, or an existing database on AWS that you want to connect to your application deployed by Qovery. Check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"our tutorial about VPC peering")," and how to securely connect to your existing database."),Object(r.b)("h2",{id:"3-configure-your-environment-variables-and-secrets"},"3. Configure your Environment Variables and Secrets"),Object(r.b)(l.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Qovery supports Doppler integration - it's the easiest way to migrate your Environment Variables and Secrets from Heroku to Qovery. ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/secret-manager/doppler/"}),"More info here"),".")),Object(r.b)("p",null,"Qovery makes the difference between an environment variable and a secret. Basically, a Secret is similar to an Environment Variable but the value is encrypted and can't be revealed. Both are injected as environment variables during the build and the run of your applications. ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"More info here")),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"I recommend reading our ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/managing-environment-variables/"}),"Getting Started with Environment Variables")," guide.")),Object(r.b)("p",null,"To extract your environment variables from Heroku, we recommend using the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://devcenter.heroku.com/articles/heroku-cli"}),"Heroku CLI")," and exporting all the environment variables and secrets in an .env (dot env) file. Qovery supports the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli/"}),"import of a dot env file")," via the Qovery web interface and the Qovery CLI."),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"If you use Buildpacks for one of your app AND you have indicated a local listening port of your application, you will need to add an environment variable ",Object(r.b)("inlineCode",{parentName:"p"},"PORT")," with the value of your port to make your application starting properly. Otherwise, Qovery will fail to deploy your app!")),Object(r.b)("p",null,Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://devcenter.heroku.com/articles/config-vars#view-current-config-var-values"}),"Export your environment variable via the Heroku CLI")," with the command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"# To install Heroku CLI: https://devcenter.heroku.com/articles/heroku-cli\nheroku config\n\nGREETINGS: hello world\nSTRIPE_API_KEY: xxx-yyy-zzz\nIS_PRODUCTION: true\n")),Object(r.b)("p",null,"Then you can create your environment variables via the web interface (watch the video below)"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/50899d7fa3d84a418f0db69f54f970d3",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Or via the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI"),":"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Import Heroku environment variables with the Qovery CLI"',title:'"Import',Heroku:!0,environment:!0,variables:!0,with:!0,the:!0,Qovery:!0,'CLI"':!0}),"# auth yourself\nqovery auth\n\n# selection the app where you want to import your environment variables\nqovery context set\n\n# import your Heroku environment variables\nheroku config --app --json | \\\n qovery env parse --heroku-json > heroku.env && \\\n qovery env import heroku.env && \\\n rm heroku.env\n\nQovery: dot env file to import: 'heroku.env'\n? Do you want to import Environment Variables or Secrets? Environment Variables\n? What environment variables do you want to import? [Use arrows to move, space to select, to all, to none, type to filter]\n [x] GREETINGS=hello world\n [ ] STRIPE_API_KEY=xxx-yyy-zzz\n> [x] IS_PRODUCTION=true\n\nQovery: \u2705 Environment Variables successfully imported!\n")),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Import sensitive data (E.g. API keys, credentials...) as ",Object(r.b)("inlineCode",{parentName:"p"},"Secret")," and not ",Object(r.b)("inlineCode",{parentName:"p"},"Environment Variable"),".")),Object(r.b)("h3",{id:"connect-your-frontend-app-to-your-backend-app"},"Connect your frontend app to your backend app"),Object(r.b)("p",null,"To connect your frontend app your backend app we will create an ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#alias-environment-variable"}),"environment variable alias"),"."),Object(r.b)("p",null,"Here is how to create a frontend app:"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/bafbbda93bd64d04afb3189bf4a1a201",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"And now how to connect your frontend app with your backend app:"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/f820925f2175465f9271b97ef414bb42",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"You can also take a look at ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/t/918"}),"this forum reply")," to learn how to do it."),Object(r.b)("h3",{id:"connect-your-backend-app-to-your-database"},"Connect your backend app to your database"),Object(r.b)("p",null,"Same as connecting your frontend app to your backend app, you can create an environment variable alias ",Object(r.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," for the ",Object(r.b)("em",{parentName:"p"},"built-in")," secret finishing with ",Object(r.b)("inlineCode",{parentName:"p"},"_DATABASE_URL_INTERNAL"),"."),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Create an alias on ",Object(r.b)("inlineCode",{parentName:"p"},"_DATABASE_URL_INTERNAL")," and not ",Object(r.b)("inlineCode",{parentName:"p"},"_DATABASE_URL"))),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/59f8368eb3c14796a807c7e39e9c0ab0",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"4-copy-data-from-your-heroku-databases-to-your-aws-databases"},"4. Copy data from your Heroku databases to your AWS databases"),Object(r.b)("p",null,Object(r.b)("em",{parentName:"p"},"Coming soon with ",Object(r.b)("a",Object(o.a)({parentName:"em"},{href:"https://www.replibyte.com"}),"Replibyte"))),Object(r.b)("h2",{id:"5-deploy-your-apps"},"5. Deploy your apps!"),Object(r.b)("p",null,"We are finally ready to deploy my applications on AWS!"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/0589d2f2aa4149edb605dc23f4efd23d",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Watch the final result \ud83d\ude0e"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/da31c21f9c104eae9270e4c4db59055e",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"faq-by-heroku-users"},"FAQ by Heroku users"),Object(r.b)("h3",{id:"how-to-create-a-custom-domain"},"How to create a custom domain?"),Object(r.b)("p",null,"Check out the documentation on ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/setting-custom-domain/"}),"how to configure your custom domain"),"."),Object(r.b)("h3",{id:"how-to-monitor-my-apps"},"How to monitor my apps?"),Object(r.b)("p",null,"We do recommend using ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://www.datadoghq.com"}),"Datadog")," or any other monitoring products for monitoring your apps deployed by Qovery. Check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/"}),"our tutorial on how to install Datadog"),"."),Object(r.b)("h3",{id:"do-you-have-heroku-review-app-equivalent"},'Do you have Heroku "Review App" equivalent?'),Object(r.b)("p",null,"Yes, it's what we call ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#preview-environment"}),"Preview Environment")),Object(r.b)("h3",{id:"how-to-rollback"},"How to rollback?"),Object(r.b)("p",null,"Check out the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deployment-actions/#deploy-other-version"}),"app rollback documentation")),Object(r.b)("h3",{id:"how-auto-scaling-works"},"How auto-scaling works?"),Object(r.b)("p",null,"Check out the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#auto-scaling"}),"app auto-scaling documentation")),Object(r.b)("h3",{id:"how-to-manage-database-migration"},"How to manage database migration?"),Object(r.b)("p",null,"Check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/t/951"}),"our forum reply")),Object(r.b)("h3",{id:"is-it-possible-to-get-a-shell--connect-to-my-app"},"Is it possible to get a shell / connect to my app?"),Object(r.b)("p",null,"Yes, with the Qovery CLI and the command ",Object(r.b)("inlineCode",{parentName:"p"},"qovery shell"),". ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#shell"}),"Check out the documentation"),"."),Object(r.b)("h3",{id:"can-i-use-terraform-and-infrastructure-as-code"},"Can I use Terraform and Infrastructure as Code?"),Object(r.b)("p",null,"Absolutely, we have a ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"Qovery Terraform provider")," available."),Object(r.b)("h3",{id:"how-can-i-connect-my-app-to-mongodb-atlas"},"How can I connect my app to MongoDB Atlas?"),Object(r.b)("p",null,"If you use MongoDB Atlas check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"our tutorial about VPC peering")," and how to securely connect to your existing MongoDB Atlas database."),Object(r.b)("h3",{id:"how-can-i-connect-my-app-to-an-aws-service-not-managed-by-qovery"},"How can I connect my app to an AWS service not managed by Qovery?"),Object(r.b)("p",null,"If you want to connect your app to an AWS service not managed by Qovery, check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"our tutorial about VPC peering")," and how to securely connect to this AWS service."),Object(r.b)("hr",null),Object(r.b)("p",null,"If you have a common question about Qovery, we have a more general ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/useful-resources/faq/"}),"FAQ section")," available."),Object(r.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(r.b)("p",null,"Congrats! You have migrated from Heroku to AWS. Feel free to check out our ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"forum")," and open a thread if you have any question."))}m.isMDXComponent=!0},424:function(e,t,a){"use strict";a(426);var o=a(0),n=a.n(o),r=a(423),l=a.n(r);a(132);t.a=function(e){var t=e.children,a=e.classNames,o=e.fill,r=e.icon,i=e.type,c=null;switch(i){case"danger":c="alert-triangle";break;case"success":c="check-circle";break;case"warning":c="alert-triangle";break;default:c="info"}return n.a.createElement("div",{className:l()(a,"alert","alert--"+i,{"alert--fill":o,"alert--icon":!1!==r}),role:"alert"},!1!==r&&n.a.createElement("i",{className:l()("feather","icon-"+(r||c))}),t)}},428:function(e,t,a){var o=a(28).f,n=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in n||a(10)&&o(n,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var o=a(0),n=a.n(o),r=a(424);t.a=function(e){var t=e.children,a=e.name;return n.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},437:function(e,t,a){"use strict";var o=a(1),n=(a(442),a(439),a(52),a(29),a(22),a(21),a(0)),r=a.n(n),l=a(449),i=a(423),c=a.n(i),b=a(433),u=a.n(b),s=a(448),p=37,d=39;function m(e){var t=e.block,a=e.centered,o=e.changeSelectedValue,n=e.className,l=e.handleKeydown,i=e.style,b=e.values,u=e.selectedValue,s=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:c()("tabs",n,{"tabs--block":t}),style:i},b.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":u===t,className:c()("tab-item",{"tab-item--active":u===t}),key:t,ref:function(e){return s.push(e)},onKeyDown:function(e){return l(s,e.target,e)},onFocus:function(){return o(t)},onClick:function(){return o(t)}},a)}))))}function h(e){var t=e.placeholder,a=e.selectedValue,o=e.changeSelectedValue,n=e.size,i=e.values,c=i;if(c[0].group){var b=_.groupBy(c,"group");c=Object.keys(b).map((function(e){return{label:e,options:b[e]}}))}return r.a.createElement(l.a,{className:"react-select-container react-select--"+n,classNamePrefix:"react-select",options:c,isClearable:a,placeholder:t,value:i.find((function(e){return e.value==a})),onChange:function(e){return o(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,a=e.defaultValue,l=e.groupId,i=e.label,c=e.placeholder,b=e.select,y=e.size,f=(e.style,e.values),O=e.urlKey,j=Object(s.a)(),g=j.tabGroupChoices,v=j.setTabGroupChoices,w=Object(n.useState)(a),k=w[0],N=w[1];if(null!=l){var T=g[l];null!=T&&T!==k&&N(T)}var C=function(e){N(e),null!=l&&v(l,e)},D=[],A=function(e,t,a){switch(a.keyCode){case d:!function(e,t){var a=e.indexOf(t)+1;e[a]?e[a].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var a=e.indexOf(t)-1;e[a]?e[a].focus():e[e.length-1].focus()}(e,t)}};return Object(n.useEffect)((function(){if("undefined"!=typeof window&&window.location&&O){var e=u.a.parse(window.location.search);e[O]&&N(e[O])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(y||"md")},i&&r.a.createElement("div",{className:"margin-vert--sm"},i),f.length>1&&(b?r.a.createElement(h,Object(o.a)({changeSelectedValue:C,handleKeydown:A,placeholder:c,selectedValue:k,size:y,tabRefs:D},e)):r.a.createElement(m,Object(o.a)({changeSelectedValue:C,handleKeydown:A,selectedValue:k,tabRefs:D},e)))),n.Children.toArray(t).filter((function(e){return e.props.value===k}))[0])}},444:function(e,t,a){"use strict";var o=a(0),n=a.n(o);t.a=function(e){return n.a.createElement(n.a.Fragment,null,e.children)}}}]); \ No newline at end of file diff --git a/05049f86.79450b0f.js b/05049f86.2780985c.js similarity index 90% rename from 05049f86.79450b0f.js rename to 05049f86.2780985c.js index 04491648b5..ba7801dd42 100644 --- a/05049f86.79450b0f.js +++ b/05049f86.2780985c.js @@ -1,2 +1,2 @@ -/*! For license information please see 05049f86.79450b0f.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{156:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return c})),r.d(t,"metadata",(function(){return u})),r.d(t,"rightToc",(function(){return l})),r.d(t,"default",(function(){return f}));var n=r(1),a=r(9),o=(r(0),r(422)),i=(r(431),r(426),r(421)),c={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Terraform",description:"Learn how to use Terraform with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: terraform"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Terraform",description:"Learn how to use Terraform with Qovery",permalink:"/guides/advanced/terraform",readingTime:"1 min read",source:"@site/guides/advanced/terraform.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: terraform",permalink:"/guides/tags/technology-terraform"}],title:"Terraform",truncated:!1,prevItem:{title:"Setup VPC peering on AWS with Qovery",permalink:"/guides/tutorial/aws-vpc-peering-with-qovery"},nextItem:{title:"URL Shortener API with Kotlin (Part 1/2)",permalink:"/guides/tutorial/url-shortener-api-with-kotlin"}},l=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:l};function f(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"this guide")," to learn more about Terraform with Qovery.")),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some additional resources you can use to learn more about Terraform integration with Qovery:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"Deploy AWS RDS instance with Terraform")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"Learn how to deploy an AWS RDS instance with Terraform and Lifecycle Job")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=terraform"}),'Forum "Terraform"')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=terraform"}),'List "Terraform" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}f.isMDXComponent=!0},420:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=a.a.createContext({}),s=function(e){var t=a.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},f=function(e){var t=s(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),f=s(r),m=n,b=f["".concat(i,".").concat(m)]||f[m]||p[m]||o;return r?a.a.createElement(b,c({ref:t},l,{components:r})):a.a.createElement(b,c({ref:t},l))}));function b(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l1?arguments[1]:void 0,r),u=i>2?arguments[2]:void 0,l=void 0===u?r:a(u,r);l>c;)t[c++]=e;return t}},425:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,r){"use strict";r(425);var n=r(0),a=r.n(n),o=r(421);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},428:function(e,t,r){"use strict";var n=r(432),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(r(n,e,i.length))})),i.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(420),r(428)),i=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),s=Object(n.useState)(null),f=s[0],p=s[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!f&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 05049f86.2780985c.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{157:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return c})),r.d(t,"metadata",(function(){return u})),r.d(t,"rightToc",(function(){return l})),r.d(t,"default",(function(){return f}));var n=r(1),a=r(9),o=(r(0),r(425)),i=(r(434),r(429),r(424)),c={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Terraform",description:"Learn how to use Terraform with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: terraform"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Terraform",description:"Learn how to use Terraform with Qovery",permalink:"/guides/advanced/terraform",readingTime:"1 min read",source:"@site/guides/advanced/terraform.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: terraform",permalink:"/guides/tags/technology-terraform"}],title:"Terraform",truncated:!1,prevItem:{title:"Setup VPC peering on AWS with Qovery",permalink:"/guides/tutorial/aws-vpc-peering-with-qovery"},nextItem:{title:"URL Shortener API with Kotlin (Part 1/2)",permalink:"/guides/tutorial/url-shortener-api-with-kotlin"}},l=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:l};function f(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"this guide")," to learn more about Terraform with Qovery.")),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some additional resources you can use to learn more about Terraform integration with Qovery:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"Deploy AWS RDS instance with Terraform")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"Learn how to deploy an AWS RDS instance with Terraform and Lifecycle Job")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=terraform"}),'Forum "Terraform"')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=terraform"}),'List "Terraform" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}f.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=a.a.createContext({}),s=function(e){var t=a.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},f=function(e){var t=s(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),f=s(r),m=n,b=f["".concat(i,".").concat(m)]||f[m]||p[m]||o;return r?a.a.createElement(b,c({ref:t},l,{components:r})):a.a.createElement(b,c({ref:t},l))}));function b(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l1?arguments[1]:void 0,r),u=i>2?arguments[2]:void 0,l=void 0===u?r:a(u,r);l>c;)t[c++]=e;return t}},428:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,r){"use strict";r(428);var n=r(0),a=r.n(n),o=r(424);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},433:function(e,t,r){"use strict";var n=r(435),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(r(n,e,i.length))})),i.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(423),r(433)),i=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),s=Object(n.useState)(null),f=s[0],p=s[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!f&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/0578cd49.b00131c4.js.LICENSE.txt b/05049f86.2780985c.js.LICENSE.txt similarity index 100% rename from 0578cd49.b00131c4.js.LICENSE.txt rename to 05049f86.2780985c.js.LICENSE.txt diff --git a/0578cd49.7eca4afb.js b/0578cd49.7eca4afb.js new file mode 100644 index 0000000000..b2d34da978 --- /dev/null +++ b/0578cd49.7eca4afb.js @@ -0,0 +1,2 @@ +/*! For license information please see 0578cd49.7eca4afb.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{158:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),o=(n(0),n(425)),i=n(424),c=n(434),s={last_modified_on:"2023-02-23",$schema:"/.meta/.schemas/guides.json",title:"Environment variables",description:"How to manage environment variables in your projects and applications",series_position:4,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},l={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Environment variables",description:"How to manage environment variables in your projects and applications",permalink:"/guides/getting-started/managing-environment-variables",readingTime:"2 min read",seriesPosition:4,source:"@site/guides/getting-started/managing-environment-variables.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Environment variables",truncated:!1,prevItem:{title:"Custom domain",permalink:"/guides/getting-started/setting-custom-domain"},nextItem:{title:"Debugging",permalink:"/guides/getting-started/debugging"}},u=[{value:"Tutorial",id:"tutorial",children:[{value:"Create an environment variable",id:"create-an-environment-variable",children:[]},{value:"Use the environment variable in the app",id:"use-the-environment-variable-in-the-app",children:[]}]}],p={rightToc:u};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Sometimes you need to pass data to your application. E.g: API key, credentials, debug parameters. For this reason, Qovery allows you to\nsecurely pass your data by using ",Object(o.b)("em",{parentName:"p"},"Environment Variables"),"."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you need to keep secure your environment variable? Use ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Secret")," instead of ",Object(o.b)("strong",{parentName:"p"},"Environment\nVariable"),".")),Object(o.b)("p",null,"Here is a short video to show how to use environment variables."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/af6d9c36b6b643eda2dc29d8b3629328",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("h2",{id:"tutorial"},"Tutorial"),Object(o.b)("p",null,"Here is an example on how to pass an environment variable to a NodeJS app."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Steps are similar for Secrets.")),Object(o.b)("p",null,"Let's first create a new Node.js application that uses environment variables."),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h3",{id:"create-an-environment-variable"},"Create an environment variable"),Object(o.b)("p",null,"Let's say that we pass an environment variable ",Object(o.b)("inlineCode",{parentName:"p"},"ENABLE_DEBUG")," that turns on the debug info from the app."),Object(o.b)("p",null,"Click on the ",Object(o.b)("inlineCode",{parentName:"p"},"environment variables")," tab inside your app view."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/environment_variables_.png",alt:"List environment variables"})),Object(o.b)("p",null,'Click on "create", and then add the ',Object(o.b)("inlineCode",{parentName:"p"},"ENABLE_DEBUG")," variable with a boolean value."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/create_environment_variable_.png",alt:"Create environment variable"}))),Object(o.b)("li",null,Object(o.b)("h3",{id:"use-the-environment-variable-in-the-app"},"Use the environment variable in the app"),Object(o.b)("p",null,"Create ",Object(o.b)("inlineCode",{parentName:"p"},"app.js")," file - a simple Node.js HTTP server application:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-javascript",metastring:'title="app.js" {6-10}',title:'"app.js"',"{6-10}":!0}),"const http = require('http');\n\nconst hostname = '0.0.0.0';\nconst port = 3333;\n\nconst enableDebug = process.env.ENABLE_DEBUG\n\nif (enableDebug) {\n console.log(\"debug mode enabled\");\n}\n\nconst server = http.createServer((req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/plain');\n res.end(\"hello world\");\n});\n\nserver.listen(port, hostname, () => {\n console.log(`Server running at http://${hostname}:${port}/`);\n});\n")),Object(o.b)("p",null,"As you can see, to get access to your environment variable you just need to use process.env.",Object(o.b)("inlineCode",{parentName:"p"},"ENABLE_DEBUG"),". Environment variables are\ninjected at the build and run time.")))),Object(o.b)("p",null,"This guide was an introduction on how to use the Environment Variables. To know more\nabout ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Environment Variables")," and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Secrets"),",\ngo to our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/"}),"detailed documentation"),"."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you want to bulk import your Environment Variables? ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli/"}),"Check out this tutorial"))))}b.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return n?a.a.createElement(m,c({ref:t},l,{components:n})):a.a.createElement(m,c({ref:t},l))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:a(s,n);l>c;)t[c++]=e;return t}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),u=Object(r.useState)(null),p=u[0],b=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/06e8d299.1138c19d.js.LICENSE.txt b/0578cd49.7eca4afb.js.LICENSE.txt similarity index 100% rename from 06e8d299.1138c19d.js.LICENSE.txt rename to 0578cd49.7eca4afb.js.LICENSE.txt diff --git a/0578cd49.b00131c4.js b/0578cd49.b00131c4.js deleted file mode 100644 index 4abed449b4..0000000000 --- a/0578cd49.b00131c4.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see 0578cd49.b00131c4.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{157:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),o=(n(0),n(422)),i=n(421),c=n(431),s={last_modified_on:"2023-02-23",$schema:"/.meta/.schemas/guides.json",title:"Environment variables",description:"How to manage environment variables in your projects and applications",series_position:4,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},l={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Environment variables",description:"How to manage environment variables in your projects and applications",permalink:"/guides/getting-started/managing-environment-variables",readingTime:"2 min read",seriesPosition:4,source:"@site/guides/getting-started/managing-environment-variables.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Environment variables",truncated:!1,prevItem:{title:"Custom domain",permalink:"/guides/getting-started/setting-custom-domain"},nextItem:{title:"Debugging",permalink:"/guides/getting-started/debugging"}},u=[{value:"Tutorial",id:"tutorial",children:[{value:"Create an environment variable",id:"create-an-environment-variable",children:[]},{value:"Use the environment variable in the app",id:"use-the-environment-variable-in-the-app",children:[]}]}],p={rightToc:u};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Sometimes you need to pass data to your application. E.g: API key, credentials, debug parameters. For this reason, Qovery allows you to\nsecurely pass your data by using ",Object(o.b)("em",{parentName:"p"},"Environment Variables"),"."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you need to keep secure your environment variable? Use ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Secret")," instead of ",Object(o.b)("strong",{parentName:"p"},"Environment\nVariable"),".")),Object(o.b)("p",null,"Here is a short video to show how to use environment variables."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/af6d9c36b6b643eda2dc29d8b3629328",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("h2",{id:"tutorial"},"Tutorial"),Object(o.b)("p",null,"Here is an example on how to pass an environment variable to a NodeJS app."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Steps are similar for Secrets.")),Object(o.b)("p",null,"Let's first create a new Node.js application that uses environment variables."),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h3",{id:"create-an-environment-variable"},"Create an environment variable"),Object(o.b)("p",null,"Let's say that we pass an environment variable ",Object(o.b)("inlineCode",{parentName:"p"},"ENABLE_DEBUG")," that turns on the debug info from the app."),Object(o.b)("p",null,"Click on the ",Object(o.b)("inlineCode",{parentName:"p"},"environment variables")," tab inside your app view."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/environment_variables_.png",alt:"List environment variables"})),Object(o.b)("p",null,'Click on "create", and then add the ',Object(o.b)("inlineCode",{parentName:"p"},"ENABLE_DEBUG")," variable with a boolean value."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/create_environment_variable_.png",alt:"Create environment variable"}))),Object(o.b)("li",null,Object(o.b)("h3",{id:"use-the-environment-variable-in-the-app"},"Use the environment variable in the app"),Object(o.b)("p",null,"Create ",Object(o.b)("inlineCode",{parentName:"p"},"app.js")," file - a simple Node.js HTTP server application:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-javascript",metastring:'title="app.js" {6-10}',title:'"app.js"',"{6-10}":!0}),"const http = require('http');\n\nconst hostname = '0.0.0.0';\nconst port = 3333;\n\nconst enableDebug = process.env.ENABLE_DEBUG\n\nif (enableDebug) {\n console.log(\"debug mode enabled\");\n}\n\nconst server = http.createServer((req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/plain');\n res.end(\"hello world\");\n});\n\nserver.listen(port, hostname, () => {\n console.log(`Server running at http://${hostname}:${port}/`);\n});\n")),Object(o.b)("p",null,"As you can see, to get access to your environment variable you just need to use process.env.",Object(o.b)("inlineCode",{parentName:"p"},"ENABLE_DEBUG"),". Environment variables are\ninjected at the build and run time.")))),Object(o.b)("p",null,"This guide was an introduction on how to use the Environment Variables. To know more\nabout ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Environment Variables")," and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Secrets"),",\ngo to our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/"}),"detailed documentation"),"."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you want to bulk import your Environment Variables? ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli/"}),"Check out this tutorial"))))}b.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return n?a.a.createElement(m,c({ref:t},l,{components:n})):a.a.createElement(m,c({ref:t},l))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:a(s,n);l>c;)t[c++]=e;return t}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),u=Object(r.useState)(null),p=u[0],b=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/1b633bfd.d827d5b6.js b/06e8d299.4de3d633.js similarity index 82% rename from 1b633bfd.d827d5b6.js rename to 06e8d299.4de3d633.js index 00e2f4f8b9..092addc344 100644 --- a/1b633bfd.d827d5b6.js +++ b/06e8d299.4de3d633.js @@ -1,2 +1,2 @@ -/*! For license information please see 1b633bfd.d827d5b6.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[33],{182:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var o=n(1),r=n(9),a=(n(0),n(422)),c=n(431),i=(n(421),n(426)),l=(n(429),{last_modified_on:"2023-10-12",$schema:"/.meta/.schemas/guides.json",title:"How to activate SSO to connect to your EKS cluster",description:"How to activate SSO to connect to your EKS cluster",author_github:"https://github.com/benjaminch",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to activate SSO to connect to your EKS cluster",description:"How to activate SSO to connect to your EKS cluster",permalink:"/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster",readingTime:"6 min read",source:"@site/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to activate SSO to connect to your EKS cluster",truncated:!1,prevItem:{title:"Helm Charts",permalink:"/guides/advanced/helm-chart"},nextItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1"}},u=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],b={rightToc:u};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Qovery makes it easy to create an EKS cluster on your AWS account and manage the deployment of applications on it. But you still might want to execute operations on it via ",Object(a.b)("inlineCode",{parentName:"p"},"kubectl")," like you would on any other Kubernetes cluster.\nYou have several ways to connect to your cluster:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Activate IAM group sync, more on that ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"here")),Object(a.b)("li",{parentName:"ul"},"Activate SSO support on your cluster allowing users to connect using AWS SSO.")),Object(a.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have AWS CLI installed"),Object(a.b)("li",{parentName:"ul"},"You have configured an ",Object(a.b)("inlineCode",{parentName:"li"},"Admins")," group (or any group used for admins) as described in the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/cloud-provider/guide-amazon-web-services/"}),"Qovery AWS setup")),Object(a.b)("li",{parentName:"ul"},"You have an existing EKS cluster managed by Qovery"),Object(a.b)("li",{parentName:"ul"},"You have followed ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"https://aws.amazon.com/fr/blogs/containers/a-quick-path-to-amazon-eks-single-sign-on-using-aws-sso/"}),"this AWS tutorial")," up to ",Object(a.b)("inlineCode",{parentName:"li"},"AWS SSO user configuration")," excluded."))),Object(a.b)("h2",{id:"goal"},"Goal"),Object(a.b)("p",null,"This tutorial will show you how to access a Qovery managed cluster using AWS SSO."),Object(a.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"install-and-configure-your-toolchain"},"Install and configure your toolchain"),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"kubectl")),Object(a.b)("p",null,"To interact with your cluster, you will need ",Object(a.b)("inlineCode",{parentName:"p"},"kubectl")," installed.\n",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://kubernetes.io/docs/tasks/tools/"}),"https://kubernetes.io/docs/tasks/tools/")),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"AWS CLI")),Object(a.b)("p",null,"The AWS CLI must be installed and configured on your machine.\n",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"}),"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"select-iam-user-group-you-configured-for-qovery-as-admin"},"Select IAM user group you configured for Qovery as admin"),Object(a.b)("p",null,"In AWS console, go to ",Object(a.b)("inlineCode",{parentName:"p"},"IAM > User Groups")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/0-go-to-iam-user-groups.png",alt:"AWS console - go to user groups"})),Object(a.b)("p",null,"then select the group you configured as admin group for Qovery (",Object(a.b)("inlineCode",{parentName:"p"},"Admins")," in the example below)."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/1-select-admins-iam-user-group.png",alt:"AWS console - select admin user group"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"create-a-new-policy-to-this-group-allowing-full-access-to-eks-resources"},"Create a new policy to this group allowing full access to EKS resources"),Object(a.b)("p",null,"In this admin group, go to ",Object(a.b)("inlineCode",{parentName:"p"},"permissions")," tab. Click on ",Object(a.b)("inlineCode",{parentName:"p"},"Add permissions > Create inline policy"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/2-create-new-inline-policy-to-admin-user-group.png",alt:"AWS console - create new inline policy"})),Object(a.b)("p",null,"Switch to JSON view."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/3-inline-policy-creation-json-view.png",alt:"AWS console - switch to inline policy creation json view"})),Object(a.b)("p",null,"Put this content to the ",Object(a.b)("inlineCode",{parentName:"p"},"Policy editor"),":"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Effect": "Allow",\n "Action": [\n "eks:*",\n "sts:AssumeRole"\n ],\n "Resource": "*"\n }\n ]\n}\n')),Object(a.b)("p",null,"Then click on ",Object(a.b)("inlineCode",{parentName:"p"},"Next"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/4-edit-inline-policy-content.png",alt:"AWS console - edit inline policy content"})),Object(a.b)("p",null,"Give a name to this new policy, for example ",Object(a.b)("inlineCode",{parentName:"p"},"SSO_EKSClusterAdminAccess"),". Then click on ",Object(a.b)("inlineCode",{parentName:"p"},"Create Policy"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/5-create-inline-policy.png",alt:"AWS console - create inline policy"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"set-up-cli-with-sso-access-to-eks"},"Set up CLI with SSO access to EKS"),Object(a.b)("p",null,"Create a named SSO profile using AWS CLI."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"aws configure sso\n")),Object(a.b)("p",null,"You will be prompted an SSO session name, put what you want, I used ",Object(a.b)("inlineCode",{parentName:"p"},"sso-benjamin"),"."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"SSO session name (Recommended): sso-benjamin\nAttempting to automatically open the SSO authorization page in your default browser.\nIf the browser does not open or you wish to use a different device to authorize this request, open the following URL:\n\nhttps://device.sso.us-east-2.amazonaws.com/\n\nThen enter the code:\n\nFHTG-****\n")),Object(a.b)("p",null,"You will be redirected to your browser, validate the form."),Object(a.b)("p",null,"Then you will be prompted to select your AWS account."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"There are 1 AWS account available to you.\n> qovery, q@qovery.com (283389****)\n")),Object(a.b)("p",null,"Then you will be prompted for default region (",Object(a.b)("inlineCode",{parentName:"p"},"eu-west-3")," in my case), output format (",Object(a.b)("inlineCode",{parentName:"p"},"json")," in my case) and profile name (",Object(a.b)("inlineCode",{parentName:"p"},"bchastanier_sso")," in my case, but feel free to pick whatever you want)."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),'Using the account ID 283389****\nThe only role available to you is: AdministratorAccess\nUsing the role name "AdministratorAccess"\nCLI default client Region [None]: eu-west-3\nCLI default output format [None]: json\nCLI profile name: bchastanier_sso\n'))),Object(a.b)("li",null,Object(a.b)("h4",{id:"get-sso-role-arn"},"Get SSO role ARN"),Object(a.b)("p",null,"Go to AWS console > IAM > Roles."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/6-iam-roles.png",alt:"AWS console - go to aws iam roles"})),Object(a.b)("p",null,"Look for a role named ",Object(a.b)("inlineCode",{parentName:"p"},"AWSReservedSSO_xx")," and select it (name can varies based on what you have configured / how you named your ",Object(a.b)("inlineCode",{parentName:"p"},"Admins")," user group, but it should start with ",Object(a.b)("inlineCode",{parentName:"p"},"AWSReservedSSO_"),")."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/7-iam-roles-look-for-sso-role.png",alt:"AWS console - look for SSO role"})),Object(a.b)("p",null,"Copy its ARN and keep it somewhere, you will need it in next step."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/8-iam-roles-copy-arn.png",alt:"AWS console - copy SSO role ARN"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"enable-sso-on-your-cluster"},"Enable SSO on your cluster"),Object(a.b)("p",null,"Go to your clusters in Qovery console and click on cluster you want to activate SSO on settings."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/9-qovery-go-to-cluster-settings.png",alt:"AWS console - go to qovery cluster settings"})),Object(a.b)("p",null,"Then go to advanced settings, and set:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("inlineCode",{parentName:"li"},"aws.iam.enable_sso")," to ",Object(a.b)("inlineCode",{parentName:"li"},"true")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("inlineCode",{parentName:"li"},"aws.iam.sso_role_arn")," to the SSO role ARN string you copy from previous step.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/10-qovery-cluster-advanced-settings-enable-sso.png",alt:"AWS console - set qovery cluster advanced settings to enable SSO"})),Object(a.b)("p",null,"Redeploy your cluster once advanced settings are saved.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"download-the-kubeconfig-file"},"Download the Kubeconfig file"),Object(a.b)("p",null,"To connect to your EKS cluster you will need to set a context to ",Object(a.b)("inlineCode",{parentName:"p"},"kubectl"),". This is done with a ",Object(a.b)("inlineCode",{parentName:"p"},"Kubeconfig")," file."),Object(a.b)("p",null,"When installing a new cluster, Qovery stores it in an S3 bucket on your account."),Object(a.b)("p",null,"Go to S3, find the Qovery bucket, and download the file. The bucket should be named something like ",Object(a.b)("inlineCode",{parentName:"p"},"qovery-kubeconfigs-.yaml"),"."),Object(a.b)("p",null,"Set the context for kubectl, run the following command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"export KUBECONFIG=\n")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/11-get-cluster-kubeconfig.png",alt:"AWS console - get Kubeconfig"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"connect-to-your-cluster"},"Connect to your cluster"),Object(a.b)("p",null,"Connect via the CLI running this command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"aws sso login --profile \n")),Object(a.b)("p",null,"This will open your browser and prompt you to connect, validate the form."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/12-validate-sso-connection-in-browser.png",alt:"AWS console - validate SSO connection in browser"})),Object(a.b)("p",null,"Now you should be able to access your cluster without anything else, let's try to get ",Object(a.b)("inlineCode",{parentName:"p"},"aws-auth")," configmap showing users and roles allowed to connect to the cluster:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"AWS_PROFILE= kubectl describe -n kube-system configmap/aws-auth\n")),Object(a.b)("p",null,"This should give you the config map content. If not, something is not properly configured.")))),Object(a.b)("h2",{id:"conclusion"},"Conclusion"),Object(a.b)("p",null,"You can access your Qovery clusters via your SSO directly."))}p.isMDXComponent=!0},420:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),m=o,d=b["".concat(c,".").concat(m)]||b[m]||p[m]||a;return n?r.a.createElement(d,i({ref:t},s,{components:n})):r.a.createElement(d,i({ref:t},s))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,c=new Array(a);c[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var s=2;s1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>i;)t[i++]=e;return t}},425:function(e,t,n){var o=n(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var o=n(0),r=n.n(o),a=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var o=n(1),r=n(0),a=n.n(r),c=n(39),i=n(430),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,b=Object(i.a)(u),p=Object(r.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&b&&window.docusaurus.prefetch(u),function(){m&&t&&t.disconnect()}}),[u,m,b]),u&&b?a.a.createElement(c.b,Object(o.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,o;m&&e&&b&&(n=e,o=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:u})):a.a.createElement("a",Object(o.a)({},e,{href:u}))}},428:function(e,t,n){"use strict";var o=n(432),r=n(51);function a(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(r),a,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[a(t,e),"[",o,"]"].join(""):[a(t,e),"[",a(o,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return a(o,t);if(Array.isArray(r)){var c=[];return r.slice().forEach((function(e){void 0!==e&&c.push(n(o,e,c.length))})),c.join("&")}return a(o,t)+"="+a(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=n(427),c=n(420),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,c=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,b=e.to,p=i()("jump-to","jump-to--"+s,n),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},o?r.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:b,target:u,className:p},m):r.a.createElement(a.a,{to:b,className:p},m)}},430:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},431:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(420),n(428)),c=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),u=Object(o.useState)(null),b=u[0],p=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 06e8d299.4de3d633.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{159:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var o=n(1),r=n(9),a=(n(0),n(425)),c=n(434),i=(n(424),n(429)),l=(n(431),{last_modified_on:"2023-10-12",$schema:"/.meta/.schemas/guides.json",title:"How to activate SSO to connect to your EKS cluster",description:"How to activate SSO to connect to your EKS cluster",author_github:"https://github.com/benjaminch",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to activate SSO to connect to your EKS cluster",description:"How to activate SSO to connect to your EKS cluster",permalink:"/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster",readingTime:"6 min read",source:"@site/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to activate SSO to connect to your EKS cluster",truncated:!1,prevItem:{title:"Helm Charts",permalink:"/guides/advanced/helm-chart"},nextItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1"}},u=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],b={rightToc:u};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Qovery makes it easy to create an EKS cluster on your AWS account and manage the deployment of applications on it. But you still might want to execute operations on it via ",Object(a.b)("inlineCode",{parentName:"p"},"kubectl")," like you would on any other Kubernetes cluster.\nYou have several ways to connect to your cluster:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Activate IAM group sync, more on that ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"here")),Object(a.b)("li",{parentName:"ul"},"Activate SSO support on your cluster allowing users to connect using AWS SSO.")),Object(a.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have AWS CLI installed"),Object(a.b)("li",{parentName:"ul"},"You have configured an ",Object(a.b)("inlineCode",{parentName:"li"},"Admins")," group (or any group used for admins) as described in the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/cloud-provider/guide-amazon-web-services/"}),"Qovery AWS setup")),Object(a.b)("li",{parentName:"ul"},"You have an existing EKS cluster managed by Qovery"),Object(a.b)("li",{parentName:"ul"},"You have followed ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"https://aws.amazon.com/fr/blogs/containers/a-quick-path-to-amazon-eks-single-sign-on-using-aws-sso/"}),"this AWS tutorial")," up to ",Object(a.b)("inlineCode",{parentName:"li"},"AWS SSO user configuration")," excluded."))),Object(a.b)("h2",{id:"goal"},"Goal"),Object(a.b)("p",null,"This tutorial will show you how to access a Qovery managed cluster using AWS SSO."),Object(a.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"install-and-configure-your-toolchain"},"Install and configure your toolchain"),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"kubectl")),Object(a.b)("p",null,"To interact with your cluster, you will need ",Object(a.b)("inlineCode",{parentName:"p"},"kubectl")," installed.\n",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://kubernetes.io/docs/tasks/tools/"}),"https://kubernetes.io/docs/tasks/tools/")),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"AWS CLI")),Object(a.b)("p",null,"The AWS CLI must be installed and configured on your machine.\n",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"}),"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"select-iam-user-group-you-configured-for-qovery-as-admin"},"Select IAM user group you configured for Qovery as admin"),Object(a.b)("p",null,"In AWS console, go to ",Object(a.b)("inlineCode",{parentName:"p"},"IAM > User Groups")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/0-go-to-iam-user-groups.png",alt:"AWS console - go to user groups"})),Object(a.b)("p",null,"then select the group you configured as admin group for Qovery (",Object(a.b)("inlineCode",{parentName:"p"},"Admins")," in the example below)."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/1-select-admins-iam-user-group.png",alt:"AWS console - select admin user group"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"create-a-new-policy-to-this-group-allowing-full-access-to-eks-resources"},"Create a new policy to this group allowing full access to EKS resources"),Object(a.b)("p",null,"In this admin group, go to ",Object(a.b)("inlineCode",{parentName:"p"},"permissions")," tab. Click on ",Object(a.b)("inlineCode",{parentName:"p"},"Add permissions > Create inline policy"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/2-create-new-inline-policy-to-admin-user-group.png",alt:"AWS console - create new inline policy"})),Object(a.b)("p",null,"Switch to JSON view."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/3-inline-policy-creation-json-view.png",alt:"AWS console - switch to inline policy creation json view"})),Object(a.b)("p",null,"Put this content to the ",Object(a.b)("inlineCode",{parentName:"p"},"Policy editor"),":"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Effect": "Allow",\n "Action": [\n "eks:*",\n "sts:AssumeRole"\n ],\n "Resource": "*"\n }\n ]\n}\n')),Object(a.b)("p",null,"Then click on ",Object(a.b)("inlineCode",{parentName:"p"},"Next"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/4-edit-inline-policy-content.png",alt:"AWS console - edit inline policy content"})),Object(a.b)("p",null,"Give a name to this new policy, for example ",Object(a.b)("inlineCode",{parentName:"p"},"SSO_EKSClusterAdminAccess"),". Then click on ",Object(a.b)("inlineCode",{parentName:"p"},"Create Policy"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/5-create-inline-policy.png",alt:"AWS console - create inline policy"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"set-up-cli-with-sso-access-to-eks"},"Set up CLI with SSO access to EKS"),Object(a.b)("p",null,"Create a named SSO profile using AWS CLI."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"aws configure sso\n")),Object(a.b)("p",null,"You will be prompted an SSO session name, put what you want, I used ",Object(a.b)("inlineCode",{parentName:"p"},"sso-benjamin"),"."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"SSO session name (Recommended): sso-benjamin\nAttempting to automatically open the SSO authorization page in your default browser.\nIf the browser does not open or you wish to use a different device to authorize this request, open the following URL:\n\nhttps://device.sso.us-east-2.amazonaws.com/\n\nThen enter the code:\n\nFHTG-****\n")),Object(a.b)("p",null,"You will be redirected to your browser, validate the form."),Object(a.b)("p",null,"Then you will be prompted to select your AWS account."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"There are 1 AWS account available to you.\n> qovery, q@qovery.com (283389****)\n")),Object(a.b)("p",null,"Then you will be prompted for default region (",Object(a.b)("inlineCode",{parentName:"p"},"eu-west-3")," in my case), output format (",Object(a.b)("inlineCode",{parentName:"p"},"json")," in my case) and profile name (",Object(a.b)("inlineCode",{parentName:"p"},"bchastanier_sso")," in my case, but feel free to pick whatever you want)."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),'Using the account ID 283389****\nThe only role available to you is: AdministratorAccess\nUsing the role name "AdministratorAccess"\nCLI default client Region [None]: eu-west-3\nCLI default output format [None]: json\nCLI profile name: bchastanier_sso\n'))),Object(a.b)("li",null,Object(a.b)("h4",{id:"get-sso-role-arn"},"Get SSO role ARN"),Object(a.b)("p",null,"Go to AWS console > IAM > Roles."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/6-iam-roles.png",alt:"AWS console - go to aws iam roles"})),Object(a.b)("p",null,"Look for a role named ",Object(a.b)("inlineCode",{parentName:"p"},"AWSReservedSSO_xx")," and select it (name can varies based on what you have configured / how you named your ",Object(a.b)("inlineCode",{parentName:"p"},"Admins")," user group, but it should start with ",Object(a.b)("inlineCode",{parentName:"p"},"AWSReservedSSO_"),")."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/7-iam-roles-look-for-sso-role.png",alt:"AWS console - look for SSO role"})),Object(a.b)("p",null,"Copy its ARN and keep it somewhere, you will need it in next step."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/8-iam-roles-copy-arn.png",alt:"AWS console - copy SSO role ARN"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"enable-sso-on-your-cluster"},"Enable SSO on your cluster"),Object(a.b)("p",null,"Go to your clusters in Qovery console and click on cluster you want to activate SSO on settings."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/9-qovery-go-to-cluster-settings.png",alt:"AWS console - go to qovery cluster settings"})),Object(a.b)("p",null,"Then go to advanced settings, and set:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("inlineCode",{parentName:"li"},"aws.iam.enable_sso")," to ",Object(a.b)("inlineCode",{parentName:"li"},"true")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("inlineCode",{parentName:"li"},"aws.iam.sso_role_arn")," to the SSO role ARN string you copy from previous step.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/10-qovery-cluster-advanced-settings-enable-sso.png",alt:"AWS console - set qovery cluster advanced settings to enable SSO"})),Object(a.b)("p",null,"Redeploy your cluster once advanced settings are saved.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"download-the-kubeconfig-file"},"Download the Kubeconfig file"),Object(a.b)("p",null,"To connect to your EKS cluster you will need to set a context to ",Object(a.b)("inlineCode",{parentName:"p"},"kubectl"),". This is done with a ",Object(a.b)("inlineCode",{parentName:"p"},"Kubeconfig")," file."),Object(a.b)("p",null,"When installing a new cluster, Qovery stores it in an S3 bucket on your account."),Object(a.b)("p",null,"Go to S3, find the Qovery bucket, and download the file. The bucket should be named something like ",Object(a.b)("inlineCode",{parentName:"p"},"qovery-kubeconfigs-.yaml"),"."),Object(a.b)("p",null,"Set the context for kubectl, run the following command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"export KUBECONFIG=\n")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/11-get-cluster-kubeconfig.png",alt:"AWS console - get Kubeconfig"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"connect-to-your-cluster"},"Connect to your cluster"),Object(a.b)("p",null,"Connect via the CLI running this command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"aws sso login --profile \n")),Object(a.b)("p",null,"This will open your browser and prompt you to connect, validate the form."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/12-validate-sso-connection-in-browser.png",alt:"AWS console - validate SSO connection in browser"})),Object(a.b)("p",null,"Now you should be able to access your cluster without anything else, let's try to get ",Object(a.b)("inlineCode",{parentName:"p"},"aws-auth")," configmap showing users and roles allowed to connect to the cluster:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"AWS_PROFILE= kubectl describe -n kube-system configmap/aws-auth\n")),Object(a.b)("p",null,"This should give you the config map content. If not, something is not properly configured.")))),Object(a.b)("h2",{id:"conclusion"},"Conclusion"),Object(a.b)("p",null,"You can access your Qovery clusters via your SSO directly."))}p.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),m=o,d=b["".concat(c,".").concat(m)]||b[m]||p[m]||a;return n?r.a.createElement(d,i({ref:t},s,{components:n})):r.a.createElement(d,i({ref:t},s))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,c=new Array(a);c[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var s=2;s1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>i;)t[i++]=e;return t}},428:function(e,t,n){var o=n(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var o=n(0),r=n.n(o),a=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var o=n(1),r=n(0),a=n.n(r),c=n(39),i=n(432),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,b=Object(i.a)(u),p=Object(r.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&b&&window.docusaurus.prefetch(u),function(){m&&t&&t.disconnect()}}),[u,m,b]),u&&b?a.a.createElement(c.b,Object(o.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,o;m&&e&&b&&(n=e,o=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:u})):a.a.createElement("a",Object(o.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=n(430),c=n(423),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,c=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,b=e.to,p=i()("jump-to","jump-to--"+s,n),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},o?r.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:b,target:u,className:p},m):r.a.createElement(a.a,{to:b,className:p},m)}},432:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},433:function(e,t,n){"use strict";var o=n(435),r=n(51);function a(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(r),a,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[a(t,e),"[",o,"]"].join(""):[a(t,e),"[",a(o,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return a(o,t);if(Array.isArray(r)){var c=[];return r.slice().forEach((function(e){void 0!==e&&c.push(n(o,e,c.length))})),c.join("&")}return a(o,t)+"="+a(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(423),n(433)),c=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),u=Object(o.useState)(null),b=u[0],p=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/072d4c63.41365721.js.LICENSE.txt b/06e8d299.4de3d633.js.LICENSE.txt similarity index 100% rename from 072d4c63.41365721.js.LICENSE.txt rename to 06e8d299.4de3d633.js.LICENSE.txt diff --git a/072d4c63.41365721.js b/072d4c63.2e5516af.js similarity index 92% rename from 072d4c63.41365721.js rename to 072d4c63.2e5516af.js index 83f76d15be..18ed3254ca 100644 --- a/072d4c63.41365721.js +++ b/072d4c63.2e5516af.js @@ -1,2 +1,2 @@ -/*! For license information please see 072d4c63.41365721.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{159:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return o})),t.d(n,"metadata",(function(){return c})),t.d(n,"rightToc",(function(){return l})),t.d(n,"default",(function(){return p}));var a=t(1),r=t(9),i=(t(0),t(422)),o=(t(421),t(426),t(429),{last_modified_on:"2021-12-27",$schema:"/.meta/.schemas/guides.json",title:"Managing Environment Variables in React (create-react-app)",description:"How to manage environemnt variables in applications bootstrapped with create-react-app",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","language: javascript"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Managing Environment Variables in React (create-react-app)",description:"How to manage environemnt variables in applications bootstrapped with create-react-app",permalink:"/guides/tutorial/managing-env-variables-in-create-react-app",readingTime:"5 min read",source:"@site/guides/tutorial/managing-env-variables-in-create-react-app.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"language: javascript",permalink:"/guides/tags/language-javascript"}],title:"Managing Environment Variables in React (create-react-app)",truncated:!1,prevItem:{title:"Kubernetes observability and monitoring with Datadog",permalink:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog"},nextItem:{title:"Microservices",permalink:"/guides/advanced/microservices"}},l=[{value:"Code Repository",id:"code-repository",children:[]},{value:"Environment Variables",id:"environment-variables",children:[{value:"Warning!",id:"warning",children:[]}]},{value:"Deployment",id:"deployment",children:[]},{value:"Adding Environment Variable",id:"adding-environment-variable",children:[]},{value:"Going Prod",id:"going-prod",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],s={rightToc:l};function p(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},s,t,{components:n,mdxType:"MDXLayout"}),Object(i.b)("p",null,"In this short guide, we'll go trough managing Secrets/Environment Variables in React applications created using ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app")," and deployed on Qovery."),Object(i.b)("p",null,"Most of the guides you can find online propose quite complex solutions with creating your own bash scripts to set up env variables in apps created by ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app")," - this guide will show you an easier alternative and a way to Dockerize your React app in production-ready way."),Object(i.b)("h2",{id:"code-repository"},"Code Repository"),Object(i.b)("p",null,"In this guide we'll use ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/cra-test"}),"https://github.com/pjeziorowski/cra-test")," repository - it's a sample application bootstrapped using ",Object(i.b)("inlineCode",{parentName:"p"},"npx create-react-app my-app")," command."),Object(i.b)("p",null,"After the application structure is generated, we dockerize the application by adding a ",Object(i.b)("inlineCode",{parentName:"p"},"Dockerfile")," with the following content:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'# Docker Image which is used as foundation to create\n# a custom Docker Image with this Dockerfile\nFROM node:10\n\n# A directory within the virtualized Docker environment\nWORKDIR /usr/src/app\n\n# Copies package.json and package-lock.json to Docker environment\nCOPY package*.json ./\n\n# Installs all node packages\nRUN npm install\n\n# Copies everything over to Docker environment\nCOPY . .\n\n# Uses port which is used by the actual application\nEXPOSE 3000\n\n# Finally runs the application\nCMD [ "npm", "start" ]\n')),Object(i.b)("p",null,"One more little thing that we change is creating a new constant that uses a value of ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_MSG")," environment variable to print a text on the website:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const msg = process.env.REACT_APP_MSG\n")),Object(i.b)("p",null,"And then, we print it in the UI:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'\n {msg}\n\n')),Object(i.b)("h2",{id:"environment-variables"},"Environment Variables"),Object(i.b)("p",null,"Let's now add a ",Object(i.b)("inlineCode",{parentName:"p"},".env")," file for the default environment variables for our React app. For this, we create a ",Object(i.b)("inlineCode",{parentName:"p"},".env")," file with the content:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'HOST="0.0.0.0"\nPORT="3000"\nREACT_APP_MSG="From .env"\n')),Object(i.b)("h3",{id:"warning"},"Warning!"),Object(i.b)("p",null,"For all custom environment variables in apps created via ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app"),", we need to use ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_")," prefix in env var names - it's a requirement, if we don't follow the convention, variables will not be accessible in our application!"),Object(i.b)("p",null,"Also, remember that all the values are accessible on the client-side (browser). You should not use it for any data that your users should not access in the browser."),Object(i.b)("h2",{id:"deployment"},"Deployment"),Object(i.b)("p",null,"Before overriding the default env vars hardcoded in our repository using Qovery, let's first deploy the app."),Object(i.b)("p",null,"To do so, add a new application using the code from previous steps. When configuring the application, don't forget to:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Use ",Object(i.b)("inlineCode",{parentName:"li"},"Docker")," build mode"),Object(i.b)("li",{parentName:"ul"},"Add port ",Object(i.b)("inlineCode",{parentName:"li"},"3000")," to expose the app on the internet")),Object(i.b)("p",null,"After the application is created, click on the ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," button in application actions."),Object(i.b)("p",null,"In a few minutes, your application should be up and running:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/cra-envs/1.png",alt:"create-react-app environment variables"})),Object(i.b)("p",null,"As you see, the text in the link ",Object(i.b)("strong",{parentName:"p"},"From .env file indicates that the value")),Object(i.b)("h2",{id:"adding-environment-variable"},"Adding Environment Variable"),Object(i.b)("p",null,"Now, let's override our ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_MSG")," environment variable (and the text we display in the UI)."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/cra-envs/2.png",alt:"create-react-app environment variables"})),Object(i.b)("p",null,"After adding a new variable, restart the application. In a minute or so, we should see that the message in our website is updated with the value of ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_MSG")," we added in Qovery Console:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/cra-envs/3.png",alt:"create-react-app environment variables"})),Object(i.b)("h2",{id:"going-prod"},"Going Prod"),Object(i.b)("p",null,"To optimize our application for production usage, we\u2019ll use a Nginx server to serve our frontend static content. To do so, we need to update our Dockerfile to the following:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'FROM node:14-alpine AS builder\nENV NODE_ENV production\n\nARG REACT_APP_MSG\nENV REACT_APP_MSG $REACT_APP_MSG\n\n# Add a work directory\nWORKDIR /app\n# Cache and Install dependencies\nCOPY package.json .\nCOPY yarn.lock .\nRUN yarn install --production\n# Copy app files\nCOPY . .\n# Build the app\nRUN yarn build\n\n# Bundle static assets with nginx\nFROM nginx:1.21.0-alpine as production\nENV NODE_ENV production\n# Copy built assets from builder\nCOPY --from=builder /app/build /usr/share/nginx/html\n# Add your nginx.conf\nCOPY nginx.conf /etc/nginx/conf.d/default.conf\n# Expose port\nEXPOSE 3000\n# Start nginx\nCMD ["nginx", "-g", "daemon off;"]\n')),Object(i.b)("p",null,"It uses a Nginx server for hosting your application instead of starting a Node.js server, which is more optimal for production usage."),Object(i.b)("p",null,"Additionally, add a ",Object(i.b)("inlineCode",{parentName:"p"},"nginx.conf")," file with this content to configure your app:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"server {\n listen 80;\n\n location / {\n root /usr/share/nginx/html/;\n include /etc/nginx/mime.types;\n try_files $uri $uri/ /index.html;\n }\n}\n")),Object(i.b)("p",null,"Now, commit and push your changes - your ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app")," is handling env vars properly and is optimized for production usage."),Object(i.b)("h2",{id:"conclusion"},"Conclusion"),Object(i.b)("p",null,"In the guide, we went through managing environment variables in react / create-react-apps without resorting to using any bash scripts and host it on Qovery using Ngnix server."))}p.isMDXComponent=!0},420:function(e,n,t){var a;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=r.a.createContext({}),p=function(e){var n=r.a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):c({},n,{},e)),t},u=function(e){var n=p(e.components);return r.a.createElement(s.Provider,{value:n},e.children)},b={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},d=Object(a.forwardRef)((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=p(t),d=a,m=u["".concat(o,".").concat(d)]||u[d]||b[d]||i;return t?r.a.createElement(m,c({ref:n},s,{components:t})):r.a.createElement(m,c({ref:n},s))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=d;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,o[1]=c;for(var s=2;s1?arguments[1]:void 0,t),l=o>2?arguments[2]:void 0,s=void 0===l?t:r(l,t);s>c;)n[c++]=e;return n}},425:function(e,n,t){var a=t(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||t(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},426:function(e,n,t){"use strict";t(425);var a=t(0),r=t.n(a),i=t(421);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},427:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),c=t(430),l=t(20),s=t.n(l);n.a=function(e){var n,t=e.to,l=e.href,p=t||l,u=Object(c.a)(p),b=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&n&&n.disconnect()}}),[p,d,u]),p&&u?i.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(p),b.current=!0)},innerRef:function(e){var t,a;d&&e&&u&&(t=e,a=function(){window.docusaurus.prefetch(p)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),a())}))}))).observe(t))},to:p})):i.a.createElement("a",Object(a.a)({},e,{href:p}))}},429:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(427),o=t(420),c=t.n(o);t(133);n.a=function(e){var n=e.children,t=e.className,a=e.badge,o=e.leftIcon,l=e.rightIcon,s=e.size,p=e.target,u=e.to,b=c()("jump-to","jump-to--"+s,t),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},o&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+o})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",n),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:u,target:p,className:b},d):r.a.createElement(i.a,{to:u,className:b},d)}},430:function(e,n,t){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see 072d4c63.2e5516af.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{160:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return o})),t.d(n,"metadata",(function(){return c})),t.d(n,"rightToc",(function(){return l})),t.d(n,"default",(function(){return p}));var a=t(1),r=t(9),i=(t(0),t(425)),o=(t(424),t(429),t(431),{last_modified_on:"2021-12-27",$schema:"/.meta/.schemas/guides.json",title:"Managing Environment Variables in React (create-react-app)",description:"How to manage environemnt variables in applications bootstrapped with create-react-app",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","language: javascript"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Managing Environment Variables in React (create-react-app)",description:"How to manage environemnt variables in applications bootstrapped with create-react-app",permalink:"/guides/tutorial/managing-env-variables-in-create-react-app",readingTime:"5 min read",source:"@site/guides/tutorial/managing-env-variables-in-create-react-app.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"language: javascript",permalink:"/guides/tags/language-javascript"}],title:"Managing Environment Variables in React (create-react-app)",truncated:!1,prevItem:{title:"Kubernetes observability and monitoring with Datadog",permalink:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog"},nextItem:{title:"Microservices",permalink:"/guides/advanced/microservices"}},l=[{value:"Code Repository",id:"code-repository",children:[]},{value:"Environment Variables",id:"environment-variables",children:[{value:"Warning!",id:"warning",children:[]}]},{value:"Deployment",id:"deployment",children:[]},{value:"Adding Environment Variable",id:"adding-environment-variable",children:[]},{value:"Going Prod",id:"going-prod",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],s={rightToc:l};function p(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},s,t,{components:n,mdxType:"MDXLayout"}),Object(i.b)("p",null,"In this short guide, we'll go trough managing Secrets/Environment Variables in React applications created using ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app")," and deployed on Qovery."),Object(i.b)("p",null,"Most of the guides you can find online propose quite complex solutions with creating your own bash scripts to set up env variables in apps created by ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app")," - this guide will show you an easier alternative and a way to Dockerize your React app in production-ready way."),Object(i.b)("h2",{id:"code-repository"},"Code Repository"),Object(i.b)("p",null,"In this guide we'll use ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/cra-test"}),"https://github.com/pjeziorowski/cra-test")," repository - it's a sample application bootstrapped using ",Object(i.b)("inlineCode",{parentName:"p"},"npx create-react-app my-app")," command."),Object(i.b)("p",null,"After the application structure is generated, we dockerize the application by adding a ",Object(i.b)("inlineCode",{parentName:"p"},"Dockerfile")," with the following content:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'# Docker Image which is used as foundation to create\n# a custom Docker Image with this Dockerfile\nFROM node:10\n\n# A directory within the virtualized Docker environment\nWORKDIR /usr/src/app\n\n# Copies package.json and package-lock.json to Docker environment\nCOPY package*.json ./\n\n# Installs all node packages\nRUN npm install\n\n# Copies everything over to Docker environment\nCOPY . .\n\n# Uses port which is used by the actual application\nEXPOSE 3000\n\n# Finally runs the application\nCMD [ "npm", "start" ]\n')),Object(i.b)("p",null,"One more little thing that we change is creating a new constant that uses a value of ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_MSG")," environment variable to print a text on the website:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const msg = process.env.REACT_APP_MSG\n")),Object(i.b)("p",null,"And then, we print it in the UI:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'\n {msg}\n\n')),Object(i.b)("h2",{id:"environment-variables"},"Environment Variables"),Object(i.b)("p",null,"Let's now add a ",Object(i.b)("inlineCode",{parentName:"p"},".env")," file for the default environment variables for our React app. For this, we create a ",Object(i.b)("inlineCode",{parentName:"p"},".env")," file with the content:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'HOST="0.0.0.0"\nPORT="3000"\nREACT_APP_MSG="From .env"\n')),Object(i.b)("h3",{id:"warning"},"Warning!"),Object(i.b)("p",null,"For all custom environment variables in apps created via ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app"),", we need to use ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_")," prefix in env var names - it's a requirement, if we don't follow the convention, variables will not be accessible in our application!"),Object(i.b)("p",null,"Also, remember that all the values are accessible on the client-side (browser). You should not use it for any data that your users should not access in the browser."),Object(i.b)("h2",{id:"deployment"},"Deployment"),Object(i.b)("p",null,"Before overriding the default env vars hardcoded in our repository using Qovery, let's first deploy the app."),Object(i.b)("p",null,"To do so, add a new application using the code from previous steps. When configuring the application, don't forget to:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Use ",Object(i.b)("inlineCode",{parentName:"li"},"Docker")," build mode"),Object(i.b)("li",{parentName:"ul"},"Add port ",Object(i.b)("inlineCode",{parentName:"li"},"3000")," to expose the app on the internet")),Object(i.b)("p",null,"After the application is created, click on the ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," button in application actions."),Object(i.b)("p",null,"In a few minutes, your application should be up and running:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/cra-envs/1.png",alt:"create-react-app environment variables"})),Object(i.b)("p",null,"As you see, the text in the link ",Object(i.b)("strong",{parentName:"p"},"From .env file indicates that the value")),Object(i.b)("h2",{id:"adding-environment-variable"},"Adding Environment Variable"),Object(i.b)("p",null,"Now, let's override our ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_MSG")," environment variable (and the text we display in the UI)."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/cra-envs/2.png",alt:"create-react-app environment variables"})),Object(i.b)("p",null,"After adding a new variable, restart the application. In a minute or so, we should see that the message in our website is updated with the value of ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_MSG")," we added in Qovery Console:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/cra-envs/3.png",alt:"create-react-app environment variables"})),Object(i.b)("h2",{id:"going-prod"},"Going Prod"),Object(i.b)("p",null,"To optimize our application for production usage, we\u2019ll use a Nginx server to serve our frontend static content. To do so, we need to update our Dockerfile to the following:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'FROM node:14-alpine AS builder\nENV NODE_ENV production\n\nARG REACT_APP_MSG\nENV REACT_APP_MSG $REACT_APP_MSG\n\n# Add a work directory\nWORKDIR /app\n# Cache and Install dependencies\nCOPY package.json .\nCOPY yarn.lock .\nRUN yarn install --production\n# Copy app files\nCOPY . .\n# Build the app\nRUN yarn build\n\n# Bundle static assets with nginx\nFROM nginx:1.21.0-alpine as production\nENV NODE_ENV production\n# Copy built assets from builder\nCOPY --from=builder /app/build /usr/share/nginx/html\n# Add your nginx.conf\nCOPY nginx.conf /etc/nginx/conf.d/default.conf\n# Expose port\nEXPOSE 3000\n# Start nginx\nCMD ["nginx", "-g", "daemon off;"]\n')),Object(i.b)("p",null,"It uses a Nginx server for hosting your application instead of starting a Node.js server, which is more optimal for production usage."),Object(i.b)("p",null,"Additionally, add a ",Object(i.b)("inlineCode",{parentName:"p"},"nginx.conf")," file with this content to configure your app:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"server {\n listen 80;\n\n location / {\n root /usr/share/nginx/html/;\n include /etc/nginx/mime.types;\n try_files $uri $uri/ /index.html;\n }\n}\n")),Object(i.b)("p",null,"Now, commit and push your changes - your ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app")," is handling env vars properly and is optimized for production usage."),Object(i.b)("h2",{id:"conclusion"},"Conclusion"),Object(i.b)("p",null,"In the guide, we went through managing environment variables in react / create-react-apps without resorting to using any bash scripts and host it on Qovery using Ngnix server."))}p.isMDXComponent=!0},423:function(e,n,t){var a;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=r.a.createContext({}),p=function(e){var n=r.a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):c({},n,{},e)),t},u=function(e){var n=p(e.components);return r.a.createElement(s.Provider,{value:n},e.children)},b={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},d=Object(a.forwardRef)((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=p(t),d=a,m=u["".concat(o,".").concat(d)]||u[d]||b[d]||i;return t?r.a.createElement(m,c({ref:n},s,{components:t})):r.a.createElement(m,c({ref:n},s))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=d;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,o[1]=c;for(var s=2;s1?arguments[1]:void 0,t),l=o>2?arguments[2]:void 0,s=void 0===l?t:r(l,t);s>c;)n[c++]=e;return n}},428:function(e,n,t){var a=t(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||t(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,n,t){"use strict";t(428);var a=t(0),r=t.n(a),i=t(424);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},430:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),c=t(432),l=t(20),s=t.n(l);n.a=function(e){var n,t=e.to,l=e.href,p=t||l,u=Object(c.a)(p),b=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&n&&n.disconnect()}}),[p,d,u]),p&&u?i.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(p),b.current=!0)},innerRef:function(e){var t,a;d&&e&&u&&(t=e,a=function(){window.docusaurus.prefetch(p)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),a())}))}))).observe(t))},to:p})):i.a.createElement("a",Object(a.a)({},e,{href:p}))}},431:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(430),o=t(423),c=t.n(o);t(133);n.a=function(e){var n=e.children,t=e.className,a=e.badge,o=e.leftIcon,l=e.rightIcon,s=e.size,p=e.target,u=e.to,b=c()("jump-to","jump-to--"+s,t),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},o&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+o})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",n),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:u,target:p,className:b},d):r.a.createElement(i.a,{to:u,className:b},d)}},432:function(e,n,t){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/073aa0b0.eb6363a9.js.LICENSE.txt b/072d4c63.2e5516af.js.LICENSE.txt similarity index 100% rename from 073aa0b0.eb6363a9.js.LICENSE.txt rename to 072d4c63.2e5516af.js.LICENSE.txt diff --git a/073aa0b0.eb6363a9.js b/073aa0b0.a27b4c34.js similarity index 92% rename from 073aa0b0.eb6363a9.js rename to 073aa0b0.a27b4c34.js index 1b906b0895..e81478ae9b 100644 --- a/073aa0b0.eb6363a9.js +++ b/073aa0b0.a27b4c34.js @@ -1,2 +1,2 @@ -/*! For license information please see 073aa0b0.eb6363a9.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{160:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return p}));var i=n(1),r=n(9),o=(n(0),n(422)),a=(n(429),n(421)),c=(n(426),{last_modified_on:"2023-07-11",title:"Service Health Checks",description:"Learn how to configure your Kubernetes health checks"}),s={id:"using-qovery/configuration/service-health-checks",title:"Service Health Checks",description:"Learn how to configure your Kubernetes health checks",source:"@site/docs/using-qovery/configuration/service-health-checks.md",permalink:"/docs/using-qovery/configuration/service-health-checks",sidebar:"docs",previous:{title:"Environment Variable & Secrets",permalink:"/docs/using-qovery/configuration/environment-variable"},next:{title:"Service Advanced Settings",permalink:"/docs/using-qovery/configuration/advanced-settings"}},l=[{value:"Probes Configuration",id:"probes-configuration",children:[{value:"Type",id:"type",children:[]},{value:"Initial Delay (in seconds)",id:"initial-delay-in-seconds",children:[]},{value:"Period (in seconds)",id:"period-in-seconds",children:[]},{value:"Timeout (in seconds)",id:"timeout-in-seconds",children:[]},{value:"Success Threshold",id:"success-threshold",children:[]},{value:"Failure Threshold",id:"failure-threshold",children:[]}]},{value:"Configuiration for Long-starting application",id:"configuiration-for-long-starting-application",children:[]}],u={rightToc:l};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(i.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Health checks are automatic procedures checking the status of your application, deciding if it is ready to receive traffic or if it needs to be restarted. Since Qovery relies on Kubernetes to deploy and run your application, we use the Kubernetes probes to regularly verify the status of your application during the deployment and/or running phases."),Object(o.b)("p",null,"Kubernetes allows you to configure two probes:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Liveness probe"),": to check if the application container is alive (passing) or dead (failing). If the check fails, the dead container is restarted to attempt to heal the application. For example, liveness probes could catch a deadlock, where an application is running, but unable to make progress. Restarting a container in such a state can help to make the application more available despite bugs."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Readiness probe"),": to check if the application container is ready to receive requests (as even alive containers can enter phases where they cannot handle incoming traffic). Kubernetes only routes traffic to the application if the check succeeds. One use of this signal is to control which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balancers.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/advanced-settings/workflow.png",alt:"Kubernetes Probes Workflow"})),Object(o.b)("p",null,"During the deployment phase, the liveness and readiness probes play an important role on determining if the deployment succeeds or not. If you have both the liveness and readiness probes configured, both of them need to succeed before considering the deployment to be completed successfully. "),Object(o.b)("p",null,"Example:\nYou have a liveness probe configured on port 80 of your application. If during the deployment of your application the probes can't connect to port 80 and we reach a timeout, the deployment fails."),Object(o.b)("p",null,"Qovery allows you to manage these probes directly from within the Qovery console during the setup of your application, letting you decide their activation, configuration and check frequency."),Object(o.b)("p",null,"Probes can be configured for:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Applications"),Object(o.b)("li",{parentName:"ul"},"Cronjobs"),Object(o.b)("li",{parentName:"ul"},"Lifecycle Jobs")),Object(o.b)("h2",{id:"probes-configuration"},"Probes Configuration"),Object(o.b)("p",null,"The following configuration parameters are valid for both the Liveness and the Readiness probes."),Object(o.b)("h3",{id:"type"},"Type"),Object(o.b)("p",null,"Allows you to specify the type of probe you want to run against your application:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"NONE")," if ",Object(o.b)("inlineCode",{parentName:"li"},"NONE")," is selected, the probe is disabled and thus Kubernetes won't be able to verify the state of your application and take the right corrective actions. ")),Object(o.b)(a.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"We strongly advise to not disable the liveness probe.")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"HTTP probes")," are the most common probe type. You can use them if your application is a HTTP server, or if you create a lightweight HTTP server inside your application specifically to respond to such probes. When using a HTTP probe, you need to configure: "),Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"a port"),Object(o.b)("li",{parentName:"ul"},"a path\nOnce configured, Kubernetes pings a path (for example: ",Object(o.b)("inlineCode",{parentName:"li"},"/healthz "),") at a given port. If it gets a response in the 200 or 300 range, the check is passed. Otherwise, it is considered as failed and Kubernetes takes the necessary corrective actions."))),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"TCP probes")," are most often used when HTTP or command probes aren't an option. When using a TCP Liveness probe, Kubernetes tries to establish a connection on the specified port. If the connection is successful, the application is considered healthy. Otherwise, it is considered dead and the container is restarted.")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"gRPC probes"),"\nWhen using a gRCP Liveness probe, Kubernetes tries to establish a connection on the specified port and service. If the connection is successful, the application is considered healthy. Otherwise, it is considered dead and the container is restarted.")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"EXEC probes"),"\nExec probes allow to define a command to be executed within your container. If the command execution fails, the probe is considered as failed."))),Object(o.b)("h3",{id:"initial-delay-in-seconds"},"Initial Delay (in seconds)"),Object(o.b)("p",null,"Allows you to specify an interval, in seconds, between the application container start and the first liveness check.\t"),Object(o.b)("p",null,"Allowing additional time for the application to start can be useful when boot time usually takes too long (due to long boot operations), or when the application opens the port before being ready to receive traffic on it (due to a still ongoing boot operation).\t"),Object(o.b)("h3",{id:"period-in-seconds"},"Period (in seconds)"),Object(o.b)("p",null,"Allows you to specify an interval, in seconds, between each probe.\t"),Object(o.b)("h3",{id:"timeout-in-seconds"},"Timeout (in seconds)"),Object(o.b)("p",null,"Allows you to specify the interval, in seconds, after which the probe times out.\t"),Object(o.b)("h3",{id:"success-threshold"},"Success Threshold"),Object(o.b)("p",null,"Allows you to specify how many consecutive successes are needed, as a minimum, for the probe to be considered successful after having failed previously."),Object(o.b)(a.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Due to a Kubernetes limitation, this value can only be 1")),Object(o.b)("h3",{id:"failure-threshold"},"Failure Threshold"),Object(o.b)("p",null,"Allows you to specify how many consecutive failures are needed, as a minimum, for the probe to be considered failed after having succeeded previously."),Object(o.b)("h2",{id:"configuiration-for-long-starting-application"},"Configuiration for Long-starting application"),Object(o.b)("p",null,"If your application has a long boot operation to run, your deployment might be marked as failed since the probe can't verify the state of your application within the specified time frame. In this case, you will find in your deployment logs a warning message ",Object(o.b)("inlineCode",{parentName:"p"},"Liveness probe failed: dial tcp xx.xx.xx.xx:xx: connect: connection refused")," , telling you that the probe is failing."),Object(o.b)("p",null,"If your application needs more time to boot, increase the ",Object(o.b)("inlineCode",{parentName:"p"},"Initial Delay in seconds")," of the probes to match the application boot time."),Object(o.b)(a.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Startup probes are not yet available. ")))}p.isMDXComponent=!0},420:function(e,t,n){var i;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),u=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(i.forwardRef)((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,a=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),d=i,f=p["".concat(a,".").concat(d)]||p[d]||b[d]||o;return n?r.a.createElement(f,c({ref:t},l,{components:n})):r.a.createElement(f,c({ref:t},l))}));function f(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,a=new Array(o);a[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:i,a[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=a>2?arguments[2]:void 0,l=void 0===s?n:r(s,n);l>c;)t[c++]=e;return t}},425:function(e,t,n){var i=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&i(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var i=n(0),r=n.n(i),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var i=n(1),r=n(0),o=n.n(r),a=n(39),c=n(430),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,p=Object(c.a)(u),b=Object(r.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?o.a.createElement(a.b,Object(i.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,i;d&&e&&p&&(n=e,i=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),i())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(i.a)({},e,{href:u}))}},429:function(e,t,n){"use strict";var i=n(0),r=n.n(i),o=n(427),a=n(420),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.className,i=e.badge,a=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+l,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},a&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+a})),r.a.createElement("div",{className:"jump-to--main"},i?r.a.createElement("span",{className:"badge badge--primary badge--right"},i):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:p,target:u,className:b},d):r.a.createElement(o.a,{to:p,className:b},d)}},430:function(e,t,n){"use strict";function i(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return i}))}}]); \ No newline at end of file +/*! For license information please see 073aa0b0.a27b4c34.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{161:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return p}));var i=n(1),r=n(9),o=(n(0),n(425)),a=(n(431),n(424)),c=(n(429),{last_modified_on:"2023-07-11",title:"Service Health Checks",description:"Learn how to configure your Kubernetes health checks"}),s={id:"using-qovery/configuration/service-health-checks",title:"Service Health Checks",description:"Learn how to configure your Kubernetes health checks",source:"@site/docs/using-qovery/configuration/service-health-checks.md",permalink:"/docs/using-qovery/configuration/service-health-checks",sidebar:"docs",previous:{title:"Environment Variable & Secrets",permalink:"/docs/using-qovery/configuration/environment-variable"},next:{title:"Service Advanced Settings",permalink:"/docs/using-qovery/configuration/advanced-settings"}},l=[{value:"Probes Configuration",id:"probes-configuration",children:[{value:"Type",id:"type",children:[]},{value:"Initial Delay (in seconds)",id:"initial-delay-in-seconds",children:[]},{value:"Period (in seconds)",id:"period-in-seconds",children:[]},{value:"Timeout (in seconds)",id:"timeout-in-seconds",children:[]},{value:"Success Threshold",id:"success-threshold",children:[]},{value:"Failure Threshold",id:"failure-threshold",children:[]}]},{value:"Configuiration for Long-starting application",id:"configuiration-for-long-starting-application",children:[]}],u={rightToc:l};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(i.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Health checks are automatic procedures checking the status of your application, deciding if it is ready to receive traffic or if it needs to be restarted. Since Qovery relies on Kubernetes to deploy and run your application, we use the Kubernetes probes to regularly verify the status of your application during the deployment and/or running phases."),Object(o.b)("p",null,"Kubernetes allows you to configure two probes:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Liveness probe"),": to check if the application container is alive (passing) or dead (failing). If the check fails, the dead container is restarted to attempt to heal the application. For example, liveness probes could catch a deadlock, where an application is running, but unable to make progress. Restarting a container in such a state can help to make the application more available despite bugs."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Readiness probe"),": to check if the application container is ready to receive requests (as even alive containers can enter phases where they cannot handle incoming traffic). Kubernetes only routes traffic to the application if the check succeeds. One use of this signal is to control which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balancers.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/advanced-settings/workflow.png",alt:"Kubernetes Probes Workflow"})),Object(o.b)("p",null,"During the deployment phase, the liveness and readiness probes play an important role on determining if the deployment succeeds or not. If you have both the liveness and readiness probes configured, both of them need to succeed before considering the deployment to be completed successfully. "),Object(o.b)("p",null,"Example:\nYou have a liveness probe configured on port 80 of your application. If during the deployment of your application the probes can't connect to port 80 and we reach a timeout, the deployment fails."),Object(o.b)("p",null,"Qovery allows you to manage these probes directly from within the Qovery console during the setup of your application, letting you decide their activation, configuration and check frequency."),Object(o.b)("p",null,"Probes can be configured for:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Applications"),Object(o.b)("li",{parentName:"ul"},"Cronjobs"),Object(o.b)("li",{parentName:"ul"},"Lifecycle Jobs")),Object(o.b)("h2",{id:"probes-configuration"},"Probes Configuration"),Object(o.b)("p",null,"The following configuration parameters are valid for both the Liveness and the Readiness probes."),Object(o.b)("h3",{id:"type"},"Type"),Object(o.b)("p",null,"Allows you to specify the type of probe you want to run against your application:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"NONE")," if ",Object(o.b)("inlineCode",{parentName:"li"},"NONE")," is selected, the probe is disabled and thus Kubernetes won't be able to verify the state of your application and take the right corrective actions. ")),Object(o.b)(a.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"We strongly advise to not disable the liveness probe.")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"HTTP probes")," are the most common probe type. You can use them if your application is a HTTP server, or if you create a lightweight HTTP server inside your application specifically to respond to such probes. When using a HTTP probe, you need to configure: "),Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"a port"),Object(o.b)("li",{parentName:"ul"},"a path\nOnce configured, Kubernetes pings a path (for example: ",Object(o.b)("inlineCode",{parentName:"li"},"/healthz "),") at a given port. If it gets a response in the 200 or 300 range, the check is passed. Otherwise, it is considered as failed and Kubernetes takes the necessary corrective actions."))),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"TCP probes")," are most often used when HTTP or command probes aren't an option. When using a TCP Liveness probe, Kubernetes tries to establish a connection on the specified port. If the connection is successful, the application is considered healthy. Otherwise, it is considered dead and the container is restarted.")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"gRPC probes"),"\nWhen using a gRCP Liveness probe, Kubernetes tries to establish a connection on the specified port and service. If the connection is successful, the application is considered healthy. Otherwise, it is considered dead and the container is restarted.")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"EXEC probes"),"\nExec probes allow to define a command to be executed within your container. If the command execution fails, the probe is considered as failed."))),Object(o.b)("h3",{id:"initial-delay-in-seconds"},"Initial Delay (in seconds)"),Object(o.b)("p",null,"Allows you to specify an interval, in seconds, between the application container start and the first liveness check.\t"),Object(o.b)("p",null,"Allowing additional time for the application to start can be useful when boot time usually takes too long (due to long boot operations), or when the application opens the port before being ready to receive traffic on it (due to a still ongoing boot operation).\t"),Object(o.b)("h3",{id:"period-in-seconds"},"Period (in seconds)"),Object(o.b)("p",null,"Allows you to specify an interval, in seconds, between each probe.\t"),Object(o.b)("h3",{id:"timeout-in-seconds"},"Timeout (in seconds)"),Object(o.b)("p",null,"Allows you to specify the interval, in seconds, after which the probe times out.\t"),Object(o.b)("h3",{id:"success-threshold"},"Success Threshold"),Object(o.b)("p",null,"Allows you to specify how many consecutive successes are needed, as a minimum, for the probe to be considered successful after having failed previously."),Object(o.b)(a.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Due to a Kubernetes limitation, this value can only be 1")),Object(o.b)("h3",{id:"failure-threshold"},"Failure Threshold"),Object(o.b)("p",null,"Allows you to specify how many consecutive failures are needed, as a minimum, for the probe to be considered failed after having succeeded previously."),Object(o.b)("h2",{id:"configuiration-for-long-starting-application"},"Configuiration for Long-starting application"),Object(o.b)("p",null,"If your application has a long boot operation to run, your deployment might be marked as failed since the probe can't verify the state of your application within the specified time frame. In this case, you will find in your deployment logs a warning message ",Object(o.b)("inlineCode",{parentName:"p"},"Liveness probe failed: dial tcp xx.xx.xx.xx:xx: connect: connection refused")," , telling you that the probe is failing."),Object(o.b)("p",null,"If your application needs more time to boot, increase the ",Object(o.b)("inlineCode",{parentName:"p"},"Initial Delay in seconds")," of the probes to match the application boot time."),Object(o.b)(a.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Startup probes are not yet available. ")))}p.isMDXComponent=!0},423:function(e,t,n){var i;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),u=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(i.forwardRef)((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,a=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),d=i,f=p["".concat(a,".").concat(d)]||p[d]||b[d]||o;return n?r.a.createElement(f,c({ref:t},l,{components:n})):r.a.createElement(f,c({ref:t},l))}));function f(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,a=new Array(o);a[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:i,a[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=a>2?arguments[2]:void 0,l=void 0===s?n:r(s,n);l>c;)t[c++]=e;return t}},428:function(e,t,n){var i=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&i(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var i=n(0),r=n.n(i),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var i=n(1),r=n(0),o=n.n(r),a=n(39),c=n(432),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,p=Object(c.a)(u),b=Object(r.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?o.a.createElement(a.b,Object(i.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,i;d&&e&&p&&(n=e,i=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),i())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(i.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var i=n(0),r=n.n(i),o=n(430),a=n(423),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.className,i=e.badge,a=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+l,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},a&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+a})),r.a.createElement("div",{className:"jump-to--main"},i?r.a.createElement("span",{className:"badge badge--primary badge--right"},i):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:p,target:u,className:b},d):r.a.createElement(o.a,{to:p,className:b},d)}},432:function(e,t,n){"use strict";function i(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return i}))}}]); \ No newline at end of file diff --git a/07c2f310.524d67dd.js.LICENSE.txt b/073aa0b0.a27b4c34.js.LICENSE.txt similarity index 100% rename from 07c2f310.524d67dd.js.LICENSE.txt rename to 073aa0b0.a27b4c34.js.LICENSE.txt diff --git a/07c2f310.524d67dd.js b/07c2f310.1a5bde23.js similarity index 98% rename from 07c2f310.524d67dd.js rename to 07c2f310.1a5bde23.js index 24062ca99e..8043b5d52f 100644 --- a/07c2f310.524d67dd.js +++ b/07c2f310.1a5bde23.js @@ -1,2 +1,2 @@ -/*! For license information please see 07c2f310.524d67dd.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{161:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return o})),a.d(t,"metadata",(function(){return c})),a.d(t,"rightToc",(function(){return p})),a.d(t,"default",(function(){return u}));var n=a(1),r=a(9),i=(a(0),a(422)),l=a(421),b=a(431),o={last_modified_on:"2023-05-29",title:"Environment Variable & Secrets",description:"Learn how to configure Environment Variables and Secrets on Qovery"},c={id:"using-qovery/configuration/environment-variable",title:"Environment Variable & Secrets",description:"Learn how to configure Environment Variables and Secrets on Qovery",source:"@site/docs/using-qovery/configuration/environment-variable.md",permalink:"/docs/using-qovery/configuration/environment-variable",sidebar:"docs",previous:{title:"Lifecycle Job",permalink:"/docs/using-qovery/configuration/lifecycle-job"},next:{title:"Service Health Checks",permalink:"/docs/using-qovery/configuration/service-health-checks"}},p=[{value:"Environment variable vs Environment variable as file",id:"environment-variable-vs-environment-variable-as-file",children:[{value:"Environment Variable",id:"environment-variable",children:[]},{value:"Environment Variable as file",id:"environment-variable-as-file",children:[]}]},{value:"Scopes",id:"scopes",children:[]},{value:"BUILT_IN variables",id:"built_in-variables",children:[]},{value:"Aliases and overrides",id:"aliases-and-overrides",children:[]},{value:"Variables Interpolation",id:"variables-interpolation",children:[]},{value:"Naming Rules",id:"naming-rules",children:[]},{value:"Create an Environment Variable",id:"create-an-environment-variable",children:[]},{value:"Delete an Environment Variable",id:"delete-an-environment-variable",children:[]},{value:"Update an Environment Variable",id:"update-an-environment-variable",children:[]},{value:"Override Environment Variable",id:"override-environment-variable",children:[]},{value:"Alias Environment Variable",id:"alias-environment-variable",children:[]},{value:"Import environment variables",id:"import-environment-variables",children:[{value:"Importation conflicts",id:"importation-conflicts",children:[]},{value:"Overwriting and limitations",id:"overwriting-and-limitations",children:[]}]},{value:"Service interconnection",id:"service-interconnection",children:[{value:"Connecting to a database",id:"connecting-to-a-database",children:[]},{value:"Connecting to another application",id:"connecting-to-another-application",children:[]}]}],s={rightToc:p};function u(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(n.a)({},s,a,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Qovery makes ",Object(i.b)("strong",{parentName:"p"},"Environment Variables")," available to your services at runtime, as well as during builds and deploys."),Object(i.b)("p",null,"If your projects and applications rely on sensitive data like credentials, API keys, certificates, Qovery offers you a way to store them as a ",Object(i.b)("strong",{parentName:"p"},"Secret"),". Secrets are special environment variable safely encrypted, and their values can not be retrieved via Qovery API - they are only accessible for your application during build and runtime."),Object(i.b)("p",null,"Qovery automatically generates for you some special environment variable (called BUILT_IN) which allows you to setup your service interconnection. See the ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"#built_in-variables"}),"BUILT_IN Section")," section."),Object(i.b)("h1",{id:"environment-variable-definition"},"Environment Variable definition"),Object(i.b)("p",null,"An environment variable is defined by:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"A type: two types are supported today",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Variable"),": classic key/value pairs where the ",Object(i.b)("inlineCode",{parentName:"li"},"value")," can be retrieved at build and run time by using its ",Object(i.b)("inlineCode",{parentName:"li"},"name")," (key). Example: Key = ",Object(i.b)("inlineCode",{parentName:"li"},"THIRD_PARTY_URL"),", Value = ",Object(i.b)("inlineCode",{parentName:"li"},"https://mythirdparty.com")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Variable as File"),": key/value/path triplets where the ",Object(i.b)("inlineCode",{parentName:"li"},"value")," will be stored as a file on the specified ",Object(i.b)("inlineCode",{parentName:"li"},"path"),". Your application can then retrieve the ",Object(i.b)("inlineCode",{parentName:"li"},"path")," of the file at run\ntime by using the variable ",Object(i.b)("inlineCode",{parentName:"li"},"name")," (key). Only text files are supported. Example: Key = ",Object(i.b)("inlineCode",{parentName:"li"},"MY_CONFIG"),", Path = ",Object(i.b)("inlineCode",{parentName:"li"},"/tmp/config.json")," Value = ",Object(i.b)("inlineCode",{parentName:"li"},'{"key1":"value1","key2":"value2"}')))),Object(i.b)("li",{parentName:"ul"},"A ",Object(i.b)("strong",{parentName:"li"},"scope"),": the accessibility level of this variable: application, environment, project (see ",Object(i.b)("a",Object(n.a)({parentName:"li"},{href:"#scopes"}),"scopes section")," below) "),Object(i.b)("li",{parentName:"ul"},"A ",Object(i.b)("strong",{parentName:"li"},"secret flag"),": it determines if the variable value needs to be encrypted and should be accessed ONLY by your applications (no access via the API/UI)")),Object(i.b)("h2",{id:"environment-variable-vs-environment-variable-as-file"},"Environment variable vs Environment variable as file"),Object(i.b)("p",null,"Depending on your use case, you might decide to use a simple key value environment variable or instead use the environment variable as a file."),Object(i.b)("h3",{id:"environment-variable"},"Environment Variable"),Object(i.b)("p",null,"If you need to store a simple value that needs to be retrieved at build or run time, than you can use a key/value environment variable"),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Example"),":\nYou have a 3rd party application running on the endpoint ",Object(i.b)("inlineCode",{parentName:"p"},"https://mythirdparty.com"),". You can create an environment variable called ",Object(i.b)("inlineCode",{parentName:"p"},"THIRD_PARTY_URL")," that will contain the 3rd party URL:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/env_key_value.png",alt:"Variable"})),Object(i.b)("p",null,"Your application will then be able to retrieve the url by getting the value of the environment variable ",Object(i.b)("inlineCode",{parentName:"p"},"THIRD_PARTY_URL"),"."),Object(i.b)("h3",{id:"environment-variable-as-file"},"Environment Variable as file"),Object(i.b)("p",null,"If your application needs to load configuration files at run time, than you can use the environment variable as file."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Example"),":\nGrafana allows you to override the default configuration by setting a few environment variables pointing to your own configuration files. By default, the variable ",Object(i.b)("inlineCode",{parentName:"p"},"GF_PATHS_CONFIG")," points to '/etc/grafana/grafana.ini' but in case you want to specify a different configuration, you can create an environment variable as file like this:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/env_file.png",alt:"Variable as file"})),Object(i.b)("p",null,"When the grafana container will load the env var ",Object(i.b)("inlineCode",{parentName:"p"},"GF_PATHS_CONFIG"),", it will retrieve the path where the configuration file is stored and load its content."),Object(i.b)("h2",{id:"scopes"},"Scopes"),Object(i.b)("p",null,"The scope of a variable allows you to define at which level this environment variable can be accessed (e.g. : only by one specific service). "),Object(i.b)("p",null,"There are three scopes for the Environment Variables:"),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Scope"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Level"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"PROJECT")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"1"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Variables at the project level are shared across all environments and all applications of the project")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"ENVIRONMENT")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"2"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Variables at the environment level are shared across all applications of the project in one, given environment")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"APPLICATION")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"3"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Variables available for one application in one environment")))),Object(i.b)("h2",{id:"built_in-variables"},"BUILT_IN variables"),Object(i.b)("p",null,"Qovery automatically generates some variables (called BUILT_IN) which allow you to easily configure your service interconnection or to access some of the environment/application information."),Object(i.b)("p",null,"By default, every environment contains the following BUILT_IN variables:"),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Name"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_PROJECT_ID")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Current project ID")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_ENVIRONMENT_ID")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Current environment ID")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_APPLICATION_ID")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Current service ID (for application with source = git repository)")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_CONTAINER_ID")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Current service ID (for application with source = container registry)")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_JOB_ID")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Current service ID (for lifecycle job and cronjob)")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_CLOUD_PROVIDER_REGION")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Cloud provider region of the Kubernetes cluster running this environment")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_KUBERNETES_NAMESPACE_NAME")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Namespace used in Kubernetes to run the application of this environment")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_KUBERNETES_CLUSTER_NAME")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Name of the Kubernetes cluster running this environment")))),Object(i.b)("p",null,"For any service within your environment (database, application, job), your application get access to a set of BUILT_IN variables. These can be used, to configure the interconnection between your services."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Naming Convention"),":"),Object(i.b)("p",null,"We use the following naming convention for additional built-in variables:"),Object(i.b)("pre",null,Object(i.b)("code",Object(n.a)({parentName:"pre"},{}),"QOVERY___\n")),Object(i.b)("p",null,"For more information on how to use the BUILT_IN environment variables to:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"connect to a database, have a look at ",Object(i.b)("a",Object(n.a)({parentName:"li"},{href:"#connecting-to-a-database"}),"this section"),"."),Object(i.b)("li",{parentName:"ul"},"connect to another service, have a look at ",Object(i.b)("a",Object(n.a)({parentName:"li"},{href:"#connecting-to-another-application"}),"this section"),".")),Object(i.b)("h2",{id:"aliases-and-overrides"},"Aliases and overrides"),Object(i.b)("p",null,"For a given environment variable, you can create aliases and overrides:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Alias: it defines an alias for the environment variable. You can access its value by its original name or by its alias name. "),Object(i.b)("li",{parentName:"ul"},"Override: it overrides the value of the environment variable. Example: you have an environment variable with scope = project having a particular value but you want to define a special value only for one environment. Instead of creating a separate environment variable only for that project, you can create an override of that variable within the environment requiring the special value.")),Object(i.b)("h2",{id:"variables-interpolation"},"Variables Interpolation"),Object(i.b)("p",null,"You can define an environment variable as a composition of text and other environment variables value (environment variables interpolation).\nFor example, you can define your APP_URL environment variable as a composition of your HOST_URL and HOST_PORT in this way:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Name = APP_URL"),Object(i.b)("li",{parentName:"ul"},"Value = ",Object(i.b)("inlineCode",{parentName:"li"},"https://{{HOST_URL}}:{{HOST_PORT}}"))),Object(i.b)("p",null,"Important information on this feature:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"the pattern used is ",Object(i.b)("inlineCode",{parentName:"li"},"{{VAR_NAME}}")),Object(i.b)("li",{parentName:"ul"},"if a referenced variable doesn't exist, it is replaced by an empty string"),Object(i.b)("li",{parentName:"ul"},"composition coherency using built in variables is kept when cloning an environment. Example: you can create a variable APP_URL = ",Object(i.b)("a",Object(n.a)({parentName:"li"},{href:"https://%7B%7BQOVERY_APPLICATION_ZEC0A2975_HOST_INTERNAL%7D%7D"}),"https://{{QOVERY_APPLICATION_ZEC0A2975_HOST_INTERNAL}}"),' and when the environment is cloned, the "ZEC0A2975" is replaced with the right ID.'),Object(i.b)("li",{parentName:"ul"},"there is no check at creation / edition / deletion if the referenced variable doesn't exist"),Object(i.b)("li",{parentName:"ul"},'"inner replacements" are not supported (e.g VAR_1 = {{VAR_2}} and VAR_2={{VAR_3}} )')),Object(i.b)("h2",{id:"naming-rules"},"Naming Rules"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Environment variable name should use only alphanumeric characters and the underscore character (_) to ensure they are accessible from all programming languages. Environment variable keys should not include the hyphen character."),Object(i.b)("li",{parentName:"ul"},"Environment variable name should not begin with a double underscore (__)."),Object(i.b)("li",{parentName:"ul"},"An environment variable\u2019s name should not begin with QOVERY_ unless it is set by the Qovery platform itself.")),Object(i.b)("h2",{id:"create-an-environment-variable"},"Create an Environment Variable"),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Do you want to bulk import your Environment Variables or Secrets? ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli/"}),"Check out this tutorial"))),Object(i.b)(b.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,"Select your project, environment and application")),Object(i.b)("li",null,Object(i.b)("p",null,"Select ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variables")," tab in the left panel and click ",Object(i.b)("inlineCode",{parentName:"p"},"New Variable")," button. Select if you want to create a classic environment variable or an environment variable as file."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/var_creation_1.png",alt:"Variables"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Select the name, value and scope of your new environment variable"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/var_creation_2.png",alt:"Variables"})),Object(i.b)("p",null,"If the variable you are trying to create is a Variable as File, define the ",Object(i.b)("inlineCode",{parentName:"p"},"Path")," where the file should be stored. Remember that in this case the ",Object(i.b)("inlineCode",{parentName:"p"},"Value")," field should contain the content of your file.\nIf the variable you are trying to create is a Secret, select the ",Object(i.b)("inlineCode",{parentName:"p"},"Secret")," checkbox.")))),Object(i.b)("h2",{id:"delete-an-environment-variable"},"Delete an Environment Variable"),Object(i.b)(b.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,"Select your project, environment and application")),Object(i.b)("li",null,Object(i.b)("p",null,"Select the ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variables")," tab in the left panel")),Object(i.b)("li",null,Object(i.b)("p",null,"Select variable you want to delete and click the ",Object(i.b)("inlineCode",{parentName:"p"},"Delete")," button from the submenu:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/var_delete.png",alt:"Delete Variables"}))))),Object(i.b)("h2",{id:"update-an-environment-variable"},"Update an Environment Variable"),Object(i.b)(b.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,"Select your project, environment and application")),Object(i.b)("li",null,Object(i.b)("p",null,"Select the ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variables")," tab in the left panel")),Object(i.b)("li",null,Object(i.b)("p",null,"Select variable you want to update and click the ",Object(i.b)("inlineCode",{parentName:"p"},"Edit")," button from the submenu:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/var_edit.png",alt:"Update Variables"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Update the variable in the popup window"),Object(i.b)("p",null,"Note: if the variable is a Secret, you won't be able to see its value")))),Object(i.b)("h2",{id:"override-environment-variable"},"Override Environment Variable"),Object(i.b)("p",null,"If you want to override a value of an environment variable, follow those steps:"),Object(i.b)(b.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,"Select your project, environment and application")),Object(i.b)("li",null,Object(i.b)("p",null,"Select the ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variables")," tab in the left panel")),Object(i.b)("li",null,Object(i.b)("p",null,"Select variable you want to override and click the ",Object(i.b)("inlineCode",{parentName:"p"},"Override")," button from the submenu")),Object(i.b)("li",null,Object(i.b)("p",null,"Select the override the variable and its scope in the popup window")))),"\\",Object(i.b)(l.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"You can only override environment variables of a higher scope, e.g. ",Object(i.b)("strong",{parentName:"p"},"Environment")," scope variable can override ",Object(i.b)("strong",{parentName:"p"},"Project")," variable, but can't override ",Object(i.b)("strong",{parentName:"p"},"Application")," variable.")),Object(i.b)("h2",{id:"alias-environment-variable"},"Alias Environment Variable"),Object(i.b)("p",null,"You can create an alias for the existing environment variable."),Object(i.b)("p",null,"Let's suppose that your application requires a ",Object(i.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," variable. Qovery provides your application with the ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_DATABASE_MY_POSTGRESQL_3498225_URL")," variable with a database password.\nInstead of copy-pasting its value, you can create an alias to ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_DATABASE_MY_POSTGRESQL_3498225_URL"),"."),Object(i.b)(b.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,"Select your project, environment and application")),Object(i.b)("li",null,Object(i.b)("p",null,"Select the ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variables")," tab in the left panel")),Object(i.b)("li",null,Object(i.b)("p",null,"Select variable you want to alias and click the ",Object(i.b)("inlineCode",{parentName:"p"},"Alias")," button from the submenu:")),Object(i.b)("li",null,Object(i.b)("p",null,"Define the alias of the variable and its scope in the popup window")))),Object(i.b)("h2",{id:"import-environment-variables"},"Import environment variables"),Object(i.b)("p",null,"You can add a set of environment variables into Qovery by importing an ",Object(i.b)("inlineCode",{parentName:"p"},".env")," file. The ",Object(i.b)("inlineCode",{parentName:"p"},".env")," file contains a list of your environment variables, in a ",Object(i.b)("inlineCode",{parentName:"p"},"MY_KEY = VALUE")," format."),Object(i.b)("p",null,"To import environment variables into your Qovery environment, follow the steps below."),Object(i.b)(b.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"On an application page, click on the ",Object(i.b)("inlineCode",{parentName:"p"},"Environment variable")," tabs > ",Object(i.b)("inlineCode",{parentName:"p"},"Import")," button."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/import_1.png",alt:"Import button"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Drag & Drop the ",Object(i.b)("inlineCode",{parentName:"p"},".env")," file into the modal, or click on the interface to open the file explorer.")),Object(i.b)("li",null,Object(i.b)("p",null,"The file is loaded and a new modal is displayed, where you can configure the import of your variables."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/import_2.png",alt:"Import configuration"})),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Overwrites variables")),Object(i.b)("p",null,"When this option is enabled, if an existing variable and an imported variable share the same name, the existing value will be overwritten by the imported one.\nIf the option is disabled, the imported value will be ignored.\nHowever, to avoid conflicts in the architecture of your environment variables, some of them will intentionally not be imported.\nTo understand how we handle conflicts, please take a look to the ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"#importation-conflicts"}),"Importation conflicts")," section."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Configure variables import")),Object(i.b)("p",null,"On this modal, you can define for each variable the following parameters:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"name"),": upate variable name"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Value"),": update variable value"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Scope"),": Specify the scope in which you want to import the variable"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Secret"),": Specify if this value is considered as a secret or not")),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Preset variables")),Object(i.b)("p",null,"To help you import a large number of variables quickly, you can predefine scope and secret settings.\nThis will change the scope and secret value of all listed variables.\nIf the secret and scope of one or more specific variables are subsequently updated, this will not change the predefined setting.")),Object(i.b)("li",null,Object(i.b)("p",null,"When you have finished the configuration, click on the ",Object(i.b)("inlineCode",{parentName:"p"},"Import")," button.")),Object(i.b)("li",null,Object(i.b)("p",null,"A pop-up message is displayed to inform you that your environment variables have been imported.")))),Object(i.b)("h3",{id:"importation-conflicts"},"Importation conflicts"),Object(i.b)("p",null,"To avoid conflicts between already existing and imported environment variables, some of them will not be imported, even if the overwrite option is activated.\nThe different cases are described below."),Object(i.b)("h4",{id:"imported-variable-has-same-name-as-built_in-variable"},"Imported variable has same name as BUILT_IN variable"),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Name"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Scope"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"}," Existing variables ")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"VALUE"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"42"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Built_in")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"}," Variables to import ")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"VALUE"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"10"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Application")))),Object(i.b)("p",null,"Built_in environment variables are generated and managed by Qovery and will not be overwritten, even if the ",Object(i.b)("inlineCode",{parentName:"p"},"overwriting")," option is activated."),Object(i.b)("h4",{id:"imported-variable-has-same-name-as-an-existing-alias"},"Imported variable has same name as an existing ALIAS"),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Name"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Scope"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"}," Existing variables ")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"VALUE"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"42"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Environment")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"ALIAS"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR_ALIAS"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Application")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"}," Variables to import ")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"VALUE"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR_ALIAS"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"10"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Application")))),Object(i.b)("p",null,"The value cannot be rewritten because the link between the original variable and the alias would be lost."),Object(i.b)("h4",{id:"imported-variable-has-same-name-as-an-existing-secret-or-vice-versa"},"Imported variable has same name as an existing secret (or vice versa)"),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Name"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Scope"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"}," Existing variables ")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"VALUE"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"1"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Application"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Ye")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"}," Variables to import ")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"VALUE"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"2"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Application"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"No")))),Object(i.b)("p",null,"The value cannot be imported because this will overwrite the existing secret."),Object(i.b)("h3",{id:"overwriting-and-limitations"},"Overwriting and limitations"),Object(i.b)("p",null,"Some overwriting cases are not supported for now. They are summarized in the following table."),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Existing variable scope"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Imported variable scope"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Supported"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"PROJECT"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"PROJECT / ENVIRONMENT / APPLICATION"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"YES")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"ENVIRONMENT"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"PROJECT"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"NO")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"ENVIRONMENT"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"ENVIRONMENT / APPLICATION"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"YES")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"APPLICATION"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"PROJECT / ENVIRONMENT"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"NO")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"APPLICATION"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"APPLICATION"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"YES")))),Object(i.b)("h2",{id:"service-interconnection"},"Service interconnection"),Object(i.b)("h3",{id:"connecting-to-a-database"},"Connecting to a database"),Object(i.b)("p",null,"To access a database managed by Qovery from your application, you can use the BUILT_IN environment variables and secrets that have been automatically created by Qovery during the database creation process. You can find all the BUILT_IN variables on the Qovery console within the Environment Variable section of your application (",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/#credentials-and-connectivity"}),"see the credentials and connectivity section for the full list"),")."),Object(i.b)("p",null,"In order to match the naming convention of the database connection variables used within your code, you can ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#alias-environment-variable"}),"create an alias")," for each variable in the Qovery console so that you don't need to change your code."),Object(i.b)("p",null,"Once you have defined an alias for each variable, you can redeploy the application and check that it has finally access to the database."),Object(i.b)("h4",{id:"example"},"Example"),Object(i.b)("p",null,"You have created a postgres database on the Qovery console. Within the code of your application you need some environment variables containing the connection parameters of the database: DATABASE_URL, DATABASE_USER, DATABASE_PASSWORD, DATABASE_PORT, DATABASE_NAME"),Object(i.b)("pre",null,Object(i.b)("code",Object(n.a)({parentName:"pre"},{className:"language-python",metastring:'title="example.py"',title:'"example.py"'}),'DB_NAME = os.getenv("DATABASE_NAME", "nemo")\nDB_USER = os.getenv("DATABASE_USER", "nemo")\nDB_PASSWORD = os.getenv("DATABASE_PASSWORD", "password")\nDB_HOST = os.getenv("DATABASE_HOST", "localhost")\nDB_PORT = os.getenv("DATABASE_PORT", "5432")\n')),Object(i.b)("p",null,"To match your internal naming convention, you can create aliases for each of the corresponding variables in this way:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/database_alias.png",alt:"Env Var Aliases"})),Object(i.b)("h3",{id:"connecting-to-another-application"},"Connecting to another application"),Object(i.b)("p",null,"To access another application managed by Qovery, you can use the BUILT_IN environment variables that have been automatically created by Qovery during the creation of that particular application. You can find all the BUILT_IN variables on the Qovery console within the Environment Variable section of your application."),Object(i.b)("p",null,"Please note that two BUILT_IN might exist:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_APPLICATION__HOST_INTERNAL")," : it contains the INTERNAL host of the application that can be used inside your Kubernetes cluster (and thus by any application running on it)"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_APPLICATION__HOST_EXTERNAL")," : it contains the EXTERNAL host of the application that can be used to reach your application from outside your Kubernetes cluster (if the application is publicly exposing one of its ports)")),Object(i.b)("p",null,"In order to match the naming convention of the connection variables used within your code, you can ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#alias-environment-variable"}),"create an alias")," for the HOST_INTERNAL variable so that you don't need to change your code."),Object(i.b)("p",null,"Once you have defined an alias for each variable, you can redeploy the application and check that it can reach the other application."),Object(i.b)("h4",{id:"example-1"},"Example"),Object(i.b)("p",null,"You have created a backend application on the Qovery console and a BUILD_IN variable has been created containing the application HOST called ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_APPLICATION_Z9D8DAA08_HOST_INTERNAL"),". Within the code of your front-end application you need some environment variables containing the host of the backend application (BACKEND_HOST)"),Object(i.b)("p",null,"To match your internal naming convention, you can create alias for the corresponding variable in this way:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/host_alias.png",alt:"Env Var Aliases"})))}u.isMDXComponent=!0},420:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var c=r.a.createContext({}),p=function(e){var t=r.a.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):b({},t,{},e)),a},s=function(e){var t=p(e.components);return r.a.createElement(c.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},O=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),s=p(a),O=n,m=s["".concat(l,".").concat(O)]||s[O]||u[O]||i;return a?r.a.createElement(m,b({ref:t},c,{components:a})):r.a.createElement(m,b({ref:t},c))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=a.length,l=new Array(i);l[0]=O;var b={};for(var o in t)hasOwnProperty.call(t,o)&&(b[o]=t[o]);b.originalType=e,b.mdxType="string"==typeof e?e:n,l[1]=b;for(var c=2;c1?arguments[1]:void 0,a),o=l>2?arguments[2]:void 0,c=void 0===o?a:r(o,a);c>b;)t[b++]=e;return t}},428:function(e,t,a){"use strict";var n=a(432),r=a(51);function i(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var a=function(e){var t;switch(e.arrayFormat){case"index":return function(e,a,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=a):n[e]=a};case"bracket":return function(e,a,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],a):n[e]=[a]:n[e]=a};default:return function(e,t,a){void 0!==a[e]?a[e]=[].concat(a[e],t):a[e]=t}}}(t=r({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),a(decodeURIComponent(r),i,n)})),Object.keys(n).sort().reduce((function(e,t){var a=n[t];return Boolean(a)&&"object"==typeof a&&!Array.isArray(a)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(a):e[t]=a,e}),Object.create(null))):n},t.stringify=function(e,t){var a=function(e){switch(e.arrayFormat){case"index":return function(t,a,n){return null===a?[i(t,e),"[",n,"]"].join(""):[i(t,e),"[",i(n,e),"]=",i(a,e)].join("")};case"bracket":return function(t,a){return null===a?i(t,e):[i(t,e),"[]=",i(a,e)].join("")};default:return function(t,a){return null===a?i(t,e):[i(t,e),"=",i(a,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var r=e[n];if(void 0===r)return"";if(null===r)return i(n,t);if(Array.isArray(r)){var l=[];return r.slice().forEach((function(e){void 0!==e&&l.push(a(n,e,l.length))})),l.join("&")}return i(n,t)+"="+i(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,a){"use strict";var n=a(0),r=a.n(n),i=(a(420),a(428)),l=a.n(i);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,i=e.hideFeedbackQuestion,b="undefined"!=typeof window?window.location:null,o={title:"Tutorial on "+b+" failed",body:"The tutorial on:\n\n"+b+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},c="https://github.com/qovery/documentation/issues/new?"+l.a.stringify(o),p=Object(n.useState)(null),s=p[0],u=p[1];return r.a.createElement("div",{className:"steps steps--h"+a},t,!i&&!s&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return u("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:c,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==s&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,a){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 07c2f310.1a5bde23.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{162:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return o})),a.d(t,"metadata",(function(){return c})),a.d(t,"rightToc",(function(){return p})),a.d(t,"default",(function(){return u}));var n=a(1),r=a(9),i=(a(0),a(425)),l=a(424),b=a(434),o={last_modified_on:"2023-05-29",title:"Environment Variable & Secrets",description:"Learn how to configure Environment Variables and Secrets on Qovery"},c={id:"using-qovery/configuration/environment-variable",title:"Environment Variable & Secrets",description:"Learn how to configure Environment Variables and Secrets on Qovery",source:"@site/docs/using-qovery/configuration/environment-variable.md",permalink:"/docs/using-qovery/configuration/environment-variable",sidebar:"docs",previous:{title:"Lifecycle Job",permalink:"/docs/using-qovery/configuration/lifecycle-job"},next:{title:"Service Health Checks",permalink:"/docs/using-qovery/configuration/service-health-checks"}},p=[{value:"Environment variable vs Environment variable as file",id:"environment-variable-vs-environment-variable-as-file",children:[{value:"Environment Variable",id:"environment-variable",children:[]},{value:"Environment Variable as file",id:"environment-variable-as-file",children:[]}]},{value:"Scopes",id:"scopes",children:[]},{value:"BUILT_IN variables",id:"built_in-variables",children:[]},{value:"Aliases and overrides",id:"aliases-and-overrides",children:[]},{value:"Variables Interpolation",id:"variables-interpolation",children:[]},{value:"Naming Rules",id:"naming-rules",children:[]},{value:"Create an Environment Variable",id:"create-an-environment-variable",children:[]},{value:"Delete an Environment Variable",id:"delete-an-environment-variable",children:[]},{value:"Update an Environment Variable",id:"update-an-environment-variable",children:[]},{value:"Override Environment Variable",id:"override-environment-variable",children:[]},{value:"Alias Environment Variable",id:"alias-environment-variable",children:[]},{value:"Import environment variables",id:"import-environment-variables",children:[{value:"Importation conflicts",id:"importation-conflicts",children:[]},{value:"Overwriting and limitations",id:"overwriting-and-limitations",children:[]}]},{value:"Service interconnection",id:"service-interconnection",children:[{value:"Connecting to a database",id:"connecting-to-a-database",children:[]},{value:"Connecting to another application",id:"connecting-to-another-application",children:[]}]}],s={rightToc:p};function u(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(n.a)({},s,a,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Qovery makes ",Object(i.b)("strong",{parentName:"p"},"Environment Variables")," available to your services at runtime, as well as during builds and deploys."),Object(i.b)("p",null,"If your projects and applications rely on sensitive data like credentials, API keys, certificates, Qovery offers you a way to store them as a ",Object(i.b)("strong",{parentName:"p"},"Secret"),". Secrets are special environment variable safely encrypted, and their values can not be retrieved via Qovery API - they are only accessible for your application during build and runtime."),Object(i.b)("p",null,"Qovery automatically generates for you some special environment variable (called BUILT_IN) which allows you to setup your service interconnection. See the ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"#built_in-variables"}),"BUILT_IN Section")," section."),Object(i.b)("h1",{id:"environment-variable-definition"},"Environment Variable definition"),Object(i.b)("p",null,"An environment variable is defined by:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"A type: two types are supported today",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Variable"),": classic key/value pairs where the ",Object(i.b)("inlineCode",{parentName:"li"},"value")," can be retrieved at build and run time by using its ",Object(i.b)("inlineCode",{parentName:"li"},"name")," (key). Example: Key = ",Object(i.b)("inlineCode",{parentName:"li"},"THIRD_PARTY_URL"),", Value = ",Object(i.b)("inlineCode",{parentName:"li"},"https://mythirdparty.com")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Variable as File"),": key/value/path triplets where the ",Object(i.b)("inlineCode",{parentName:"li"},"value")," will be stored as a file on the specified ",Object(i.b)("inlineCode",{parentName:"li"},"path"),". Your application can then retrieve the ",Object(i.b)("inlineCode",{parentName:"li"},"path")," of the file at run\ntime by using the variable ",Object(i.b)("inlineCode",{parentName:"li"},"name")," (key). Only text files are supported. Example: Key = ",Object(i.b)("inlineCode",{parentName:"li"},"MY_CONFIG"),", Path = ",Object(i.b)("inlineCode",{parentName:"li"},"/tmp/config.json")," Value = ",Object(i.b)("inlineCode",{parentName:"li"},'{"key1":"value1","key2":"value2"}')))),Object(i.b)("li",{parentName:"ul"},"A ",Object(i.b)("strong",{parentName:"li"},"scope"),": the accessibility level of this variable: application, environment, project (see ",Object(i.b)("a",Object(n.a)({parentName:"li"},{href:"#scopes"}),"scopes section")," below) "),Object(i.b)("li",{parentName:"ul"},"A ",Object(i.b)("strong",{parentName:"li"},"secret flag"),": it determines if the variable value needs to be encrypted and should be accessed ONLY by your applications (no access via the API/UI)")),Object(i.b)("h2",{id:"environment-variable-vs-environment-variable-as-file"},"Environment variable vs Environment variable as file"),Object(i.b)("p",null,"Depending on your use case, you might decide to use a simple key value environment variable or instead use the environment variable as a file."),Object(i.b)("h3",{id:"environment-variable"},"Environment Variable"),Object(i.b)("p",null,"If you need to store a simple value that needs to be retrieved at build or run time, than you can use a key/value environment variable"),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Example"),":\nYou have a 3rd party application running on the endpoint ",Object(i.b)("inlineCode",{parentName:"p"},"https://mythirdparty.com"),". You can create an environment variable called ",Object(i.b)("inlineCode",{parentName:"p"},"THIRD_PARTY_URL")," that will contain the 3rd party URL:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/env_key_value.png",alt:"Variable"})),Object(i.b)("p",null,"Your application will then be able to retrieve the url by getting the value of the environment variable ",Object(i.b)("inlineCode",{parentName:"p"},"THIRD_PARTY_URL"),"."),Object(i.b)("h3",{id:"environment-variable-as-file"},"Environment Variable as file"),Object(i.b)("p",null,"If your application needs to load configuration files at run time, than you can use the environment variable as file."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Example"),":\nGrafana allows you to override the default configuration by setting a few environment variables pointing to your own configuration files. By default, the variable ",Object(i.b)("inlineCode",{parentName:"p"},"GF_PATHS_CONFIG")," points to '/etc/grafana/grafana.ini' but in case you want to specify a different configuration, you can create an environment variable as file like this:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/env_file.png",alt:"Variable as file"})),Object(i.b)("p",null,"When the grafana container will load the env var ",Object(i.b)("inlineCode",{parentName:"p"},"GF_PATHS_CONFIG"),", it will retrieve the path where the configuration file is stored and load its content."),Object(i.b)("h2",{id:"scopes"},"Scopes"),Object(i.b)("p",null,"The scope of a variable allows you to define at which level this environment variable can be accessed (e.g. : only by one specific service). "),Object(i.b)("p",null,"There are three scopes for the Environment Variables:"),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Scope"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Level"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"PROJECT")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"1"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Variables at the project level are shared across all environments and all applications of the project")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"ENVIRONMENT")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"2"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Variables at the environment level are shared across all applications of the project in one, given environment")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"APPLICATION")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"3"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Variables available for one application in one environment")))),Object(i.b)("h2",{id:"built_in-variables"},"BUILT_IN variables"),Object(i.b)("p",null,"Qovery automatically generates some variables (called BUILT_IN) which allow you to easily configure your service interconnection or to access some of the environment/application information."),Object(i.b)("p",null,"By default, every environment contains the following BUILT_IN variables:"),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Name"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_PROJECT_ID")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Current project ID")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_ENVIRONMENT_ID")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Current environment ID")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_APPLICATION_ID")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Current service ID (for application with source = git repository)")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_CONTAINER_ID")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Current service ID (for application with source = container registry)")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_JOB_ID")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Current service ID (for lifecycle job and cronjob)")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_CLOUD_PROVIDER_REGION")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Cloud provider region of the Kubernetes cluster running this environment")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_KUBERNETES_NAMESPACE_NAME")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Namespace used in Kubernetes to run the application of this environment")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"},"QOVERY_KUBERNETES_CLUSTER_NAME")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Name of the Kubernetes cluster running this environment")))),Object(i.b)("p",null,"For any service within your environment (database, application, job), your application get access to a set of BUILT_IN variables. These can be used, to configure the interconnection between your services."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Naming Convention"),":"),Object(i.b)("p",null,"We use the following naming convention for additional built-in variables:"),Object(i.b)("pre",null,Object(i.b)("code",Object(n.a)({parentName:"pre"},{}),"QOVERY___\n")),Object(i.b)("p",null,"For more information on how to use the BUILT_IN environment variables to:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"connect to a database, have a look at ",Object(i.b)("a",Object(n.a)({parentName:"li"},{href:"#connecting-to-a-database"}),"this section"),"."),Object(i.b)("li",{parentName:"ul"},"connect to another service, have a look at ",Object(i.b)("a",Object(n.a)({parentName:"li"},{href:"#connecting-to-another-application"}),"this section"),".")),Object(i.b)("h2",{id:"aliases-and-overrides"},"Aliases and overrides"),Object(i.b)("p",null,"For a given environment variable, you can create aliases and overrides:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Alias: it defines an alias for the environment variable. You can access its value by its original name or by its alias name. "),Object(i.b)("li",{parentName:"ul"},"Override: it overrides the value of the environment variable. Example: you have an environment variable with scope = project having a particular value but you want to define a special value only for one environment. Instead of creating a separate environment variable only for that project, you can create an override of that variable within the environment requiring the special value.")),Object(i.b)("h2",{id:"variables-interpolation"},"Variables Interpolation"),Object(i.b)("p",null,"You can define an environment variable as a composition of text and other environment variables value (environment variables interpolation).\nFor example, you can define your APP_URL environment variable as a composition of your HOST_URL and HOST_PORT in this way:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Name = APP_URL"),Object(i.b)("li",{parentName:"ul"},"Value = ",Object(i.b)("inlineCode",{parentName:"li"},"https://{{HOST_URL}}:{{HOST_PORT}}"))),Object(i.b)("p",null,"Important information on this feature:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"the pattern used is ",Object(i.b)("inlineCode",{parentName:"li"},"{{VAR_NAME}}")),Object(i.b)("li",{parentName:"ul"},"if a referenced variable doesn't exist, it is replaced by an empty string"),Object(i.b)("li",{parentName:"ul"},"composition coherency using built in variables is kept when cloning an environment. Example: you can create a variable APP_URL = ",Object(i.b)("a",Object(n.a)({parentName:"li"},{href:"https://%7B%7BQOVERY_APPLICATION_ZEC0A2975_HOST_INTERNAL%7D%7D"}),"https://{{QOVERY_APPLICATION_ZEC0A2975_HOST_INTERNAL}}"),' and when the environment is cloned, the "ZEC0A2975" is replaced with the right ID.'),Object(i.b)("li",{parentName:"ul"},"there is no check at creation / edition / deletion if the referenced variable doesn't exist"),Object(i.b)("li",{parentName:"ul"},'"inner replacements" are not supported (e.g VAR_1 = {{VAR_2}} and VAR_2={{VAR_3}} )')),Object(i.b)("h2",{id:"naming-rules"},"Naming Rules"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Environment variable name should use only alphanumeric characters and the underscore character (_) to ensure they are accessible from all programming languages. Environment variable keys should not include the hyphen character."),Object(i.b)("li",{parentName:"ul"},"Environment variable name should not begin with a double underscore (__)."),Object(i.b)("li",{parentName:"ul"},"An environment variable\u2019s name should not begin with QOVERY_ unless it is set by the Qovery platform itself.")),Object(i.b)("h2",{id:"create-an-environment-variable"},"Create an Environment Variable"),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Do you want to bulk import your Environment Variables or Secrets? ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli/"}),"Check out this tutorial"))),Object(i.b)(b.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,"Select your project, environment and application")),Object(i.b)("li",null,Object(i.b)("p",null,"Select ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variables")," tab in the left panel and click ",Object(i.b)("inlineCode",{parentName:"p"},"New Variable")," button. Select if you want to create a classic environment variable or an environment variable as file."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/var_creation_1.png",alt:"Variables"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Select the name, value and scope of your new environment variable"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/var_creation_2.png",alt:"Variables"})),Object(i.b)("p",null,"If the variable you are trying to create is a Variable as File, define the ",Object(i.b)("inlineCode",{parentName:"p"},"Path")," where the file should be stored. Remember that in this case the ",Object(i.b)("inlineCode",{parentName:"p"},"Value")," field should contain the content of your file.\nIf the variable you are trying to create is a Secret, select the ",Object(i.b)("inlineCode",{parentName:"p"},"Secret")," checkbox.")))),Object(i.b)("h2",{id:"delete-an-environment-variable"},"Delete an Environment Variable"),Object(i.b)(b.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,"Select your project, environment and application")),Object(i.b)("li",null,Object(i.b)("p",null,"Select the ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variables")," tab in the left panel")),Object(i.b)("li",null,Object(i.b)("p",null,"Select variable you want to delete and click the ",Object(i.b)("inlineCode",{parentName:"p"},"Delete")," button from the submenu:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/var_delete.png",alt:"Delete Variables"}))))),Object(i.b)("h2",{id:"update-an-environment-variable"},"Update an Environment Variable"),Object(i.b)(b.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,"Select your project, environment and application")),Object(i.b)("li",null,Object(i.b)("p",null,"Select the ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variables")," tab in the left panel")),Object(i.b)("li",null,Object(i.b)("p",null,"Select variable you want to update and click the ",Object(i.b)("inlineCode",{parentName:"p"},"Edit")," button from the submenu:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/var_edit.png",alt:"Update Variables"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Update the variable in the popup window"),Object(i.b)("p",null,"Note: if the variable is a Secret, you won't be able to see its value")))),Object(i.b)("h2",{id:"override-environment-variable"},"Override Environment Variable"),Object(i.b)("p",null,"If you want to override a value of an environment variable, follow those steps:"),Object(i.b)(b.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,"Select your project, environment and application")),Object(i.b)("li",null,Object(i.b)("p",null,"Select the ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variables")," tab in the left panel")),Object(i.b)("li",null,Object(i.b)("p",null,"Select variable you want to override and click the ",Object(i.b)("inlineCode",{parentName:"p"},"Override")," button from the submenu")),Object(i.b)("li",null,Object(i.b)("p",null,"Select the override the variable and its scope in the popup window")))),"\\",Object(i.b)(l.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"You can only override environment variables of a higher scope, e.g. ",Object(i.b)("strong",{parentName:"p"},"Environment")," scope variable can override ",Object(i.b)("strong",{parentName:"p"},"Project")," variable, but can't override ",Object(i.b)("strong",{parentName:"p"},"Application")," variable.")),Object(i.b)("h2",{id:"alias-environment-variable"},"Alias Environment Variable"),Object(i.b)("p",null,"You can create an alias for the existing environment variable."),Object(i.b)("p",null,"Let's suppose that your application requires a ",Object(i.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," variable. Qovery provides your application with the ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_DATABASE_MY_POSTGRESQL_3498225_URL")," variable with a database password.\nInstead of copy-pasting its value, you can create an alias to ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_DATABASE_MY_POSTGRESQL_3498225_URL"),"."),Object(i.b)(b.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,"Select your project, environment and application")),Object(i.b)("li",null,Object(i.b)("p",null,"Select the ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variables")," tab in the left panel")),Object(i.b)("li",null,Object(i.b)("p",null,"Select variable you want to alias and click the ",Object(i.b)("inlineCode",{parentName:"p"},"Alias")," button from the submenu:")),Object(i.b)("li",null,Object(i.b)("p",null,"Define the alias of the variable and its scope in the popup window")))),Object(i.b)("h2",{id:"import-environment-variables"},"Import environment variables"),Object(i.b)("p",null,"You can add a set of environment variables into Qovery by importing an ",Object(i.b)("inlineCode",{parentName:"p"},".env")," file. The ",Object(i.b)("inlineCode",{parentName:"p"},".env")," file contains a list of your environment variables, in a ",Object(i.b)("inlineCode",{parentName:"p"},"MY_KEY = VALUE")," format."),Object(i.b)("p",null,"To import environment variables into your Qovery environment, follow the steps below."),Object(i.b)(b.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"On an application page, click on the ",Object(i.b)("inlineCode",{parentName:"p"},"Environment variable")," tabs > ",Object(i.b)("inlineCode",{parentName:"p"},"Import")," button."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/import_1.png",alt:"Import button"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Drag & Drop the ",Object(i.b)("inlineCode",{parentName:"p"},".env")," file into the modal, or click on the interface to open the file explorer.")),Object(i.b)("li",null,Object(i.b)("p",null,"The file is loaded and a new modal is displayed, where you can configure the import of your variables."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/import_2.png",alt:"Import configuration"})),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Overwrites variables")),Object(i.b)("p",null,"When this option is enabled, if an existing variable and an imported variable share the same name, the existing value will be overwritten by the imported one.\nIf the option is disabled, the imported value will be ignored.\nHowever, to avoid conflicts in the architecture of your environment variables, some of them will intentionally not be imported.\nTo understand how we handle conflicts, please take a look to the ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"#importation-conflicts"}),"Importation conflicts")," section."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Configure variables import")),Object(i.b)("p",null,"On this modal, you can define for each variable the following parameters:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"name"),": upate variable name"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Value"),": update variable value"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Scope"),": Specify the scope in which you want to import the variable"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Secret"),": Specify if this value is considered as a secret or not")),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Preset variables")),Object(i.b)("p",null,"To help you import a large number of variables quickly, you can predefine scope and secret settings.\nThis will change the scope and secret value of all listed variables.\nIf the secret and scope of one or more specific variables are subsequently updated, this will not change the predefined setting.")),Object(i.b)("li",null,Object(i.b)("p",null,"When you have finished the configuration, click on the ",Object(i.b)("inlineCode",{parentName:"p"},"Import")," button.")),Object(i.b)("li",null,Object(i.b)("p",null,"A pop-up message is displayed to inform you that your environment variables have been imported.")))),Object(i.b)("h3",{id:"importation-conflicts"},"Importation conflicts"),Object(i.b)("p",null,"To avoid conflicts between already existing and imported environment variables, some of them will not be imported, even if the overwrite option is activated.\nThe different cases are described below."),Object(i.b)("h4",{id:"imported-variable-has-same-name-as-built_in-variable"},"Imported variable has same name as BUILT_IN variable"),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Name"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Scope"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"}," Existing variables ")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"VALUE"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"42"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Built_in")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"}," Variables to import ")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"VALUE"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"10"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Application")))),Object(i.b)("p",null,"Built_in environment variables are generated and managed by Qovery and will not be overwritten, even if the ",Object(i.b)("inlineCode",{parentName:"p"},"overwriting")," option is activated."),Object(i.b)("h4",{id:"imported-variable-has-same-name-as-an-existing-alias"},"Imported variable has same name as an existing ALIAS"),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Name"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Scope"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"}," Existing variables ")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"VALUE"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"42"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Environment")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"ALIAS"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR_ALIAS"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Application")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"}," Variables to import ")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"VALUE"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR_ALIAS"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"10"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Application")))),Object(i.b)("p",null,"The value cannot be rewritten because the link between the original variable and the alias would be lost."),Object(i.b)("h4",{id:"imported-variable-has-same-name-as-an-existing-secret-or-vice-versa"},"Imported variable has same name as an existing secret (or vice versa)"),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Name"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Scope"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"}," Existing variables ")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"VALUE"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"1"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Application"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Ye")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(i.b)("strong",{parentName:"td"}," Variables to import ")),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"VALUE"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"MY_VAR"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"2"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Application"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"No")))),Object(i.b)("p",null,"The value cannot be imported because this will overwrite the existing secret."),Object(i.b)("h3",{id:"overwriting-and-limitations"},"Overwriting and limitations"),Object(i.b)("p",null,"Some overwriting cases are not supported for now. They are summarized in the following table."),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Existing variable scope"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Imported variable scope"),Object(i.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Supported"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"PROJECT"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"PROJECT / ENVIRONMENT / APPLICATION"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"YES")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"ENVIRONMENT"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"PROJECT"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"NO")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"ENVIRONMENT"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"ENVIRONMENT / APPLICATION"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"YES")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"APPLICATION"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"PROJECT / ENVIRONMENT"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"NO")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"APPLICATION"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"APPLICATION"),Object(i.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"YES")))),Object(i.b)("h2",{id:"service-interconnection"},"Service interconnection"),Object(i.b)("h3",{id:"connecting-to-a-database"},"Connecting to a database"),Object(i.b)("p",null,"To access a database managed by Qovery from your application, you can use the BUILT_IN environment variables and secrets that have been automatically created by Qovery during the database creation process. You can find all the BUILT_IN variables on the Qovery console within the Environment Variable section of your application (",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/#credentials-and-connectivity"}),"see the credentials and connectivity section for the full list"),")."),Object(i.b)("p",null,"In order to match the naming convention of the database connection variables used within your code, you can ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#alias-environment-variable"}),"create an alias")," for each variable in the Qovery console so that you don't need to change your code."),Object(i.b)("p",null,"Once you have defined an alias for each variable, you can redeploy the application and check that it has finally access to the database."),Object(i.b)("h4",{id:"example"},"Example"),Object(i.b)("p",null,"You have created a postgres database on the Qovery console. Within the code of your application you need some environment variables containing the connection parameters of the database: DATABASE_URL, DATABASE_USER, DATABASE_PASSWORD, DATABASE_PORT, DATABASE_NAME"),Object(i.b)("pre",null,Object(i.b)("code",Object(n.a)({parentName:"pre"},{className:"language-python",metastring:'title="example.py"',title:'"example.py"'}),'DB_NAME = os.getenv("DATABASE_NAME", "nemo")\nDB_USER = os.getenv("DATABASE_USER", "nemo")\nDB_PASSWORD = os.getenv("DATABASE_PASSWORD", "password")\nDB_HOST = os.getenv("DATABASE_HOST", "localhost")\nDB_PORT = os.getenv("DATABASE_PORT", "5432")\n')),Object(i.b)("p",null,"To match your internal naming convention, you can create aliases for each of the corresponding variables in this way:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/database_alias.png",alt:"Env Var Aliases"})),Object(i.b)("h3",{id:"connecting-to-another-application"},"Connecting to another application"),Object(i.b)("p",null,"To access another application managed by Qovery, you can use the BUILT_IN environment variables that have been automatically created by Qovery during the creation of that particular application. You can find all the BUILT_IN variables on the Qovery console within the Environment Variable section of your application."),Object(i.b)("p",null,"Please note that two BUILT_IN might exist:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_APPLICATION__HOST_INTERNAL")," : it contains the INTERNAL host of the application that can be used inside your Kubernetes cluster (and thus by any application running on it)"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_APPLICATION__HOST_EXTERNAL")," : it contains the EXTERNAL host of the application that can be used to reach your application from outside your Kubernetes cluster (if the application is publicly exposing one of its ports)")),Object(i.b)("p",null,"In order to match the naming convention of the connection variables used within your code, you can ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#alias-environment-variable"}),"create an alias")," for the HOST_INTERNAL variable so that you don't need to change your code."),Object(i.b)("p",null,"Once you have defined an alias for each variable, you can redeploy the application and check that it can reach the other application."),Object(i.b)("h4",{id:"example-1"},"Example"),Object(i.b)("p",null,"You have created a backend application on the Qovery console and a BUILD_IN variable has been created containing the application HOST called ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_APPLICATION_Z9D8DAA08_HOST_INTERNAL"),". Within the code of your front-end application you need some environment variables containing the host of the backend application (BACKEND_HOST)"),Object(i.b)("p",null,"To match your internal naming convention, you can create alias for the corresponding variable in this way:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/variables/host_alias.png",alt:"Env Var Aliases"})))}u.isMDXComponent=!0},423:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var c=r.a.createContext({}),p=function(e){var t=r.a.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):b({},t,{},e)),a},s=function(e){var t=p(e.components);return r.a.createElement(c.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},O=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),s=p(a),O=n,m=s["".concat(l,".").concat(O)]||s[O]||u[O]||i;return a?r.a.createElement(m,b({ref:t},c,{components:a})):r.a.createElement(m,b({ref:t},c))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=a.length,l=new Array(i);l[0]=O;var b={};for(var o in t)hasOwnProperty.call(t,o)&&(b[o]=t[o]);b.originalType=e,b.mdxType="string"==typeof e?e:n,l[1]=b;for(var c=2;c1?arguments[1]:void 0,a),o=l>2?arguments[2]:void 0,c=void 0===o?a:r(o,a);c>b;)t[b++]=e;return t}},433:function(e,t,a){"use strict";var n=a(435),r=a(51);function i(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var a=function(e){var t;switch(e.arrayFormat){case"index":return function(e,a,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=a):n[e]=a};case"bracket":return function(e,a,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],a):n[e]=[a]:n[e]=a};default:return function(e,t,a){void 0!==a[e]?a[e]=[].concat(a[e],t):a[e]=t}}}(t=r({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),a(decodeURIComponent(r),i,n)})),Object.keys(n).sort().reduce((function(e,t){var a=n[t];return Boolean(a)&&"object"==typeof a&&!Array.isArray(a)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(a):e[t]=a,e}),Object.create(null))):n},t.stringify=function(e,t){var a=function(e){switch(e.arrayFormat){case"index":return function(t,a,n){return null===a?[i(t,e),"[",n,"]"].join(""):[i(t,e),"[",i(n,e),"]=",i(a,e)].join("")};case"bracket":return function(t,a){return null===a?i(t,e):[i(t,e),"[]=",i(a,e)].join("")};default:return function(t,a){return null===a?i(t,e):[i(t,e),"=",i(a,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var r=e[n];if(void 0===r)return"";if(null===r)return i(n,t);if(Array.isArray(r)){var l=[];return r.slice().forEach((function(e){void 0!==e&&l.push(a(n,e,l.length))})),l.join("&")}return i(n,t)+"="+i(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,a){"use strict";var n=a(0),r=a.n(n),i=(a(423),a(433)),l=a.n(i);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,i=e.hideFeedbackQuestion,b="undefined"!=typeof window?window.location:null,o={title:"Tutorial on "+b+" failed",body:"The tutorial on:\n\n"+b+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},c="https://github.com/qovery/documentation/issues/new?"+l.a.stringify(o),p=Object(n.useState)(null),s=p[0],u=p[1];return r.a.createElement("div",{className:"steps steps--h"+a},t,!i&&!s&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return u("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:c,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==s&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,a){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/0806b243.5b87326a.js.LICENSE.txt b/07c2f310.1a5bde23.js.LICENSE.txt similarity index 100% rename from 0806b243.5b87326a.js.LICENSE.txt rename to 07c2f310.1a5bde23.js.LICENSE.txt diff --git a/0806b243.5b87326a.js b/0806b243.1d04d47e.js similarity index 87% rename from 0806b243.5b87326a.js rename to 0806b243.1d04d47e.js index 44258e52b5..2534150cd8 100644 --- a/0806b243.5b87326a.js +++ b/0806b243.1d04d47e.js @@ -1,2 +1,2 @@ -/*! For license information please see 0806b243.5b87326a.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{162:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return l}));var r=n(1),o=n(9),a=(n(0),n(422)),i=(n(431),n(421),n(426),{last_modified_on:"2023-11-25",title:"Digital Ocean (DO)",description:"Learn how to configure and plug your Digital Ocean (DO) account"}),c={id:"using-qovery/configuration/cloud-service-provider/digital-ocean",title:"Digital Ocean (DO)",description:"Learn how to configure and plug your Digital Ocean (DO) account",source:"@site/docs/using-qovery/configuration/cloud-service-provider/digital-ocean.md",permalink:"/docs/using-qovery/configuration/cloud-service-provider/digital-ocean"},u=[],s={rightToc:u};function l(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},s,n,{components:t,mdxType:"MDXLayout"}))}l.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},f=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),f=l(n),d=r,m=f["".concat(i,".").concat(d)]||f[d]||p[d]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:o(u,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),f=l[0],p=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!f&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 0806b243.1d04d47e.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{163:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return l}));var r=n(1),o=n(9),a=(n(0),n(425)),i=(n(434),n(424),n(429),{last_modified_on:"2023-11-25",title:"Digital Ocean (DO)",description:"Learn how to configure and plug your Digital Ocean (DO) account"}),c={id:"using-qovery/configuration/cloud-service-provider/digital-ocean",title:"Digital Ocean (DO)",description:"Learn how to configure and plug your Digital Ocean (DO) account",source:"@site/docs/using-qovery/configuration/cloud-service-provider/digital-ocean.md",permalink:"/docs/using-qovery/configuration/cloud-service-provider/digital-ocean"},u=[],s={rightToc:u};function l(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},s,n,{components:t,mdxType:"MDXLayout"}))}l.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},f=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),f=l(n),d=r,m=f["".concat(i,".").concat(d)]||f[d]||p[d]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:o(u,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),f=l[0],p=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!f&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/0c18cf89.61c3d706.js.LICENSE.txt b/0806b243.1d04d47e.js.LICENSE.txt similarity index 100% rename from 0c18cf89.61c3d706.js.LICENSE.txt rename to 0806b243.1d04d47e.js.LICENSE.txt diff --git a/0c18cf89.61c3d706.js b/0c18cf89.f23da0fe.js similarity index 94% rename from 0c18cf89.61c3d706.js rename to 0c18cf89.f23da0fe.js index d009b56501..a34d89f3c6 100644 --- a/0c18cf89.61c3d706.js +++ b/0c18cf89.f23da0fe.js @@ -1,2 +1,2 @@ -/*! For license information please see 0c18cf89.61c3d706.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{163:function(e,t,o){"use strict";o.r(t),o.d(t,"frontMatter",(function(){return s})),o.d(t,"metadata",(function(){return l})),o.d(t,"rightToc",(function(){return u})),o.d(t,"default",(function(){return b}));var n=o(1),a=o(9),r=(o(0),o(422)),i=o(421),c=(o(426),o(429)),s={last_modified_on:"2022-07-09",$schema:"/.meta/.schemas/guides.json",title:"Zero to Hero - How to deploy your apps on AWS in 30 minutes",description:"Step-by-step guide on how to deploy your apps on AWS in 30 minutes. No AWS knowledge required.",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0},l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Zero to Hero - How to deploy your apps on AWS in 30 minutes",description:"Step-by-step guide on how to deploy your apps on AWS in 30 minutes. No AWS knowledge required.",permalink:"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes",readingTime:"6 min read",source:"@site/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Zero to Hero - How to deploy your apps on AWS in 30 minutes",truncated:!1,prevItem:{title:"Working with Git Submodules",permalink:"/guides/tutorial/working-with-git-submodules"}},u=[{value:"Before you start",id:"before-you-start",children:[{value:"What is Qovery",id:"what-is-qovery",children:[]},{value:"Why you should use AWS",id:"why-you-should-use-aws",children:[]},{value:"Why you should not use AWS",id:"why-you-should-not-use-aws",children:[]}]},{value:"Create an AWS account",id:"create-an-aws-account",children:[{value:"Get your AWS API keys",id:"get-your-aws-api-keys",children:[]}]},{value:"Configure Qovery",id:"configure-qovery",children:[{value:"Sign-up to Qovery",id:"sign-up-to-qovery",children:[]},{value:"Create your Organization",id:"create-your-organization",children:[]},{value:"Install Qovery on your AWS account",id:"install-qovery-on-your-aws-account",children:[]}]},{value:"Deploy your application",id:"deploy-your-application",children:[]}],p={rightToc:u};function b(e){var t=e.components,o=Object(a.a)(e,["components"]);return Object(r.b)("wrapper",Object(n.a)({},p,o,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aws.amazon.com?ref=qovery"}),"Amazon Web Services")," (AWS) is a platform that offers flexible, reliable, and scalable Cloud computing solutions. The platform is developed with a combination of infrastructure as a service (IaaS), platform as a service (PaaS), and packaged software as a service (SaaS) offerings. In 2021, thousands of companies host their apps on AWS. In 2006, AWS was composed of only 3 services (SQS, S3, EC2) that were simple to use. In 2021, more than 200 services and 2000 features exist, and deploying your app can take days."),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.qovery.com"}),"Qovery")," is the simplest way to deploy your apps on AWS.")),Object(r.b)("p",null,"In this tutorial, I will explain step by step how to deploy your app on AWS in 30 minutes. No AWS/infrastructure/Cloud knowledge required - no kidding!"),Object(r.b)("h2",{id:"before-you-start"},"Before you start"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"This tutorial is perfect for anyone interested into deploying their apps on AWS seamlessly."),Object(r.b)("li",{parentName:"ol"},"If you have any question or suggestion on this tutorial, please contact us via ",Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.qovery.com/contact"}),"this form")," or ",Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://discord.qovery.com"}),"Discord"),".")),Object(r.b)("h3",{id:"what-is-qovery"},"What is Qovery"),Object(r.b)("p",null,'Qovery is a platform that makes your app deployment on AWS very simple. The installation of Qovery on your AWS account takes approximately 30 minutes. Then you\'re ready to deploy your apps "\xe0 la" Heroku-like.'),Object(r.b)("h3",{id:"why-you-should-use-aws"},"Why you should use AWS"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You need a reliable hosting platform."),Object(r.b)("li",{parentName:"ul"},"You want to stay focus on what you are building."),Object(r.b)("li",{parentName:"ul"},"You need to speed up your Go-To-Market and Product Market Fit."),Object(r.b)("li",{parentName:"ul"},"You plan to be the next unicorn \ud83e\udd84")),Object(r.b)("h3",{id:"why-you-should-not-use-aws"},"Why you should not use AWS"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You are building a hobby project."),Object(r.b)("li",{parentName:"ul"},"You are looking for a cheap hosting provider."),Object(r.b)("li",{parentName:"ul"},"You do not want to use Amazon services.")),Object(r.b)("p",null,"Let's start!"),Object(r.b)("h1",{id:"video-install-qovery-on-aws"},"Video: Install Qovery on AWS"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Follow ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"this guide")," to create your AWS credentials")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/3450aa0c4122467892cd7c6e1fc85f6e",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h1",{id:"step-by-step-install-qovery-on-aws"},"Step-by-step: Install Qovery on AWS"),Object(r.b)("h2",{id:"create-an-aws-account"},"Create an AWS account"),Object(r.b)("p",null,Object(r.b)("em",{parentName:"p"},"If you already have an AWS account, you can go to the next point.")),Object(r.b)("p",null,"Before creating an AWS account, I'd recommend contacting AWS to see if you are eligible to free credits. AWS provides up to $100k of credits for 12 to 24 months. Which is convenient to have at the beginning of a project. If you know that you are not eligible, you can create your account by clicking on the top right button ",Object(r.b)("inlineCode",{parentName:"p"},"Create an AWS Account")," of their ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aws.amazon.com?ref=qovery"}),"main page"),"."),Object(r.b)("img",{src:"/img/aws-create-an-account.jpg",alt:"Create an account on AWS"}),Object(r.b)("h3",{id:"get-your-aws-api-keys"},"Get your AWS API keys"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Follow ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"this guide")," to create your AWS credentials")),Object(r.b)("p",null,"To install Qovery on your AWS account, the ",Object(r.b)("inlineCode",{parentName:"p"},"secret access key")," and ",Object(r.b)("inlineCode",{parentName:"p"},"access key id")," are required. Here is a comprehensive ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"step-by-step guide")," on how to generate your ",Object(r.b)("inlineCode",{parentName:"p"},"secret access key")," and ",Object(r.b)("inlineCode",{parentName:"p"},"access key id"),". If you already have those keys, then you can go to the next point."),Object(r.b)("h2",{id:"configure-qovery"},"Configure Qovery"),Object(r.b)("h3",{id:"sign-up-to-qovery"},"Sign-up to Qovery"),Object(r.b)("p",null,"Using Qovery is as simple as connect with your ",Object(r.b)("em",{parentName:"p"},"Github"),", ",Object(r.b)("em",{parentName:"p"},"Gitlab")," or ",Object(r.b)("em",{parentName:"p"},"Bitbucket")," account on ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"start.qovery.com"),"."),Object(r.b)("p",null,"-> ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Connect to Qovery")),Object(r.b)("h3",{id:"create-your-organization"},"Create your Organization"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can skip this step if you already have an Organization.")),Object(r.b)("p",null,"An organization is a shared account where developers can collaborate across many projects at once. Owners and organization administrators can manage:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Cloud accounts."),Object(r.b)("li",{parentName:"ul"},"Members access."),Object(r.b)("li",{parentName:"ul"},"Billing.")),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/"}),"Read more")," about Organizations"),Object(r.b)("p",null,"To deploy on your AWS account, you have to choose between ",Object(r.b)("strong",{parentName:"p"},"Free"),", ",Object(r.b)("strong",{parentName:"p"},"Professional")," and ",Object(r.b)("strong",{parentName:"p"},"Business")," plan for your organization."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Qovery_Pricing_Plans.png",alt:"Qovery - Create an Organization and select the plan"})),Object(r.b)("h3",{id:"install-qovery-on-your-aws-account"},"Install Qovery on your AWS account"),Object(r.b)("p",null,'1/ Go to your organization settings by clicking on the "cog" icon next to your organization name.'),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_clusters_empty.jpg",alt:"Go your organization settings > clusters"})),Object(r.b)("p",null,"2/ Create a cluster, select ",Object(r.b)("em",{parentName:"p"},"Amazon Web Services")," and the region where you want to deploy your apps."),Object(r.b)(i.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Choose a region close to where your users will use your applications to have better performances.")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_create_cluster.jpg",alt:"Create a cluster"})),Object(r.b)("p",null,"3/ Set your AWS credentials. (Check out ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/"}),"this guide")," if you have no AWS credentials)."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_add_credentials.jpg",alt:"Set your cloud credentials"})),Object(r.b)("p",null,"4/ Under the hood, Qovery uses a managed Kubernetes (",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aws.amazon.com/eks"}),"AWS EKS"),") to run your applications. You need to specify the instance type that you would like to use and the min/max number of nodes. Qovery will keep low the number of nodes and will only scale up your nodes if your applications really need to scale.\nIf you don't know which instance type to chose, have a look at the AWS instance list or use the helper to chose the right instance based on your CPU/RAM needs."),Object(r.b)(i.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Qovery optimizes and keep your AWS costs low.")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_cluster_resources.jpg",alt:"Set your cluster resources"})),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},"Qovery might use some temporary free resources on your Kubernetes cluster to perform spotted maintenance operations (e.g. : cluster version upgrades). This is why we recommend a cluster setup with:",Object(r.b)("ul",null,Object(r.b)("li",null,"at least 20% difference between the minimum and the maximum number of nodes;"),Object(r.b)("li",null,"at least 5 nodes as the maximum number of nodes of your cluster;"))),Object(r.b)("p",null,"5/ Click on ",Object(r.b)("strong",{parentName:"p"},"Save")," and ",Object(r.b)("strong",{parentName:"p"},"Deploy"),"."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_clusters_aws.jpg",alt:"AWS cluster is now available"})),Object(r.b)("p",null,"Congrats! Qovery will be installed within 30 minutes \ud83c\udf89. You will be notified when it is all good.\nIn the meantime, you can take a look at our ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"guide section"),"."),Object(r.b)("p",null,"6/ Enable cluster sync with SSO account"),Object(r.b)("p",null,"If you're using SSO for your AWS account deploying the Qovery cluster you have to add some infos in the ",Object(r.b)("em",{parentName:"p"},"aws-auth configmap")," in ",Object(r.b)("inlineCode",{parentName:"p"},"kube-system")," namespace.\nConnect to your cluster and edit the ",Object(r.b)("em",{parentName:"p"},"aws-auth configmap")," in order to add the following code in the mapRoles section:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-yaml"}),'- rolearn: arn:aws:iam:::role/AWSReservedSSO_AdministratorAccess_\n username: "{{SessionName}}"\n groups:\n - system:masters\n')),Object(r.b)("h2",{id:"deploy-your-application"},"Deploy your application"),Object(r.b)("p",null,"Once Qovery is installed on your AWS account, you have the possibility to deploy your application. Take a look to ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"our guide")," on how to ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"deploy your first application")," with Qovery."),Object(r.b)(c.a,{to:"/guides/getting-started/deploy-your-first-application",mdxType:"Jump"},"Deploy your first application"))}b.isMDXComponent=!0},420:function(e,t,o){var n;!function(){"use strict";var o={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[o]=e[o]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(a[o]=e[o])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),o=t;return e&&(o="function"==typeof e?e(t):c({},t,{},e)),o},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var o=e.components,n=e.mdxType,r=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(o),d=n,y=p["".concat(i,".").concat(d)]||p[d]||b[d]||r;return o?a.a.createElement(y,c({ref:t},l,{components:o})):a.a.createElement(y,c({ref:t},l))}));function y(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=o.length,i=new Array(r);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l1?arguments[1]:void 0,o),s=i>2?arguments[2]:void 0,l=void 0===s?o:a(s,o);l>c;)t[c++]=e;return t}},425:function(e,t,o){var n=o(28).f,a=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in a||o(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,o){"use strict";o(425);var n=o(0),a=o.n(n),r=o(421);t.a=function(e){var t=e.children,o=e.name;return a.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",o||"page"," assumes the following:"),t)}},427:function(e,t,o){"use strict";var n=o(1),a=o(0),r=o.n(a),i=o(39),c=o(430),s=o(20),l=o.n(s);t.a=function(e){var t,o=e.to,s=e.href,u=o||s,p=Object(c.a)(u),b=Object(a.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?r.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var o,n;d&&e&&p&&(o=e,n=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){o===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(o),t.disconnect(),n())}))}))).observe(o))},to:u})):r.a.createElement("a",Object(n.a)({},e,{href:u}))}},429:function(e,t,o){"use strict";var n=o(0),a=o.n(n),r=o(427),i=o(420),c=o.n(i);o(133);t.a=function(e){var t=e.children,o=e.className,n=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+l,o),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},n?a.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?a.a.createElement("a",{href:p,target:u,className:b},d):a.a.createElement(r.a,{to:p,className:b},d)}},430:function(e,t,o){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}o.d(t,"a",(function(){return n}))}}]); \ No newline at end of file +/*! For license information please see 0c18cf89.f23da0fe.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{164:function(e,t,o){"use strict";o.r(t),o.d(t,"frontMatter",(function(){return s})),o.d(t,"metadata",(function(){return l})),o.d(t,"rightToc",(function(){return u})),o.d(t,"default",(function(){return b}));var n=o(1),a=o(9),r=(o(0),o(425)),i=o(424),c=(o(429),o(431)),s={last_modified_on:"2022-07-09",$schema:"/.meta/.schemas/guides.json",title:"Zero to Hero - How to deploy your apps on AWS in 30 minutes",description:"Step-by-step guide on how to deploy your apps on AWS in 30 minutes. No AWS knowledge required.",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0},l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Zero to Hero - How to deploy your apps on AWS in 30 minutes",description:"Step-by-step guide on how to deploy your apps on AWS in 30 minutes. No AWS knowledge required.",permalink:"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes",readingTime:"6 min read",source:"@site/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Zero to Hero - How to deploy your apps on AWS in 30 minutes",truncated:!1,prevItem:{title:"Working with Git Submodules",permalink:"/guides/tutorial/working-with-git-submodules"}},u=[{value:"Before you start",id:"before-you-start",children:[{value:"What is Qovery",id:"what-is-qovery",children:[]},{value:"Why you should use AWS",id:"why-you-should-use-aws",children:[]},{value:"Why you should not use AWS",id:"why-you-should-not-use-aws",children:[]}]},{value:"Create an AWS account",id:"create-an-aws-account",children:[{value:"Get your AWS API keys",id:"get-your-aws-api-keys",children:[]}]},{value:"Configure Qovery",id:"configure-qovery",children:[{value:"Sign-up to Qovery",id:"sign-up-to-qovery",children:[]},{value:"Create your Organization",id:"create-your-organization",children:[]},{value:"Install Qovery on your AWS account",id:"install-qovery-on-your-aws-account",children:[]}]},{value:"Deploy your application",id:"deploy-your-application",children:[]}],p={rightToc:u};function b(e){var t=e.components,o=Object(a.a)(e,["components"]);return Object(r.b)("wrapper",Object(n.a)({},p,o,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aws.amazon.com?ref=qovery"}),"Amazon Web Services")," (AWS) is a platform that offers flexible, reliable, and scalable Cloud computing solutions. The platform is developed with a combination of infrastructure as a service (IaaS), platform as a service (PaaS), and packaged software as a service (SaaS) offerings. In 2021, thousands of companies host their apps on AWS. In 2006, AWS was composed of only 3 services (SQS, S3, EC2) that were simple to use. In 2021, more than 200 services and 2000 features exist, and deploying your app can take days."),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.qovery.com"}),"Qovery")," is the simplest way to deploy your apps on AWS.")),Object(r.b)("p",null,"In this tutorial, I will explain step by step how to deploy your app on AWS in 30 minutes. No AWS/infrastructure/Cloud knowledge required - no kidding!"),Object(r.b)("h2",{id:"before-you-start"},"Before you start"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"This tutorial is perfect for anyone interested into deploying their apps on AWS seamlessly."),Object(r.b)("li",{parentName:"ol"},"If you have any question or suggestion on this tutorial, please contact us via ",Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.qovery.com/contact"}),"this form")," or ",Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://discord.qovery.com"}),"Discord"),".")),Object(r.b)("h3",{id:"what-is-qovery"},"What is Qovery"),Object(r.b)("p",null,'Qovery is a platform that makes your app deployment on AWS very simple. The installation of Qovery on your AWS account takes approximately 30 minutes. Then you\'re ready to deploy your apps "\xe0 la" Heroku-like.'),Object(r.b)("h3",{id:"why-you-should-use-aws"},"Why you should use AWS"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You need a reliable hosting platform."),Object(r.b)("li",{parentName:"ul"},"You want to stay focus on what you are building."),Object(r.b)("li",{parentName:"ul"},"You need to speed up your Go-To-Market and Product Market Fit."),Object(r.b)("li",{parentName:"ul"},"You plan to be the next unicorn \ud83e\udd84")),Object(r.b)("h3",{id:"why-you-should-not-use-aws"},"Why you should not use AWS"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You are building a hobby project."),Object(r.b)("li",{parentName:"ul"},"You are looking for a cheap hosting provider."),Object(r.b)("li",{parentName:"ul"},"You do not want to use Amazon services.")),Object(r.b)("p",null,"Let's start!"),Object(r.b)("h1",{id:"video-install-qovery-on-aws"},"Video: Install Qovery on AWS"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Follow ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"this guide")," to create your AWS credentials")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/3450aa0c4122467892cd7c6e1fc85f6e",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h1",{id:"step-by-step-install-qovery-on-aws"},"Step-by-step: Install Qovery on AWS"),Object(r.b)("h2",{id:"create-an-aws-account"},"Create an AWS account"),Object(r.b)("p",null,Object(r.b)("em",{parentName:"p"},"If you already have an AWS account, you can go to the next point.")),Object(r.b)("p",null,"Before creating an AWS account, I'd recommend contacting AWS to see if you are eligible to free credits. AWS provides up to $100k of credits for 12 to 24 months. Which is convenient to have at the beginning of a project. If you know that you are not eligible, you can create your account by clicking on the top right button ",Object(r.b)("inlineCode",{parentName:"p"},"Create an AWS Account")," of their ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aws.amazon.com?ref=qovery"}),"main page"),"."),Object(r.b)("img",{src:"/img/aws-create-an-account.jpg",alt:"Create an account on AWS"}),Object(r.b)("h3",{id:"get-your-aws-api-keys"},"Get your AWS API keys"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Follow ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"this guide")," to create your AWS credentials")),Object(r.b)("p",null,"To install Qovery on your AWS account, the ",Object(r.b)("inlineCode",{parentName:"p"},"secret access key")," and ",Object(r.b)("inlineCode",{parentName:"p"},"access key id")," are required. Here is a comprehensive ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"step-by-step guide")," on how to generate your ",Object(r.b)("inlineCode",{parentName:"p"},"secret access key")," and ",Object(r.b)("inlineCode",{parentName:"p"},"access key id"),". If you already have those keys, then you can go to the next point."),Object(r.b)("h2",{id:"configure-qovery"},"Configure Qovery"),Object(r.b)("h3",{id:"sign-up-to-qovery"},"Sign-up to Qovery"),Object(r.b)("p",null,"Using Qovery is as simple as connect with your ",Object(r.b)("em",{parentName:"p"},"Github"),", ",Object(r.b)("em",{parentName:"p"},"Gitlab")," or ",Object(r.b)("em",{parentName:"p"},"Bitbucket")," account on ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"start.qovery.com"),"."),Object(r.b)("p",null,"-> ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Connect to Qovery")),Object(r.b)("h3",{id:"create-your-organization"},"Create your Organization"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can skip this step if you already have an Organization.")),Object(r.b)("p",null,"An organization is a shared account where developers can collaborate across many projects at once. Owners and organization administrators can manage:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Cloud accounts."),Object(r.b)("li",{parentName:"ul"},"Members access."),Object(r.b)("li",{parentName:"ul"},"Billing.")),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/"}),"Read more")," about Organizations"),Object(r.b)("p",null,"To deploy on your AWS account, you have to choose between ",Object(r.b)("strong",{parentName:"p"},"Free"),", ",Object(r.b)("strong",{parentName:"p"},"Professional")," and ",Object(r.b)("strong",{parentName:"p"},"Business")," plan for your organization."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Qovery_Pricing_Plans.png",alt:"Qovery - Create an Organization and select the plan"})),Object(r.b)("h3",{id:"install-qovery-on-your-aws-account"},"Install Qovery on your AWS account"),Object(r.b)("p",null,'1/ Go to your organization settings by clicking on the "cog" icon next to your organization name.'),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_clusters_empty.jpg",alt:"Go your organization settings > clusters"})),Object(r.b)("p",null,"2/ Create a cluster, select ",Object(r.b)("em",{parentName:"p"},"Amazon Web Services")," and the region where you want to deploy your apps."),Object(r.b)(i.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Choose a region close to where your users will use your applications to have better performances.")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_create_cluster.jpg",alt:"Create a cluster"})),Object(r.b)("p",null,"3/ Set your AWS credentials. (Check out ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/"}),"this guide")," if you have no AWS credentials)."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_add_credentials.jpg",alt:"Set your cloud credentials"})),Object(r.b)("p",null,"4/ Under the hood, Qovery uses a managed Kubernetes (",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aws.amazon.com/eks"}),"AWS EKS"),") to run your applications. You need to specify the instance type that you would like to use and the min/max number of nodes. Qovery will keep low the number of nodes and will only scale up your nodes if your applications really need to scale.\nIf you don't know which instance type to chose, have a look at the AWS instance list or use the helper to chose the right instance based on your CPU/RAM needs."),Object(r.b)(i.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Qovery optimizes and keep your AWS costs low.")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_cluster_resources.jpg",alt:"Set your cluster resources"})),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},"Qovery might use some temporary free resources on your Kubernetes cluster to perform spotted maintenance operations (e.g. : cluster version upgrades). This is why we recommend a cluster setup with:",Object(r.b)("ul",null,Object(r.b)("li",null,"at least 20% difference between the minimum and the maximum number of nodes;"),Object(r.b)("li",null,"at least 5 nodes as the maximum number of nodes of your cluster;"))),Object(r.b)("p",null,"5/ Click on ",Object(r.b)("strong",{parentName:"p"},"Save")," and ",Object(r.b)("strong",{parentName:"p"},"Deploy"),"."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_clusters_aws.jpg",alt:"AWS cluster is now available"})),Object(r.b)("p",null,"Congrats! Qovery will be installed within 30 minutes \ud83c\udf89. You will be notified when it is all good.\nIn the meantime, you can take a look at our ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"guide section"),"."),Object(r.b)("p",null,"6/ Enable cluster sync with SSO account"),Object(r.b)("p",null,"If you're using SSO for your AWS account deploying the Qovery cluster you have to add some infos in the ",Object(r.b)("em",{parentName:"p"},"aws-auth configmap")," in ",Object(r.b)("inlineCode",{parentName:"p"},"kube-system")," namespace.\nConnect to your cluster and edit the ",Object(r.b)("em",{parentName:"p"},"aws-auth configmap")," in order to add the following code in the mapRoles section:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-yaml"}),'- rolearn: arn:aws:iam:::role/AWSReservedSSO_AdministratorAccess_\n username: "{{SessionName}}"\n groups:\n - system:masters\n')),Object(r.b)("h2",{id:"deploy-your-application"},"Deploy your application"),Object(r.b)("p",null,"Once Qovery is installed on your AWS account, you have the possibility to deploy your application. Take a look to ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"our guide")," on how to ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"deploy your first application")," with Qovery."),Object(r.b)(c.a,{to:"/guides/getting-started/deploy-your-first-application",mdxType:"Jump"},"Deploy your first application"))}b.isMDXComponent=!0},423:function(e,t,o){var n;!function(){"use strict";var o={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[o]=e[o]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(a[o]=e[o])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),o=t;return e&&(o="function"==typeof e?e(t):c({},t,{},e)),o},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var o=e.components,n=e.mdxType,r=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(o),d=n,y=p["".concat(i,".").concat(d)]||p[d]||b[d]||r;return o?a.a.createElement(y,c({ref:t},l,{components:o})):a.a.createElement(y,c({ref:t},l))}));function y(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=o.length,i=new Array(r);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l1?arguments[1]:void 0,o),s=i>2?arguments[2]:void 0,l=void 0===s?o:a(s,o);l>c;)t[c++]=e;return t}},428:function(e,t,o){var n=o(28).f,a=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in a||o(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,o){"use strict";o(428);var n=o(0),a=o.n(n),r=o(424);t.a=function(e){var t=e.children,o=e.name;return a.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",o||"page"," assumes the following:"),t)}},430:function(e,t,o){"use strict";var n=o(1),a=o(0),r=o.n(a),i=o(39),c=o(432),s=o(20),l=o.n(s);t.a=function(e){var t,o=e.to,s=e.href,u=o||s,p=Object(c.a)(u),b=Object(a.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?r.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var o,n;d&&e&&p&&(o=e,n=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){o===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(o),t.disconnect(),n())}))}))).observe(o))},to:u})):r.a.createElement("a",Object(n.a)({},e,{href:u}))}},431:function(e,t,o){"use strict";var n=o(0),a=o.n(n),r=o(430),i=o(423),c=o.n(i);o(133);t.a=function(e){var t=e.children,o=e.className,n=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+l,o),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},n?a.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?a.a.createElement("a",{href:p,target:u,className:b},d):a.a.createElement(r.a,{to:p,className:b},d)}},432:function(e,t,o){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}o.d(t,"a",(function(){return n}))}}]); \ No newline at end of file diff --git a/1.a5b1a3ad.js.LICENSE.txt b/0c18cf89.f23da0fe.js.LICENSE.txt similarity index 100% rename from 1.a5b1a3ad.js.LICENSE.txt rename to 0c18cf89.f23da0fe.js.LICENSE.txt diff --git a/0c52d983.7818df42.js b/0c52d983.81032bc9.js similarity index 74% rename from 0c52d983.7818df42.js rename to 0c52d983.81032bc9.js index 1d6b2befe8..68a7b509d6 100644 --- a/0c52d983.7818df42.js +++ b/0c52d983.81032bc9.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{164:function(e){e.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"provider-kubernetes","name":"provider: kubernetes","count":1,"permalink":"/guides/tags/provider-kubernetes"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{165:function(e){e.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"provider-kubernetes","name":"provider: kubernetes","count":1,"permalink":"/guides/tags/provider-kubernetes"}')}}]); \ No newline at end of file diff --git a/0e2fb061.4df53b9c.js b/0e2fb061.62a8172c.js similarity index 77% rename from 0e2fb061.4df53b9c.js rename to 0e2fb061.62a8172c.js index e26e9e1e91..34262a56c5 100644 --- a/0e2fb061.4df53b9c.js +++ b/0e2fb061.62a8172c.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{165:function(e){e.exports=JSON.parse('{"category":{"name":"getting-started","title":"Getting Started","description":"Take Qovery from zero to production in under 10 minutes.","permalink":"/guides/getting-started"}}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[18],{166:function(e){e.exports=JSON.parse('{"category":{"name":"getting-started","title":"Getting Started","description":"Take Qovery from zero to production in under 10 minutes.","permalink":"/guides/getting-started"}}')}}]); \ No newline at end of file diff --git a/1.a5b1a3ad.js b/1.5236ee97.js similarity index 98% rename from 1.a5b1a3ad.js rename to 1.5236ee97.js index b09d97542f..1959723a3a 100644 --- a/1.a5b1a3ad.js +++ b/1.5236ee97.js @@ -1,2 +1,2 @@ -/*! For license information please see 1.a5b1a3ad.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[1],{420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=o.a.createContext({}),c=function(e){var t=o.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a({},t,{},e)),n},p=function(e){var t=c(e.components);return o.a.createElement(l.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,u=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=c(n),d=r,h=p["".concat(u,".").concat(d)]||p[d]||f[d]||i;return n?o.a.createElement(h,a({ref:t},l,{components:n})):o.a.createElement(h,a({ref:t},l))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,u=new Array(i);u[0]=d;var a={};for(var s in t)hasOwnProperty.call(t,s)&&(a[s]=t[s]);a.originalType=e,a.mdxType="string"==typeof e?e:r,u[1]=a;for(var l=2;l1?arguments[1]:void 0,n),s=u>2?arguments[2]:void 0,l=void 0===s?n:o(s,n);l>a;)t[a++]=e;return t}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function i(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(o),i,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[i(t,e),"[",r,"]"].join(""):[i(t,e),"[",i(r,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return i(r,t);if(Array.isArray(o)){var u=[];return o.slice().forEach((function(e){void 0!==e&&u.push(n(r,e,u.length))})),u.join("&")}return i(r,t)+"="+i(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},436:function(e,t,n){"use strict";var r=n(12),o=n(462)(5),i=!0;"find"in[]&&Array(1).find((function(){i=!1})),r(r.P+r.F*i,"Array",{find:function(e){return o(this,e,arguments.length>1?arguments[1]:void 0)}}),n(74)("find")},439:function(e,t,n){"use strict";var r=n(8),o=n(483),i=n(55);n(56)("search",1,(function(e,t,n,u){return[function(n){var r=e(this),o=null==n?void 0:n[t];return void 0!==o?o.call(n,r):new RegExp(n)[t](String(r))},function(e){var t=u(n,e,this);if(t.done)return t.value;var a=r(e),s=String(this),l=a.lastIndex;o(l,0)||(a.lastIndex=0);var c=i(a,s);return o(a.lastIndex,l)||(a.lastIndex=l),null===c?-1:c.index}]}))},445:function(e,t,n){"use strict";var r=n(0),o=n(451);t.a=function(){return Object(r.useContext)(o.a)}},446:function(e,t,n){"use strict";var r=n(0),o=n.n(r);function i(e,t){if(e.length!==t.length)return!1;for(var n=0;nr&&(r=(t=t.trim()).charCodeAt(0)),r){case 38:return t.replace(m,"$1"+e.trim());case 58:return e.trim()+t.replace(m,"$1"+e.trim());default:if(0<1*n&&0s.charCodeAt(8))break;case 115:u=u.replace(s,"-webkit-"+s)+";"+u;break;case 207:case 102:u=u.replace(s,"-webkit-"+(102a.charCodeAt(0)&&(a=a.trim()),a=[a],0d)&&(N=(U=U.replace(" ",":")).length),0=4;++r,o-=4)t=1540483477*(65535&(t=255&e.charCodeAt(r)|(255&e.charCodeAt(++r))<<8|(255&e.charCodeAt(++r))<<16|(255&e.charCodeAt(++r))<<24))+(59797*(t>>>16)<<16),n=1540483477*(65535&(t^=t>>>24))+(59797*(t>>>16)<<16)^1540483477*(65535&n)+(59797*(n>>>16)<<16);switch(o){case 3:n^=(255&e.charCodeAt(r+2))<<16;case 2:n^=(255&e.charCodeAt(r+1))<<8;case 1:n=1540483477*(65535&(n^=255&e.charCodeAt(r)))+(59797*(n>>>16)<<16)}return(((n=1540483477*(65535&(n^=n>>>13))+(59797*(n>>>16)<<16))^n>>>15)>>>0).toString(36)},b={animationIterationCount:1,borderImageOutset:1,borderImageSlice:1,borderImageWidth:1,boxFlex:1,boxFlexGroup:1,boxOrdinalGroup:1,columnCount:1,columns:1,flex:1,flexGrow:1,flexPositive:1,flexShrink:1,flexNegative:1,flexOrder:1,gridRow:1,gridRowEnd:1,gridRowSpan:1,gridRowStart:1,gridColumn:1,gridColumnEnd:1,gridColumnSpan:1,gridColumnStart:1,msGridRow:1,msGridRowSpan:1,msGridColumn:1,msGridColumnSpan:1,fontWeight:1,lineHeight:1,opacity:1,order:1,orphans:1,tabSize:1,widows:1,zIndex:1,zoom:1,WebkitLineClamp:1,fillOpacity:1,floodOpacity:1,stopOpacity:1,strokeDasharray:1,strokeDashoffset:1,strokeMiterlimit:1,strokeOpacity:1,strokeWidth:1};var E=/[A-Z]|^ms/g,y=/_EMO_([^_]+?)_([^]*?)_EMO_/g,C=function(e){return 45===e.charCodeAt(1)},O=function(e){return null!=e&&"boolean"!=typeof e},A=function(e){var t={};return function(n){return void 0===t[n]&&(t[n]=e(n)),t[n]}}((function(e){return C(e)?e:e.replace(E,"-$&").toLowerCase()})),w=function(e,t){switch(e){case"animation":case"animationName":if("string"==typeof t)return t.replace(y,(function(e,t,n){return x={name:t,styles:n,next:x},t}))}return 1===b[e]||C(e)||"number"!=typeof t||0===t?t:t+"px"};function F(e,t,n,r){if(null==n)return"";if(void 0!==n.__emotion_styles)return n;switch(typeof n){case"boolean":return"";case"object":if(1===n.anim)return x={name:n.name,styles:n.styles,next:x},n.name;if(void 0!==n.styles){var o=n.next;if(void 0!==o)for(;void 0!==o;)x={name:o.name,styles:o.styles,next:x},o=o.next;return n.styles+";"}return function(e,t,n){var r="";if(Array.isArray(n))for(var o=0;o-1}function J(e){return K(e)?window.pageYOffset:e.scrollTop}function q(e,t){K(e)?window.scrollTo(0,t):e.scrollTop=t}function Z(e,t,n,r){void 0===n&&(n=200),void 0===r&&(r=G);var o=J(e),i=t-o,u=0;!function t(){var a,s=i*((a=(a=u+=10)/n-1)*a*a+1)+o;q(e,s),u=d)return{placement:"bottom",maxHeight:t};if(A>=d&&!u)return i&&Z(s,w,160),{placement:"bottom",maxHeight:t};if(!u&&A>=r||u&&C>=r)return i&&Z(s,w,160),{placement:"bottom",maxHeight:u?C-b:A-b};if("auto"===o||u){var x=t,S=u?y:O;return S>=r&&(x=Math.min(S-b-a.controlHeight,t)),{placement:"top",maxHeight:x}}if("bottom"===o)return q(s,w),{placement:"bottom",maxHeight:t};break;case"top":if(y>=d)return{placement:"top",maxHeight:t};if(O>=d&&!u)return i&&Z(s,F,160),{placement:"top",maxHeight:t};if(!u&&O>=r||u&&y>=r){var D=t;return(!u&&O>=r||u&&y>=r)&&(D=u?y-E:O-E),i&&Z(s,F,160),{placement:"top",maxHeight:D}}return{placement:"bottom",maxHeight:t};default:throw new Error('Invalid placement provided "'+o+'".')}return l}var ie=function(e){return"auto"===e?"bottom":e},ue=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),o=0;o=0||(o[n]=e[n]);return o}(e,["size"]);return B("svg",Ee({height:t,width:t,viewBox:"0 0 20 20","aria-hidden":"true",focusable:"false",css:ye},n))},Oe=function(e){return B(Ce,Ee({size:20},e),B("path",{d:"M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z"}))},Ae=function(e){return B(Ce,Ee({size:20},e),B("path",{d:"M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"}))},we=function(e){var t=e.isFocused,n=e.theme,r=n.spacing.baseUnit,o=n.colors;return{label:"indicatorContainer",color:t?o.neutral60:o.neutral20,display:"flex",padding:2*r,transition:"color 150ms",":hover":{color:t?o.neutral80:o.neutral40}}},Fe=we,xe=we,Se=function(){var e=k.apply(void 0,arguments),t="animation-"+e.name;return{name:t,styles:"@keyframes "+t+"{"+e.styles+"}",anim:1,toString:function(){return"_EMO_"+this.name+"_"+this.styles+"_EMO_"}}}(be()),De=function(e){var t=e.delay,n=e.offset;return B("span",{css:k({animation:Se+" 1s ease-in-out "+t+"ms infinite;",backgroundColor:"currentColor",borderRadius:"1em",display:"inline-block",marginLeft:n?"1em":null,height:"1em",verticalAlign:"top",width:"1em"},"")})},ke=function(e){var t=e.className,n=e.cx,r=e.getStyles,o=e.innerProps,i=e.isRtl;return B("div",Ee({},o,{css:r("loadingIndicator",e),className:n({indicator:!0,"loading-indicator":!0},t)}),B(De,{delay:0,offset:i}),B(De,{delay:160,offset:!0}),B(De,{delay:320,offset:!i}))};function Ie(){return(Ie=Object.assign||function(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,["className","cx","getStyles","theme","selectProps"]));return B("div",Me({css:r("groupHeading",Me({theme:o},i)),className:n({"group-heading":!0},t)},i))},IndicatorsContainer:function(e){var t=e.children,n=e.className,r=e.cx,o=e.getStyles;return B("div",{css:o("indicatorsContainer",e),className:r({indicators:!0},n)},t)},IndicatorSeparator:function(e){var t=e.className,n=e.cx,r=e.getStyles,o=e.innerProps;return B("span",Ee({},o,{css:r("indicatorSeparator",e),className:n({"indicator-separator":!0},t)}))},Input:function(e){var t=e.className,n=e.cx,r=e.getStyles,o=e.innerRef,i=e.isHidden,u=e.isDisabled,a=e.theme,s=(e.selectProps,function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r=0||(o[n]=e[n]);return o}(e,["className","cx","getStyles","innerRef","isHidden","isDisabled","theme","selectProps"]));return B("div",{css:r("input",Pe({theme:a},s))},B(te.a,Pe({className:n({input:!0},t),inputRef:o,inputStyle:Le(i),disabled:u},s)))},LoadingIndicator:ke,Menu:function(e){var t=e.children,n=e.className,r=e.cx,o=e.getStyles,i=e.innerRef,u=e.innerProps;return B("div",ne({css:o("menu",e),className:r({menu:!0},n)},u,{ref:i}),t)},MenuList:function(e){var t=e.children,n=e.className,r=e.cx,o=e.getStyles,i=e.isMulti,u=e.innerRef;return B("div",{css:o("menuList",e),className:r({"menu-list":!0,"menu-list--is-multi":i},n),ref:u},t)},MenuPortal:fe,LoadingMessage:pe,NoOptionsMessage:ce,MultiValue:Be,MultiValueContainer:Re,MultiValueLabel:je,MultiValueRemove:function(e){var t=e.children,n=e.innerProps;return B("div",n,t||B(Oe,{size:14}))},Option:function(e){var t=e.children,n=e.className,r=e.cx,o=e.getStyles,i=e.isDisabled,u=e.isFocused,a=e.isSelected,s=e.innerRef,l=e.innerProps;return B("div",Ne({css:o("option",e),className:r({option:!0,"option--is-disabled":i,"option--is-focused":u,"option--is-selected":a},n),ref:s},l),t)},Placeholder:function(e){var t=e.children,n=e.className,r=e.cx,o=e.getStyles,i=e.innerProps;return B("div",He({css:o("placeholder",e),className:r({placeholder:!0},n)},i),t)},SelectContainer:function(e){var t=e.children,n=e.className,r=e.cx,o=e.getStyles,i=e.innerProps,u=e.isDisabled,a=e.isRtl;return B("div",ge({css:o("container",e),className:r({"--is-disabled":u,"--is-rtl":a},n)},i),t)},SingleValue:function(e){var t=e.children,n=e.className,r=e.cx,o=e.getStyles,i=e.isDisabled,u=e.innerProps;return B("div",_e({css:o("singleValue",e),className:r({"single-value":!0,"single-value--is-disabled":i},n)},u),t)},ValueContainer:function(e){var t=e.children,n=e.className,r=e.cx,o=e.isMulti,i=e.getStyles,u=e.hasValue;return B("div",{css:i("valueContainer",e),className:r({"value-container":!0,"value-container--is-multi":o,"value-container--has-value":u},n)},t)}},We=[{base:"A",letters:/[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g},{base:"AA",letters:/[\uA732]/g},{base:"AE",letters:/[\u00C6\u01FC\u01E2]/g},{base:"AO",letters:/[\uA734]/g},{base:"AU",letters:/[\uA736]/g},{base:"AV",letters:/[\uA738\uA73A]/g},{base:"AY",letters:/[\uA73C]/g},{base:"B",letters:/[\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181]/g},{base:"C",letters:/[\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E]/g},{base:"D",letters:/[\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779]/g},{base:"DZ",letters:/[\u01F1\u01C4]/g},{base:"Dz",letters:/[\u01F2\u01C5]/g},{base:"E",letters:/[\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E]/g},{base:"F",letters:/[\u0046\u24BB\uFF26\u1E1E\u0191\uA77B]/g},{base:"G",letters:/[\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E]/g},{base:"H",letters:/[\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D]/g},{base:"I",letters:/[\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197]/g},{base:"J",letters:/[\u004A\u24BF\uFF2A\u0134\u0248]/g},{base:"K",letters:/[\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2]/g},{base:"L",letters:/[\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780]/g},{base:"LJ",letters:/[\u01C7]/g},{base:"Lj",letters:/[\u01C8]/g},{base:"M",letters:/[\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C]/g},{base:"N",letters:/[\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4]/g},{base:"NJ",letters:/[\u01CA]/g},{base:"Nj",letters:/[\u01CB]/g},{base:"O",letters:/[\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C]/g},{base:"OI",letters:/[\u01A2]/g},{base:"OO",letters:/[\uA74E]/g},{base:"OU",letters:/[\u0222]/g},{base:"P",letters:/[\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754]/g},{base:"Q",letters:/[\u0051\u24C6\uFF31\uA756\uA758\u024A]/g},{base:"R",letters:/[\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782]/g},{base:"S",letters:/[\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784]/g},{base:"T",letters:/[\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786]/g},{base:"TZ",letters:/[\uA728]/g},{base:"U",letters:/[\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244]/g},{base:"V",letters:/[\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245]/g},{base:"VY",letters:/[\uA760]/g},{base:"W",letters:/[\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72]/g},{base:"X",letters:/[\u0058\u24CD\uFF38\u1E8A\u1E8C]/g},{base:"Y",letters:/[\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE]/g},{base:"Z",letters:/[\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762]/g},{base:"a",letters:/[\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250]/g},{base:"aa",letters:/[\uA733]/g},{base:"ae",letters:/[\u00E6\u01FD\u01E3]/g},{base:"ao",letters:/[\uA735]/g},{base:"au",letters:/[\uA737]/g},{base:"av",letters:/[\uA739\uA73B]/g},{base:"ay",letters:/[\uA73D]/g},{base:"b",letters:/[\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253]/g},{base:"c",letters:/[\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184]/g},{base:"d",letters:/[\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A]/g},{base:"dz",letters:/[\u01F3\u01C6]/g},{base:"e",letters:/[\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD]/g},{base:"f",letters:/[\u0066\u24D5\uFF46\u1E1F\u0192\uA77C]/g},{base:"g",letters:/[\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F]/g},{base:"h",letters:/[\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265]/g},{base:"hv",letters:/[\u0195]/g},{base:"i",letters:/[\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131]/g},{base:"j",letters:/[\u006A\u24D9\uFF4A\u0135\u01F0\u0249]/g},{base:"k",letters:/[\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3]/g},{base:"l",letters:/[\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747]/g},{base:"lj",letters:/[\u01C9]/g},{base:"m",letters:/[\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F]/g},{base:"n",letters:/[\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5]/g},{base:"nj",letters:/[\u01CC]/g},{base:"o",letters:/[\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275]/g},{base:"oi",letters:/[\u01A3]/g},{base:"ou",letters:/[\u0223]/g},{base:"oo",letters:/[\uA74F]/g},{base:"p",letters:/[\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755]/g},{base:"q",letters:/[\u0071\u24E0\uFF51\u024B\uA757\uA759]/g},{base:"r",letters:/[\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783]/g},{base:"s",letters:/[\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B]/g},{base:"t",letters:/[\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787]/g},{base:"tz",letters:/[\uA729]/g},{base:"u",letters:/[\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289]/g},{base:"v",letters:/[\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C]/g},{base:"vy",letters:/[\uA761]/g},{base:"w",letters:/[\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73]/g},{base:"x",letters:/[\u0078\u24E7\uFF58\u1E8B\u1E8D]/g},{base:"y",letters:/[\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF]/g},{base:"z",letters:/[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763]/g}],Ge=function(e){for(var t=0;t=0||(o[n]=e[n]);return o}(e,["in","out","onExited","appear","enter","exit","innerRef","emotion"]));return B("input",Ze({ref:t},n,{css:k({label:"dummyInput",background:0,border:0,fontSize:"inherit",outline:0,padding:0,width:1,color:"transparent",left:-100,opacity:0,position:"relative",transform:"scale(0)"},"")}))}var et=function(e){var t,n;function r(){return e.apply(this,arguments)||this}n=e,(t=r).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n;var o=r.prototype;return o.componentDidMount=function(){this.props.innerRef(Object(U.findDOMNode)(this))},o.componentWillUnmount=function(){this.props.innerRef(null)},o.render=function(){return this.props.children},r}(r.Component),tt=["boxSizing","height","overflow","paddingRight","position"],nt={boxSizing:"border-box",overflow:"hidden",position:"relative",height:"100%"};function rt(e){e.preventDefault()}function ot(e){e.stopPropagation()}function it(){var e=this.scrollTop,t=this.scrollHeight,n=e+this.offsetHeight;0===e?this.scrollTop=1:n===t&&(this.scrollTop=e-1)}function ut(){return"ontouchstart"in window||navigator.maxTouchPoints}var at=!(!window.document||!window.document.createElement),st=0,lt=function(e){var t,n;function r(){for(var t,n=arguments.length,r=new Array(n),o=0;o0,h=c-p-l,m=!1;h>n&&t.isBottom&&(i&&i(e),t.isBottom=!1),d&&t.isTop&&(a&&a(e),t.isTop=!1),d&&n>h?(o&&!t.isBottom&&o(e),f.scrollTop=c,m=!0,t.isBottom=!0):!d&&-n>l&&(u&&!t.isTop&&u(e),f.scrollTop=0,m=!0,t.isTop=!0),m&&t.cancelScroll(e)},t.onWheel=function(e){t.handleEventDelta(e,e.deltaY)},t.onTouchStart=function(e){t.touchStart=e.changedTouches[0].clientY},t.onTouchMove=function(e){var n=t.touchStart-e.changedTouches[0].clientY;t.handleEventDelta(e,n)},t.getScrollTarget=function(e){t.scrollTarget=e},t}n=e,(t=r).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n;var i=r.prototype;return i.componentDidMount=function(){this.startListening(this.scrollTarget)},i.componentWillUnmount=function(){this.stopListening(this.scrollTarget)},i.startListening=function(e){e&&("function"==typeof e.addEventListener&&e.addEventListener("wheel",this.onWheel,!1),"function"==typeof e.addEventListener&&e.addEventListener("touchstart",this.onTouchStart,!1),"function"==typeof e.addEventListener&&e.addEventListener("touchmove",this.onTouchMove,!1))},i.stopListening=function(e){"function"==typeof e.removeEventListener&&e.removeEventListener("wheel",this.onWheel,!1),"function"==typeof e.removeEventListener&&e.removeEventListener("touchstart",this.onTouchStart,!1),"function"==typeof e.removeEventListener&&e.removeEventListener("touchmove",this.onTouchMove,!1)},i.render=function(){return o.a.createElement(et,{innerRef:this.getScrollTarget},this.props.children)},r}(r.Component);function dt(e){var t=e.isEnabled,n=void 0===t||t,r=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r=0||(o[n]=e[n]);return o}(e,["isEnabled"]);return n?o.a.createElement(ft,r):r.children}var ht=function(e,t){void 0===t&&(t={});var n=t,r=n.isSearchable,o=n.isMulti,i=n.label,u=n.isDisabled;switch(e){case"menu":return"Use Up and Down to choose options"+(u?"":", press Enter to select the currently focused option")+", press Escape to exit the menu, press Tab to select the option and exit the menu.";case"input":return(i||"Select")+" is focused "+(r?",type to refine list":"")+", press Down to open the menu, "+(o?" press left to focus selected values":"");case"value":return"Use left and right to toggle between focused values, press Backspace to remove the currently focused value"}},mt=function(e,t){var n=t.value,r=t.isDisabled;if(n)switch(e){case"deselect-option":case"pop-value":case"remove-value":return"option "+n+", deselected.";case"select-option":return r?"option "+n+" is disabled. Select another option.":"option "+n+", selected."}},vt=function(e){return!!e.isDisabled};var gt={clearIndicator:xe,container:function(e){var t=e.isDisabled;return{label:"container",direction:e.isRtl?"rtl":null,pointerEvents:t?"none":null,position:"relative"}},control:function(e){var t=e.isDisabled,n=e.isFocused,r=e.theme,o=r.colors,i=r.borderRadius,u=r.spacing;return{label:"control",alignItems:"center",backgroundColor:t?o.neutral5:o.neutral0,borderColor:t?o.neutral10:n?o.primary:o.neutral20,borderRadius:i,borderStyle:"solid",borderWidth:1,boxShadow:n?"0 0 0 1px "+o.primary:null,cursor:"default",display:"flex",flexWrap:"wrap",justifyContent:"space-between",minHeight:u.controlHeight,outline:"0 !important",position:"relative",transition:"all 100ms","&:hover":{borderColor:n?o.primary:o.neutral30}}},dropdownIndicator:Fe,group:function(e){var t=e.theme.spacing;return{paddingBottom:2*t.baseUnit,paddingTop:2*t.baseUnit}},groupHeading:function(e){var t=e.theme.spacing;return{label:"group",color:"#999",cursor:"default",display:"block",fontSize:"75%",fontWeight:"500",marginBottom:"0.25em",paddingLeft:3*t.baseUnit,paddingRight:3*t.baseUnit,textTransform:"uppercase"}},indicatorsContainer:function(){return{alignItems:"center",alignSelf:"stretch",display:"flex",flexShrink:0}},indicatorSeparator:function(e){var t=e.isDisabled,n=e.theme,r=n.spacing.baseUnit,o=n.colors;return{label:"indicatorSeparator",alignSelf:"stretch",backgroundColor:t?o.neutral10:o.neutral20,marginBottom:2*r,marginTop:2*r,width:1}},input:function(e){var t=e.isDisabled,n=e.theme,r=n.spacing,o=n.colors;return{margin:r.baseUnit/2,paddingBottom:r.baseUnit/2,paddingTop:r.baseUnit/2,visibility:t?"hidden":"visible",color:o.neutral80}},loadingIndicator:function(e){var t=e.isFocused,n=e.size,r=e.theme,o=r.colors,i=r.spacing.baseUnit;return{label:"loadingIndicator",color:t?o.neutral60:o.neutral20,display:"flex",padding:2*i,transition:"color 150ms",alignSelf:"center",fontSize:n,lineHeight:1,marginRight:n,textAlign:"center",verticalAlign:"middle"}},loadingMessage:le,menu:function(e){var t,n=e.placement,r=e.theme,o=r.borderRadius,i=r.spacing,u=r.colors;return(t={label:"menu"})[function(e){return e?{bottom:"top",top:"bottom"}[e]:"bottom"}(n)]="100%",t.backgroundColor=u.neutral0,t.borderRadius=o,t.boxShadow="0 0 0 1px hsla(0, 0%, 0%, 0.1), 0 4px 11px hsla(0, 0%, 0%, 0.1)",t.marginBottom=i.menuGutter,t.marginTop=i.menuGutter,t.position="absolute",t.width="100%",t.zIndex=1,t},menuList:function(e){var t=e.maxHeight,n=e.theme.spacing.baseUnit;return{maxHeight:t,overflowY:"auto",paddingBottom:n,paddingTop:n,position:"relative",WebkitOverflowScrolling:"touch"}},menuPortal:function(e){var t=e.rect,n=e.offset,r=e.position;return{left:t.left,position:r,top:n,width:t.width,zIndex:1}},multiValue:function(e){var t=e.theme,n=t.spacing,r=t.borderRadius;return{label:"multiValue",backgroundColor:t.colors.neutral10,borderRadius:r/2,display:"flex",margin:n.baseUnit/2,minWidth:0}},multiValueLabel:function(e){var t=e.theme,n=t.borderRadius,r=t.colors,o=e.cropWithEllipsis;return{borderRadius:n/2,color:r.neutral80,fontSize:"85%",overflow:"hidden",padding:3,paddingLeft:6,textOverflow:o?"ellipsis":null,whiteSpace:"nowrap"}},multiValueRemove:function(e){var t=e.theme,n=t.spacing,r=t.borderRadius,o=t.colors;return{alignItems:"center",borderRadius:r/2,backgroundColor:e.isFocused&&o.dangerLight,display:"flex",paddingLeft:n.baseUnit,paddingRight:n.baseUnit,":hover":{backgroundColor:o.dangerLight,color:o.danger}}},noOptionsMessage:se,option:function(e){var t=e.isDisabled,n=e.isFocused,r=e.isSelected,o=e.theme,i=o.spacing,u=o.colors;return{label:"option",backgroundColor:r?u.primary:n?u.primary25:"transparent",color:t?u.neutral20:r?u.neutral0:"inherit",cursor:"default",display:"block",fontSize:"inherit",padding:2*i.baseUnit+"px "+3*i.baseUnit+"px",width:"100%",userSelect:"none",WebkitTapHighlightColor:"rgba(0, 0, 0, 0)",":active":{backgroundColor:!t&&(r?u.primary:u.primary50)}}},placeholder:function(e){var t=e.theme,n=t.spacing;return{label:"placeholder",color:t.colors.neutral50,marginLeft:n.baseUnit/2,marginRight:n.baseUnit/2,position:"absolute",top:"50%",transform:"translateY(-50%)"}},singleValue:function(e){var t=e.isDisabled,n=e.theme,r=n.spacing,o=n.colors;return{label:"singleValue",color:t?o.neutral40:o.neutral80,marginLeft:r.baseUnit/2,marginRight:r.baseUnit/2,maxWidth:"calc(100% - "+2*r.baseUnit+"px)",overflow:"hidden",position:"absolute",textOverflow:"ellipsis",whiteSpace:"nowrap",top:"50%",transform:"translateY(-50%)"}},valueContainer:function(e){var t=e.theme.spacing;return{alignItems:"center",display:"flex",flex:1,flexWrap:"wrap",padding:t.baseUnit/2+"px "+2*t.baseUnit+"px",WebkitOverflowScrolling:"touch",position:"relative",overflow:"hidden"}}};var bt={borderRadius:4,colors:{primary:"#2684FF",primary75:"#4C9AFF",primary50:"#B2D4FF",primary25:"#DEEBFF",danger:"#DE350B",dangerLight:"#FFBDAD",neutral0:"hsl(0, 0%, 100%)",neutral5:"hsl(0, 0%, 95%)",neutral10:"hsl(0, 0%, 90%)",neutral20:"hsl(0, 0%, 80%)",neutral30:"hsl(0, 0%, 70%)",neutral40:"hsl(0, 0%, 60%)",neutral50:"hsl(0, 0%, 50%)",neutral60:"hsl(0, 0%, 40%)",neutral70:"hsl(0, 0%, 30%)",neutral80:"hsl(0, 0%, 20%)",neutral90:"hsl(0, 0%, 10%)"},spacing:{baseUnit:4,controlHeight:38,menuGutter:8}};function Et(){return(Et=Object.assign||function(e){for(var t=1;t-1},formatGroupLabel:function(e){return e.label},getOptionLabel:function(e){return e.label},getOptionValue:function(e){return e.value},isDisabled:!1,isLoading:!1,isMulti:!1,isRtl:!1,isSearchable:!0,isOptionDisabled:vt,loadingMessage:function(){return"Loading..."},maxMenuHeight:300,minMenuHeight:140,menuIsOpen:!1,menuPlacement:"bottom",menuPosition:"absolute",menuShouldBlockScroll:!1,menuShouldScrollIntoView:!function(){try{return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)}catch(e){return!1}}(),noOptionsMessage:function(){return"No options"},openMenuOnFocus:!1,openMenuOnClick:!0,options:[],pageSize:5,placeholder:"Select...",screenReaderStatus:function(e){var t=e.count;return t+" result"+(1!==t?"s":"")+" available"},styles:{},tabIndex:"0",tabSelectsValue:!0},At=1,wt=function(e){var t,n;function r(t){var n;(n=e.call(this,t)||this).state={ariaLiveSelection:"",ariaLiveContext:"",focusedOption:null,focusedValue:null,inputIsHidden:!1,isFocused:!1,menuOptions:{render:[],focusable:[]},selectValue:[]},n.blockOptionHover=!1,n.isComposing=!1,n.clearFocusValueOnUpdate=!1,n.commonProps=void 0,n.components=void 0,n.hasGroups=!1,n.initialTouchX=0,n.initialTouchY=0,n.inputIsHiddenAfterUpdate=void 0,n.instancePrefix="",n.openAfterFocus=!1,n.scrollToFocusedOptionOnUpdate=!1,n.userIsDragging=void 0,n.controlRef=null,n.getControlRef=function(e){n.controlRef=e},n.focusedOptionRef=null,n.getFocusedOptionRef=function(e){n.focusedOptionRef=e},n.menuListRef=null,n.getMenuListRef=function(e){n.menuListRef=e},n.inputRef=null,n.getInputRef=function(e){n.inputRef=e},n.cacheComponents=function(e){n.components=Ue({},ze,{components:e}.components)},n.focus=n.focusInput,n.blur=n.blurInput,n.onChange=function(e,t){var r=n.props;(0,r.onChange)(e,Et({},t,{name:r.name}))},n.setValue=function(e,t,r){void 0===t&&(t="set-value");var o=n.props,i=o.closeMenuOnSelect,u=o.isMulti;n.onInputChange("",{action:"set-value"}),i&&(n.inputIsHiddenAfterUpdate=!u,n.onMenuClose()),n.clearFocusValueOnUpdate=!0,n.onChange(e,{action:t,option:r})},n.selectOption=function(e){var t=n.props,r=t.blurInputOnSelect,o=t.isMulti,i=n.state.selectValue;if(o)if(n.isOptionSelected(e,i)){var u=n.getOptionValue(e);n.setValue(i.filter((function(e){return n.getOptionValue(e)!==u})),"deselect-option",e),n.announceAriaLiveSelection({event:"deselect-option",context:{value:n.getOptionLabel(e)}})}else n.isOptionDisabled(e,i)?n.announceAriaLiveSelection({event:"select-option",context:{value:n.getOptionLabel(e),isDisabled:!0}}):(n.setValue([].concat(i,[e]),"select-option",e),n.announceAriaLiveSelection({event:"select-option",context:{value:n.getOptionLabel(e)}}));else n.isOptionDisabled(e,i)?n.announceAriaLiveSelection({event:"select-option",context:{value:n.getOptionLabel(e),isDisabled:!0}}):(n.setValue(e,"select-option"),n.announceAriaLiveSelection({event:"select-option",context:{value:n.getOptionLabel(e)}}));r&&n.blurInput()},n.removeValue=function(e){var t=n.state.selectValue,r=n.getOptionValue(e),o=t.filter((function(e){return n.getOptionValue(e)!==r}));n.onChange(o.length?o:null,{action:"remove-value",removedValue:e}),n.announceAriaLiveSelection({event:"remove-value",context:{value:e?n.getOptionLabel(e):""}}),n.focusInput()},n.clearValue=function(){var e=n.props.isMulti;n.onChange(e?[]:null,{action:"clear"})},n.popValue=function(){var e=n.state.selectValue,t=e[e.length-1],r=e.slice(0,e.length-1);n.announceAriaLiveSelection({event:"pop-value",context:{value:t?n.getOptionLabel(t):""}}),n.onChange(r.length?r:null,{action:"pop-value",removedValue:t})},n.getOptionLabel=function(e){return n.props.getOptionLabel(e)},n.getOptionValue=function(e){return n.props.getOptionValue(e)},n.getStyles=function(e,t){var r=gt[e](t);r.boxSizing="border-box";var o=n.props.styles[e];return o?o(r,t):r},n.getElementId=function(e){return n.instancePrefix+"-"+e},n.getActiveDescendentId=function(){var e=n.props.menuIsOpen,t=n.state,r=t.menuOptions,o=t.focusedOption;if(o&&e){var i=r.focusable.indexOf(o),u=r.render[i];return u&&u.key}},n.announceAriaLiveSelection=function(e){var t=e.event,r=e.context;n.setState({ariaLiveSelection:mt(t,r)})},n.announceAriaLiveContext=function(e){var t=e.event,r=e.context;n.setState({ariaLiveContext:ht(t,Et({},r,{label:n.props["aria-label"]}))})},n.onMenuMouseDown=function(e){0===e.button&&(e.stopPropagation(),e.preventDefault(),n.focusInput())},n.onMenuMouseMove=function(e){n.blockOptionHover=!1},n.onControlMouseDown=function(e){var t=n.props.openMenuOnClick;n.state.isFocused?n.props.menuIsOpen?"INPUT"!==e.target.tagName&&"TEXTAREA"!==e.target.tagName&&n.onMenuClose():t&&n.openMenu("first"):(t&&(n.openAfterFocus=!0),n.focusInput()),"INPUT"!==e.target.tagName&&"TEXTAREA"!==e.target.tagName&&e.preventDefault()},n.onDropdownIndicatorMouseDown=function(e){if(!(e&&"mousedown"===e.type&&0!==e.button||n.props.isDisabled)){var t=n.props,r=t.isMulti,o=t.menuIsOpen;n.focusInput(),o?(n.inputIsHiddenAfterUpdate=!r,n.onMenuClose()):n.openMenu("first"),e.preventDefault(),e.stopPropagation()}},n.onClearIndicatorMouseDown=function(e){e&&"mousedown"===e.type&&0!==e.button||(n.clearValue(),e.stopPropagation(),n.openAfterFocus=!1,"touchend"===e.type?n.focusInput():setTimeout((function(){return n.focusInput()})))},n.onScroll=function(e){"boolean"==typeof n.props.closeMenuOnScroll?e.target instanceof HTMLElement&&K(e.target)&&n.props.onMenuClose():"function"==typeof n.props.closeMenuOnScroll&&n.props.closeMenuOnScroll(e)&&n.props.onMenuClose()},n.onCompositionStart=function(){n.isComposing=!0},n.onCompositionEnd=function(){n.isComposing=!1},n.onTouchStart=function(e){var t=e.touches.item(0);t&&(n.initialTouchX=t.clientX,n.initialTouchY=t.clientY,n.userIsDragging=!1)},n.onTouchMove=function(e){var t=e.touches.item(0);if(t){var r=Math.abs(t.clientX-n.initialTouchX),o=Math.abs(t.clientY-n.initialTouchY);n.userIsDragging=r>5||o>5}},n.onTouchEnd=function(e){n.userIsDragging||(n.controlRef&&!n.controlRef.contains(e.target)&&n.menuListRef&&!n.menuListRef.contains(e.target)&&n.blurInput(),n.initialTouchX=0,n.initialTouchY=0)},n.onControlTouchEnd=function(e){n.userIsDragging||n.onControlMouseDown(e)},n.onClearIndicatorTouchEnd=function(e){n.userIsDragging||n.onClearIndicatorMouseDown(e)},n.onDropdownIndicatorTouchEnd=function(e){n.userIsDragging||n.onDropdownIndicatorMouseDown(e)},n.handleInputChange=function(e){var t=e.currentTarget.value;n.inputIsHiddenAfterUpdate=!1,n.onInputChange(t,{action:"input-change"}),n.onMenuOpen()},n.onInputFocus=function(e){var t=n.props,r=t.isSearchable,o=t.isMulti;n.props.onFocus&&n.props.onFocus(e),n.inputIsHiddenAfterUpdate=!1,n.announceAriaLiveContext({event:"input",context:{isSearchable:r,isMulti:o}}),n.setState({isFocused:!0}),(n.openAfterFocus||n.props.openMenuOnFocus)&&n.openMenu("first"),n.openAfterFocus=!1},n.onInputBlur=function(e){n.menuListRef&&n.menuListRef.contains(document.activeElement)?n.inputRef.focus():(n.props.onBlur&&n.props.onBlur(e),n.onInputChange("",{action:"input-blur"}),n.onMenuClose(),n.setState({focusedValue:null,isFocused:!1}))},n.onOptionHover=function(e){n.blockOptionHover||n.state.focusedOption===e||n.setState({focusedOption:e})},n.shouldHideSelectedOptions=function(){var e=n.props,t=e.hideSelectedOptions,r=e.isMulti;return void 0===t?r:t},n.onKeyDown=function(e){var t=n.props,r=t.isMulti,o=t.backspaceRemovesValue,i=t.escapeClearsValue,u=t.inputValue,a=t.isClearable,s=t.isDisabled,l=t.menuIsOpen,c=t.onKeyDown,p=t.tabSelectsValue,f=t.openMenuOnFocus,d=n.state,h=d.focusedOption,m=d.focusedValue,v=d.selectValue;if(!(s||"function"==typeof c&&(c(e),e.defaultPrevented))){switch(n.blockOptionHover=!0,e.key){case"ArrowLeft":if(!r||u)return;n.focusValue("previous");break;case"ArrowRight":if(!r||u)return;n.focusValue("next");break;case"Delete":case"Backspace":if(u)return;if(m)n.removeValue(m);else{if(!o)return;r?n.popValue():a&&n.clearValue()}break;case"Tab":if(n.isComposing)return;if(e.shiftKey||!l||!p||!h||f&&n.isOptionSelected(h,v))return;n.selectOption(h);break;case"Enter":if(229===e.keyCode)break;if(l){if(!h)return;if(n.isComposing)return;n.selectOption(h);break}return;case"Escape":l?(n.inputIsHiddenAfterUpdate=!1,n.onInputChange("",{action:"menu-close"}),n.onMenuClose()):a&&i&&n.clearValue();break;case" ":if(u)return;if(!l){n.openMenu("first");break}if(!h)return;n.selectOption(h);break;case"ArrowUp":l?n.focusOption("up"):n.openMenu("last");break;case"ArrowDown":l?n.focusOption("down"):n.openMenu("first");break;case"PageUp":if(!l)return;n.focusOption("pageup");break;case"PageDown":if(!l)return;n.focusOption("pagedown");break;case"Home":if(!l)return;n.focusOption("first");break;case"End":if(!l)return;n.focusOption("last");break;default:return}e.preventDefault()}},n.buildMenuOptions=function(e,t){var r=e.inputValue,o=void 0===r?"":r,i=e.options,u=function(e,r){var i=n.isOptionDisabled(e,t),u=n.isOptionSelected(e,t),a=n.getOptionLabel(e),s=n.getOptionValue(e);if(!(n.shouldHideSelectedOptions()&&u||!n.filterOption({label:a,value:s,data:e},o))){var l=i?void 0:function(){return n.onOptionHover(e)},c=i?void 0:function(){return n.selectOption(e)},p=n.getElementId("option")+"-"+r;return{innerProps:{id:p,onClick:c,onMouseMove:l,onMouseOver:l,tabIndex:-1},data:e,isDisabled:i,isSelected:u,key:p,label:a,type:"option",value:s}}};return i.reduce((function(e,t,r){if(t.options){n.hasGroups||(n.hasGroups=!0);var o=t.options.map((function(t,n){var o=u(t,r+"-"+n);return o&&e.focusable.push(t),o})).filter(Boolean);if(o.length){var i=n.getElementId("group")+"-"+r;e.render.push({type:"group",key:i,data:t,options:o})}}else{var a=u(t,""+r);a&&(e.render.push(a),e.focusable.push(t))}return e}),{render:[],focusable:[]})};var r=t.value;n.cacheComponents=u(n.cacheComponents,ve).bind(yt(yt(n))),n.cacheComponents(t.components),n.instancePrefix="react-select-"+(n.props.instanceId||++At);var o=X(r);n.buildMenuOptions=u(n.buildMenuOptions,(function(e,t){var n=e,r=n[0],o=n[1],i=t,u=i[0];return ve(o,i[1])&&ve(r.inputValue,u.inputValue)&&ve(r.options,u.options)})).bind(yt(yt(n)));var i=t.menuIsOpen?n.buildMenuOptions(t,o):{render:[],focusable:[]};return n.state.menuOptions=i,n.state.selectValue=o,n}n=e,(t=r).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n;var i=r.prototype;return i.componentDidMount=function(){this.startListeningComposition(),this.startListeningToTouch(),this.props.closeMenuOnScroll&&document&&document.addEventListener&&document.addEventListener("scroll",this.onScroll,!0),this.props.autoFocus&&this.focusInput()},i.UNSAFE_componentWillReceiveProps=function(e){var t=this.props,n=t.options,r=t.value,o=t.menuIsOpen,i=t.inputValue;if(this.cacheComponents(e.components),e.value!==r||e.options!==n||e.menuIsOpen!==o||e.inputValue!==i){var u=X(e.value),a=e.menuIsOpen?this.buildMenuOptions(e,u):{render:[],focusable:[]},s=this.getNextFocusedValue(u),l=this.getNextFocusedOption(a.focusable);this.setState({menuOptions:a,selectValue:u,focusedOption:l,focusedValue:s})}null!=this.inputIsHiddenAfterUpdate&&(this.setState({inputIsHidden:this.inputIsHiddenAfterUpdate}),delete this.inputIsHiddenAfterUpdate)},i.componentDidUpdate=function(e){var t,n,r,o,i,u=this.props,a=u.isDisabled,s=u.menuIsOpen,l=this.state.isFocused;(l&&!a&&e.isDisabled||l&&s&&!e.menuIsOpen)&&this.focusInput(),this.menuListRef&&this.focusedOptionRef&&this.scrollToFocusedOptionOnUpdate&&(t=this.menuListRef,n=this.focusedOptionRef,r=t.getBoundingClientRect(),o=n.getBoundingClientRect(),i=n.offsetHeight/3,o.bottom+i>r.bottom?q(t,Math.min(n.offsetTop+n.clientHeight-t.offsetHeight+i,t.scrollHeight)):o.top-i-1&&(a=s)}this.scrollToFocusedOptionOnUpdate=!(o&&this.menuListRef),this.inputIsHiddenAfterUpdate=!1,this.setState({menuOptions:i,focusedValue:null,focusedOption:i.focusable[a]},(function(){t.onMenuOpen(),t.announceAriaLiveContext({event:"menu"})}))},i.focusValue=function(e){var t=this.props,n=t.isMulti,r=t.isSearchable,o=this.state,i=o.selectValue,u=o.focusedValue;if(n){this.setState({focusedOption:null});var a=i.indexOf(u);u||(a=-1,this.announceAriaLiveContext({event:"value"}));var s=i.length-1,l=-1;if(i.length){switch(e){case"previous":l=0===a?0:-1===a?s:a-1;break;case"next":a>-1&&a0?u-1:o.length-1:"down"===e?i=(u+1)%o.length:"pageup"===e?(i=u-t)<0&&(i=0):"pagedown"===e?(i=u+t)>o.length-1&&(i=o.length-1):"last"===e&&(i=o.length-1),this.scrollToFocusedOptionOnUpdate=!0,this.setState({focusedOption:o[i],focusedValue:null}),this.announceAriaLiveContext({event:"menu",context:{isDisabled:vt(o[i])}})}},i.getTheme=function(){return this.props.theme?"function"==typeof this.props.theme?this.props.theme(bt):Et({},bt,this.props.theme):bt},i.getCommonProps=function(){var e=this.clearValue,t=this.getStyles,n=this.setValue,r=this.selectOption,o=this.props,i=o.classNamePrefix,u=o.isMulti,a=o.isRtl,s=o.options,l=this.state.selectValue,c=this.hasValue();return{cx:Y.bind(null,i),clearValue:e,getStyles:t,getValue:function(){return l},hasValue:c,isMulti:u,isRtl:a,options:s,selectOption:r,setValue:n,selectProps:o,theme:this.getTheme()}},i.getNextFocusedValue=function(e){if(this.clearFocusValueOnUpdate)return this.clearFocusValueOnUpdate=!1,null;var t=this.state,n=t.focusedValue,r=t.selectValue.indexOf(n);if(r>-1){if(e.indexOf(n)>-1)return n;if(r-1?t:e[0]},i.hasValue=function(){return this.state.selectValue.length>0},i.hasOptions=function(){return!!this.state.menuOptions.render.length},i.countOptions=function(){return this.state.menuOptions.focusable.length},i.isClearable=function(){var e=this.props,t=e.isClearable,n=e.isMulti;return void 0===t?n:t},i.isOptionDisabled=function(e,t){return"function"==typeof this.props.isOptionDisabled&&this.props.isOptionDisabled(e,t)},i.isOptionSelected=function(e,t){var n=this;if(t.indexOf(e)>-1)return!0;if("function"==typeof this.props.isOptionSelected)return this.props.isOptionSelected(e,t);var r=this.getOptionValue(e);return t.some((function(e){return n.getOptionValue(e)===r}))},i.filterOption=function(e,t){return!this.props.filterOption||this.props.filterOption(e,t)},i.formatOptionLabel=function(e,t){if("function"==typeof this.props.formatOptionLabel){var n=this.props.inputValue,r=this.state.selectValue;return this.props.formatOptionLabel(e,{context:t,inputValue:n,selectValue:r})}return this.getOptionLabel(e)},i.formatGroupLabel=function(e){return this.props.formatGroupLabel(e)},i.startListeningComposition=function(){document&&document.addEventListener&&(document.addEventListener("compositionstart",this.onCompositionStart,!1),document.addEventListener("compositionend",this.onCompositionEnd,!1))},i.stopListeningComposition=function(){document&&document.removeEventListener&&(document.removeEventListener("compositionstart",this.onCompositionStart),document.removeEventListener("compositionend",this.onCompositionEnd))},i.startListeningToTouch=function(){document&&document.addEventListener&&(document.addEventListener("touchstart",this.onTouchStart,!1),document.addEventListener("touchmove",this.onTouchMove,!1),document.addEventListener("touchend",this.onTouchEnd,!1))},i.stopListeningToTouch=function(){document&&document.removeEventListener&&(document.removeEventListener("touchstart",this.onTouchStart),document.removeEventListener("touchmove",this.onTouchMove),document.removeEventListener("touchend",this.onTouchEnd))},i.constructAriaLiveMessage=function(){var e=this.state,t=e.ariaLiveContext,n=e.selectValue,r=e.focusedValue,o=e.focusedOption,i=this.props,u=i.options,a=i.menuIsOpen,s=i.inputValue,l=i.screenReaderStatus;return(r?function(e){var t=e.focusedValue,n=e.getOptionLabel,r=e.selectValue;return"value "+n(t)+" focused, "+(r.indexOf(t)+1)+" of "+r.length+"."}({focusedValue:r,getOptionLabel:this.getOptionLabel,selectValue:n}):"")+" "+(o&&a?function(e){var t=e.focusedOption,n=e.getOptionLabel,r=e.options;return"option "+n(t)+" focused"+(t.isDisabled?" disabled":"")+", "+(r.indexOf(t)+1)+" of "+r.length+"."}({focusedOption:o,getOptionLabel:this.getOptionLabel,options:u}):"")+" "+function(e){var t=e.inputValue;return e.screenReaderMessage+(t?" for search term "+t:"")+"."}({inputValue:s,screenReaderMessage:l({count:this.countOptions()})})+" "+t},i.renderInput=function(){var e=this.props,t=e.isDisabled,n=e.isSearchable,r=e.inputId,i=e.inputValue,u=e.tabIndex,a=this.components.Input,s=this.state.inputIsHidden,l=r||this.getElementId("input"),c={"aria-autocomplete":"list","aria-label":this.props["aria-label"],"aria-labelledby":this.props["aria-labelledby"]};if(!n)return o.a.createElement(Qe,Et({id:l,innerRef:this.getInputRef,onBlur:this.onInputBlur,onChange:G,onFocus:this.onInputFocus,readOnly:!0,disabled:t,tabIndex:u,value:""},c));var p=this.commonProps,f=p.cx,d=p.theme,h=p.selectProps;return o.a.createElement(a,Et({autoCapitalize:"none",autoComplete:"off",autoCorrect:"off",cx:f,getStyles:this.getStyles,id:l,innerRef:this.getInputRef,isDisabled:t,isHidden:s,onBlur:this.onInputBlur,onChange:this.handleInputChange,onFocus:this.onInputFocus,selectProps:h,spellCheck:"false",tabIndex:u,theme:d,type:"text",value:i},c))},i.renderPlaceholderOrValue=function(){var e=this,t=this.components,n=t.MultiValue,r=t.MultiValueContainer,i=t.MultiValueLabel,u=t.MultiValueRemove,a=t.SingleValue,s=t.Placeholder,l=this.commonProps,c=this.props,p=c.controlShouldRenderValue,f=c.isDisabled,d=c.isMulti,h=c.inputValue,m=c.placeholder,v=this.state,g=v.selectValue,b=v.focusedValue,E=v.isFocused;if(!this.hasValue()||!p)return h?null:o.a.createElement(s,Et({},l,{key:"placeholder",isDisabled:f,isFocused:E}),m);if(d)return g.map((function(t,a){var s=t===b;return o.a.createElement(n,Et({},l,{components:{Container:r,Label:i,Remove:u},isFocused:s,isDisabled:f,key:e.getOptionValue(t),index:a,removeProps:{onClick:function(){return e.removeValue(t)},onTouchEnd:function(){return e.removeValue(t)},onMouseDown:function(e){e.preventDefault(),e.stopPropagation()}},data:t}),e.formatOptionLabel(t,"value"))}));if(h)return null;var y=g[0];return o.a.createElement(a,Et({},l,{data:y,isDisabled:f}),this.formatOptionLabel(y,"value"))},i.renderClearIndicator=function(){var e=this.components.ClearIndicator,t=this.commonProps,n=this.props,r=n.isDisabled,i=n.isLoading,u=this.state.isFocused;if(!this.isClearable()||!e||r||!this.hasValue()||i)return null;var a={onMouseDown:this.onClearIndicatorMouseDown,onTouchEnd:this.onClearIndicatorTouchEnd,"aria-hidden":"true"};return o.a.createElement(e,Et({},t,{innerProps:a,isFocused:u}))},i.renderLoadingIndicator=function(){var e=this.components.LoadingIndicator,t=this.commonProps,n=this.props,r=n.isDisabled,i=n.isLoading,u=this.state.isFocused;if(!e||!i)return null;return o.a.createElement(e,Et({},t,{innerProps:{"aria-hidden":"true"},isDisabled:r,isFocused:u}))},i.renderIndicatorSeparator=function(){var e=this.components,t=e.DropdownIndicator,n=e.IndicatorSeparator;if(!t||!n)return null;var r=this.commonProps,i=this.props.isDisabled,u=this.state.isFocused;return o.a.createElement(n,Et({},r,{isDisabled:i,isFocused:u}))},i.renderDropdownIndicator=function(){var e=this.components.DropdownIndicator;if(!e)return null;var t=this.commonProps,n=this.props.isDisabled,r=this.state.isFocused,i={onMouseDown:this.onDropdownIndicatorMouseDown,onTouchEnd:this.onDropdownIndicatorTouchEnd,"aria-hidden":"true"};return o.a.createElement(e,Et({},t,{innerProps:i,isDisabled:n,isFocused:r}))},i.renderMenu=function(){var e=this,t=this.components,n=t.Group,r=t.GroupHeading,i=t.Menu,u=t.MenuList,a=t.MenuPortal,s=t.LoadingMessage,l=t.NoOptionsMessage,c=t.Option,p=this.commonProps,f=this.state,d=f.focusedOption,h=f.menuOptions,m=this.props,v=m.captureMenuScroll,g=m.inputValue,b=m.isLoading,E=m.loadingMessage,y=m.minMenuHeight,C=m.maxMenuHeight,O=m.menuIsOpen,A=m.menuPlacement,w=m.menuPosition,F=m.menuPortalTarget,x=m.menuShouldBlockScroll,S=m.menuShouldScrollIntoView,D=m.noOptionsMessage,k=m.onMenuScrollToTop,I=m.onMenuScrollToBottom;if(!O)return null;var M,P=function(t){var n=d===t.data;return t.innerRef=n?e.getFocusedOptionRef:void 0,o.a.createElement(c,Et({},p,t,{isFocused:n}),e.formatOptionLabel(t.data,"menu"))};if(this.hasOptions())M=h.render.map((function(t){if("group"===t.type){t.type;var i=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r=0||(o[n]=e[n]);return o}(t,["type"]),u=t.key+"-heading";return o.a.createElement(n,Et({},p,i,{Heading:r,headingProps:{id:u},label:e.formatGroupLabel(t.data)}),t.options.map((function(e){return P(e)})))}if("option"===t.type)return P(t)}));else if(b){var L=E({inputValue:g});if(null===L)return null;M=o.a.createElement(s,p,L)}else{var V=D({inputValue:g});if(null===V)return null;M=o.a.createElement(l,p,V)}var T={minMenuHeight:y,maxMenuHeight:C,menuPlacement:A,menuPosition:w,menuShouldScrollIntoView:S},R=o.a.createElement(ue,Et({},p,T),(function(t){var n=t.ref,r=t.placerProps,a=r.placement,s=r.maxHeight;return o.a.createElement(i,Et({},p,T,{innerRef:n,innerProps:{onMouseDown:e.onMenuMouseDown,onMouseMove:e.onMenuMouseMove},isLoading:b,placement:a}),o.a.createElement(dt,{isEnabled:v,onTopArrive:k,onBottomArrive:I},o.a.createElement(pt,{isEnabled:x},o.a.createElement(u,Et({},p,{innerRef:e.getMenuListRef,isLoading:b,maxHeight:s}),M))))}));return F||"fixed"===w?o.a.createElement(a,Et({},p,{appendTo:F,controlElement:this.controlRef,menuPlacement:A,menuPosition:w}),R):R},i.renderFormField=function(){var e=this,t=this.props,n=t.delimiter,r=t.isDisabled,i=t.isMulti,u=t.name,a=this.state.selectValue;if(u&&!r){if(i){if(n){var s=a.map((function(t){return e.getOptionValue(t)})).join(n);return o.a.createElement("input",{name:u,type:"hidden",value:s})}var l=a.length>0?a.map((function(t,n){return o.a.createElement("input",{key:"i-"+n,name:u,type:"hidden",value:e.getOptionValue(t)})})):o.a.createElement("input",{name:u,type:"hidden"});return o.a.createElement("div",null,l)}var c=a[0]?this.getOptionValue(a[0]):"";return o.a.createElement("input",{name:u,type:"hidden",value:c})}},i.renderLiveRegion=function(){return this.state.isFocused?o.a.createElement(qe,{"aria-live":"polite"},o.a.createElement("p",{id:"aria-selection-event"},"\xa0",this.state.ariaLiveSelection),o.a.createElement("p",{id:"aria-context"},"\xa0",this.constructAriaLiveMessage())):null},i.render=function(){var e=this.components,t=e.Control,n=e.IndicatorsContainer,r=e.SelectContainer,i=e.ValueContainer,u=this.props,a=u.className,s=u.id,l=u.isDisabled,c=u.menuIsOpen,p=this.state.isFocused,f=this.commonProps=this.getCommonProps();return o.a.createElement(r,Et({},f,{className:a,innerProps:{id:s,onKeyDown:this.onKeyDown},isDisabled:l,isFocused:p}),this.renderLiveRegion(),o.a.createElement(t,Et({},f,{innerRef:this.getControlRef,innerProps:{onMouseDown:this.onControlMouseDown,onTouchEnd:this.onControlTouchEnd},isDisabled:l,isFocused:p,menuIsOpen:c}),o.a.createElement(i,Et({},f,{isDisabled:l}),this.renderPlaceholderOrValue(),this.renderInput()),o.a.createElement(n,Et({},f,{isDisabled:l}),this.renderClearIndicator(),this.renderLoadingIndicator(),this.renderIndicatorSeparator(),this.renderDropdownIndicator())),this.renderMenu(),this.renderFormField())},r}(r.Component);function Ft(){return(Ft=Object.assign||function(e){for(var t=1;t1?n-1:0),o=1;o=0||(o[n]=e[n]);return o}(t,["defaultInputValue","defaultMenuIsOpen","defaultValue"]));return o.a.createElement(St,Ft({},n,{ref:function(t){e.select=t},inputValue:this.getProp("inputValue"),menuIsOpen:this.getProp("menuIsOpen"),onChange:this.onChange,onInputChange:this.onInputChange,onMenuClose:this.onMenuClose,onMenuOpen:this.onMenuOpen,value:this.getProp("value")}))},r}(r.Component),Dt.defaultProps=xt,kt);t.a=It},451:function(e,t,n){"use strict";var r=n(0),o=Object(r.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=o},462:function(e,t,n){var r=n(30),o=n(54),i=n(27),u=n(26),a=n(463);e.exports=function(e,t){var n=1==e,s=2==e,l=3==e,c=4==e,p=6==e,f=5==e||p,d=t||a;return function(t,a,h){for(var m,v,g=i(t),b=o(g),E=r(a,h,3),y=u(b.length),C=0,O=n?d(t,y):s?d(t,0):void 0;y>C;C++)if((f||C in b)&&(v=E(m=b[C],C,g),e))if(n)O[C]=v;else if(v)switch(e){case 3:return!0;case 5:return m;case 6:return C;case 2:O.push(m)}else if(c)return!1;return p?-1:l||c?c:O}}},463:function(e,t,n){var r=n(464);e.exports=function(e,t){return new(r(e))(t)}},464:function(e,t,n){var r=n(13),o=n(465),i=n(2)("species");e.exports=function(e){var t;return o(e)&&("function"!=typeof(t=e.constructor)||t!==Array&&!o(t.prototype)||(t=void 0),r(t)&&null===(t=t[i])&&(t=void 0)),void 0===t?Array:t}},465:function(e,t,n){var r=n(23);e.exports=Array.isArray||function(e){return"Array"==r(e)}},483:function(e,t){e.exports=Object.is||function(e,t){return e===t?0!==e||1/e==1/t:e!=e&&t!=t}},563:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=Object.assign||function(e){for(var t=1;t=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}(this.props,[]);return function(e){c.forEach((function(t){return delete e[t]}))}(o),o.className=this.props.inputClassName,o.id=this.state.inputId,o.style=n,u.default.createElement("div",{className:this.props.className,style:t},this.renderStyles(),u.default.createElement("input",r({},o,{ref:this.inputRef})),u.default.createElement("div",{ref:this.sizerRef,style:l},e),this.props.placeholder?u.default.createElement("div",{ref:this.placeHolderSizerRef,style:l},this.props.placeholder):null)}}]),t}(i.Component);h.propTypes={className:a.default.string,defaultValue:a.default.any,extraWidth:a.default.oneOfType([a.default.number,a.default.string]),id:a.default.string,injectStyles:a.default.bool,inputClassName:a.default.string,inputRef:a.default.func,inputStyle:a.default.object,minWidth:a.default.oneOfType([a.default.number,a.default.string]),onAutosize:a.default.func,onChange:a.default.func,placeholder:a.default.string,placeholderIsMinWidth:a.default.bool,style:a.default.object,value:a.default.any},h.defaultProps={minWidth:1,injectStyles:!0},t.default=h}}]); \ No newline at end of file +/*! For license information please see 1.5236ee97.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[1],{423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=o.a.createContext({}),c=function(e){var t=o.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a({},t,{},e)),n},p=function(e){var t=c(e.components);return o.a.createElement(l.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,u=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=c(n),d=r,h=p["".concat(u,".").concat(d)]||p[d]||f[d]||i;return n?o.a.createElement(h,a({ref:t},l,{components:n})):o.a.createElement(h,a({ref:t},l))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,u=new Array(i);u[0]=d;var a={};for(var s in t)hasOwnProperty.call(t,s)&&(a[s]=t[s]);a.originalType=e,a.mdxType="string"==typeof e?e:r,u[1]=a;for(var l=2;l1?arguments[1]:void 0,n),s=u>2?arguments[2]:void 0,l=void 0===s?n:o(s,n);l>a;)t[a++]=e;return t}},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function i(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(o),i,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[i(t,e),"[",r,"]"].join(""):[i(t,e),"[",i(r,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return i(r,t);if(Array.isArray(o)){var u=[];return o.slice().forEach((function(e){void 0!==e&&u.push(n(r,e,u.length))})),u.join("&")}return i(r,t)+"="+i(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},439:function(e,t,n){"use strict";var r=n(12),o=n(465)(5),i=!0;"find"in[]&&Array(1).find((function(){i=!1})),r(r.P+r.F*i,"Array",{find:function(e){return o(this,e,arguments.length>1?arguments[1]:void 0)}}),n(74)("find")},442:function(e,t,n){"use strict";var r=n(8),o=n(486),i=n(55);n(56)("search",1,(function(e,t,n,u){return[function(n){var r=e(this),o=null==n?void 0:n[t];return void 0!==o?o.call(n,r):new RegExp(n)[t](String(r))},function(e){var t=u(n,e,this);if(t.done)return t.value;var a=r(e),s=String(this),l=a.lastIndex;o(l,0)||(a.lastIndex=0);var c=i(a,s);return o(a.lastIndex,l)||(a.lastIndex=l),null===c?-1:c.index}]}))},448:function(e,t,n){"use strict";var r=n(0),o=n(454);t.a=function(){return Object(r.useContext)(o.a)}},449:function(e,t,n){"use strict";var r=n(0),o=n.n(r);function i(e,t){if(e.length!==t.length)return!1;for(var n=0;nr&&(r=(t=t.trim()).charCodeAt(0)),r){case 38:return t.replace(m,"$1"+e.trim());case 58:return e.trim()+t.replace(m,"$1"+e.trim());default:if(0<1*n&&0s.charCodeAt(8))break;case 115:u=u.replace(s,"-webkit-"+s)+";"+u;break;case 207:case 102:u=u.replace(s,"-webkit-"+(102a.charCodeAt(0)&&(a=a.trim()),a=[a],0d)&&(N=(U=U.replace(" ",":")).length),0=4;++r,o-=4)t=1540483477*(65535&(t=255&e.charCodeAt(r)|(255&e.charCodeAt(++r))<<8|(255&e.charCodeAt(++r))<<16|(255&e.charCodeAt(++r))<<24))+(59797*(t>>>16)<<16),n=1540483477*(65535&(t^=t>>>24))+(59797*(t>>>16)<<16)^1540483477*(65535&n)+(59797*(n>>>16)<<16);switch(o){case 3:n^=(255&e.charCodeAt(r+2))<<16;case 2:n^=(255&e.charCodeAt(r+1))<<8;case 1:n=1540483477*(65535&(n^=255&e.charCodeAt(r)))+(59797*(n>>>16)<<16)}return(((n=1540483477*(65535&(n^=n>>>13))+(59797*(n>>>16)<<16))^n>>>15)>>>0).toString(36)},b={animationIterationCount:1,borderImageOutset:1,borderImageSlice:1,borderImageWidth:1,boxFlex:1,boxFlexGroup:1,boxOrdinalGroup:1,columnCount:1,columns:1,flex:1,flexGrow:1,flexPositive:1,flexShrink:1,flexNegative:1,flexOrder:1,gridRow:1,gridRowEnd:1,gridRowSpan:1,gridRowStart:1,gridColumn:1,gridColumnEnd:1,gridColumnSpan:1,gridColumnStart:1,msGridRow:1,msGridRowSpan:1,msGridColumn:1,msGridColumnSpan:1,fontWeight:1,lineHeight:1,opacity:1,order:1,orphans:1,tabSize:1,widows:1,zIndex:1,zoom:1,WebkitLineClamp:1,fillOpacity:1,floodOpacity:1,stopOpacity:1,strokeDasharray:1,strokeDashoffset:1,strokeMiterlimit:1,strokeOpacity:1,strokeWidth:1};var E=/[A-Z]|^ms/g,y=/_EMO_([^_]+?)_([^]*?)_EMO_/g,C=function(e){return 45===e.charCodeAt(1)},O=function(e){return null!=e&&"boolean"!=typeof e},A=function(e){var t={};return function(n){return void 0===t[n]&&(t[n]=e(n)),t[n]}}((function(e){return C(e)?e:e.replace(E,"-$&").toLowerCase()})),w=function(e,t){switch(e){case"animation":case"animationName":if("string"==typeof t)return t.replace(y,(function(e,t,n){return x={name:t,styles:n,next:x},t}))}return 1===b[e]||C(e)||"number"!=typeof t||0===t?t:t+"px"};function F(e,t,n,r){if(null==n)return"";if(void 0!==n.__emotion_styles)return n;switch(typeof n){case"boolean":return"";case"object":if(1===n.anim)return x={name:n.name,styles:n.styles,next:x},n.name;if(void 0!==n.styles){var o=n.next;if(void 0!==o)for(;void 0!==o;)x={name:o.name,styles:o.styles,next:x},o=o.next;return n.styles+";"}return function(e,t,n){var r="";if(Array.isArray(n))for(var o=0;o-1}function J(e){return K(e)?window.pageYOffset:e.scrollTop}function q(e,t){K(e)?window.scrollTo(0,t):e.scrollTop=t}function Z(e,t,n,r){void 0===n&&(n=200),void 0===r&&(r=G);var o=J(e),i=t-o,u=0;!function t(){var a,s=i*((a=(a=u+=10)/n-1)*a*a+1)+o;q(e,s),u=d)return{placement:"bottom",maxHeight:t};if(A>=d&&!u)return i&&Z(s,w,160),{placement:"bottom",maxHeight:t};if(!u&&A>=r||u&&C>=r)return i&&Z(s,w,160),{placement:"bottom",maxHeight:u?C-b:A-b};if("auto"===o||u){var x=t,S=u?y:O;return S>=r&&(x=Math.min(S-b-a.controlHeight,t)),{placement:"top",maxHeight:x}}if("bottom"===o)return q(s,w),{placement:"bottom",maxHeight:t};break;case"top":if(y>=d)return{placement:"top",maxHeight:t};if(O>=d&&!u)return i&&Z(s,F,160),{placement:"top",maxHeight:t};if(!u&&O>=r||u&&y>=r){var D=t;return(!u&&O>=r||u&&y>=r)&&(D=u?y-E:O-E),i&&Z(s,F,160),{placement:"top",maxHeight:D}}return{placement:"bottom",maxHeight:t};default:throw new Error('Invalid placement provided "'+o+'".')}return l}var ie=function(e){return"auto"===e?"bottom":e},ue=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),o=0;o=0||(o[n]=e[n]);return o}(e,["size"]);return B("svg",Ee({height:t,width:t,viewBox:"0 0 20 20","aria-hidden":"true",focusable:"false",css:ye},n))},Oe=function(e){return B(Ce,Ee({size:20},e),B("path",{d:"M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z"}))},Ae=function(e){return B(Ce,Ee({size:20},e),B("path",{d:"M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"}))},we=function(e){var t=e.isFocused,n=e.theme,r=n.spacing.baseUnit,o=n.colors;return{label:"indicatorContainer",color:t?o.neutral60:o.neutral20,display:"flex",padding:2*r,transition:"color 150ms",":hover":{color:t?o.neutral80:o.neutral40}}},Fe=we,xe=we,Se=function(){var e=k.apply(void 0,arguments),t="animation-"+e.name;return{name:t,styles:"@keyframes "+t+"{"+e.styles+"}",anim:1,toString:function(){return"_EMO_"+this.name+"_"+this.styles+"_EMO_"}}}(be()),De=function(e){var t=e.delay,n=e.offset;return B("span",{css:k({animation:Se+" 1s ease-in-out "+t+"ms infinite;",backgroundColor:"currentColor",borderRadius:"1em",display:"inline-block",marginLeft:n?"1em":null,height:"1em",verticalAlign:"top",width:"1em"},"")})},ke=function(e){var t=e.className,n=e.cx,r=e.getStyles,o=e.innerProps,i=e.isRtl;return B("div",Ee({},o,{css:r("loadingIndicator",e),className:n({indicator:!0,"loading-indicator":!0},t)}),B(De,{delay:0,offset:i}),B(De,{delay:160,offset:!0}),B(De,{delay:320,offset:!i}))};function Ie(){return(Ie=Object.assign||function(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,["className","cx","getStyles","theme","selectProps"]));return B("div",Me({css:r("groupHeading",Me({theme:o},i)),className:n({"group-heading":!0},t)},i))},IndicatorsContainer:function(e){var t=e.children,n=e.className,r=e.cx,o=e.getStyles;return B("div",{css:o("indicatorsContainer",e),className:r({indicators:!0},n)},t)},IndicatorSeparator:function(e){var t=e.className,n=e.cx,r=e.getStyles,o=e.innerProps;return B("span",Ee({},o,{css:r("indicatorSeparator",e),className:n({"indicator-separator":!0},t)}))},Input:function(e){var t=e.className,n=e.cx,r=e.getStyles,o=e.innerRef,i=e.isHidden,u=e.isDisabled,a=e.theme,s=(e.selectProps,function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r=0||(o[n]=e[n]);return o}(e,["className","cx","getStyles","innerRef","isHidden","isDisabled","theme","selectProps"]));return B("div",{css:r("input",Pe({theme:a},s))},B(te.a,Pe({className:n({input:!0},t),inputRef:o,inputStyle:Le(i),disabled:u},s)))},LoadingIndicator:ke,Menu:function(e){var t=e.children,n=e.className,r=e.cx,o=e.getStyles,i=e.innerRef,u=e.innerProps;return B("div",ne({css:o("menu",e),className:r({menu:!0},n)},u,{ref:i}),t)},MenuList:function(e){var t=e.children,n=e.className,r=e.cx,o=e.getStyles,i=e.isMulti,u=e.innerRef;return B("div",{css:o("menuList",e),className:r({"menu-list":!0,"menu-list--is-multi":i},n),ref:u},t)},MenuPortal:fe,LoadingMessage:pe,NoOptionsMessage:ce,MultiValue:Be,MultiValueContainer:Re,MultiValueLabel:je,MultiValueRemove:function(e){var t=e.children,n=e.innerProps;return B("div",n,t||B(Oe,{size:14}))},Option:function(e){var t=e.children,n=e.className,r=e.cx,o=e.getStyles,i=e.isDisabled,u=e.isFocused,a=e.isSelected,s=e.innerRef,l=e.innerProps;return B("div",Ne({css:o("option",e),className:r({option:!0,"option--is-disabled":i,"option--is-focused":u,"option--is-selected":a},n),ref:s},l),t)},Placeholder:function(e){var t=e.children,n=e.className,r=e.cx,o=e.getStyles,i=e.innerProps;return B("div",He({css:o("placeholder",e),className:r({placeholder:!0},n)},i),t)},SelectContainer:function(e){var t=e.children,n=e.className,r=e.cx,o=e.getStyles,i=e.innerProps,u=e.isDisabled,a=e.isRtl;return B("div",ge({css:o("container",e),className:r({"--is-disabled":u,"--is-rtl":a},n)},i),t)},SingleValue:function(e){var t=e.children,n=e.className,r=e.cx,o=e.getStyles,i=e.isDisabled,u=e.innerProps;return B("div",_e({css:o("singleValue",e),className:r({"single-value":!0,"single-value--is-disabled":i},n)},u),t)},ValueContainer:function(e){var t=e.children,n=e.className,r=e.cx,o=e.isMulti,i=e.getStyles,u=e.hasValue;return B("div",{css:i("valueContainer",e),className:r({"value-container":!0,"value-container--is-multi":o,"value-container--has-value":u},n)},t)}},We=[{base:"A",letters:/[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g},{base:"AA",letters:/[\uA732]/g},{base:"AE",letters:/[\u00C6\u01FC\u01E2]/g},{base:"AO",letters:/[\uA734]/g},{base:"AU",letters:/[\uA736]/g},{base:"AV",letters:/[\uA738\uA73A]/g},{base:"AY",letters:/[\uA73C]/g},{base:"B",letters:/[\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181]/g},{base:"C",letters:/[\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E]/g},{base:"D",letters:/[\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779]/g},{base:"DZ",letters:/[\u01F1\u01C4]/g},{base:"Dz",letters:/[\u01F2\u01C5]/g},{base:"E",letters:/[\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E]/g},{base:"F",letters:/[\u0046\u24BB\uFF26\u1E1E\u0191\uA77B]/g},{base:"G",letters:/[\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E]/g},{base:"H",letters:/[\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D]/g},{base:"I",letters:/[\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197]/g},{base:"J",letters:/[\u004A\u24BF\uFF2A\u0134\u0248]/g},{base:"K",letters:/[\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2]/g},{base:"L",letters:/[\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780]/g},{base:"LJ",letters:/[\u01C7]/g},{base:"Lj",letters:/[\u01C8]/g},{base:"M",letters:/[\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C]/g},{base:"N",letters:/[\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4]/g},{base:"NJ",letters:/[\u01CA]/g},{base:"Nj",letters:/[\u01CB]/g},{base:"O",letters:/[\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C]/g},{base:"OI",letters:/[\u01A2]/g},{base:"OO",letters:/[\uA74E]/g},{base:"OU",letters:/[\u0222]/g},{base:"P",letters:/[\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754]/g},{base:"Q",letters:/[\u0051\u24C6\uFF31\uA756\uA758\u024A]/g},{base:"R",letters:/[\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782]/g},{base:"S",letters:/[\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784]/g},{base:"T",letters:/[\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786]/g},{base:"TZ",letters:/[\uA728]/g},{base:"U",letters:/[\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244]/g},{base:"V",letters:/[\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245]/g},{base:"VY",letters:/[\uA760]/g},{base:"W",letters:/[\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72]/g},{base:"X",letters:/[\u0058\u24CD\uFF38\u1E8A\u1E8C]/g},{base:"Y",letters:/[\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE]/g},{base:"Z",letters:/[\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762]/g},{base:"a",letters:/[\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250]/g},{base:"aa",letters:/[\uA733]/g},{base:"ae",letters:/[\u00E6\u01FD\u01E3]/g},{base:"ao",letters:/[\uA735]/g},{base:"au",letters:/[\uA737]/g},{base:"av",letters:/[\uA739\uA73B]/g},{base:"ay",letters:/[\uA73D]/g},{base:"b",letters:/[\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253]/g},{base:"c",letters:/[\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184]/g},{base:"d",letters:/[\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A]/g},{base:"dz",letters:/[\u01F3\u01C6]/g},{base:"e",letters:/[\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD]/g},{base:"f",letters:/[\u0066\u24D5\uFF46\u1E1F\u0192\uA77C]/g},{base:"g",letters:/[\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F]/g},{base:"h",letters:/[\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265]/g},{base:"hv",letters:/[\u0195]/g},{base:"i",letters:/[\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131]/g},{base:"j",letters:/[\u006A\u24D9\uFF4A\u0135\u01F0\u0249]/g},{base:"k",letters:/[\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3]/g},{base:"l",letters:/[\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747]/g},{base:"lj",letters:/[\u01C9]/g},{base:"m",letters:/[\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F]/g},{base:"n",letters:/[\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5]/g},{base:"nj",letters:/[\u01CC]/g},{base:"o",letters:/[\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275]/g},{base:"oi",letters:/[\u01A3]/g},{base:"ou",letters:/[\u0223]/g},{base:"oo",letters:/[\uA74F]/g},{base:"p",letters:/[\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755]/g},{base:"q",letters:/[\u0071\u24E0\uFF51\u024B\uA757\uA759]/g},{base:"r",letters:/[\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783]/g},{base:"s",letters:/[\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B]/g},{base:"t",letters:/[\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787]/g},{base:"tz",letters:/[\uA729]/g},{base:"u",letters:/[\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289]/g},{base:"v",letters:/[\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C]/g},{base:"vy",letters:/[\uA761]/g},{base:"w",letters:/[\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73]/g},{base:"x",letters:/[\u0078\u24E7\uFF58\u1E8B\u1E8D]/g},{base:"y",letters:/[\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF]/g},{base:"z",letters:/[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763]/g}],Ge=function(e){for(var t=0;t=0||(o[n]=e[n]);return o}(e,["in","out","onExited","appear","enter","exit","innerRef","emotion"]));return B("input",Ze({ref:t},n,{css:k({label:"dummyInput",background:0,border:0,fontSize:"inherit",outline:0,padding:0,width:1,color:"transparent",left:-100,opacity:0,position:"relative",transform:"scale(0)"},"")}))}var et=function(e){var t,n;function r(){return e.apply(this,arguments)||this}n=e,(t=r).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n;var o=r.prototype;return o.componentDidMount=function(){this.props.innerRef(Object(U.findDOMNode)(this))},o.componentWillUnmount=function(){this.props.innerRef(null)},o.render=function(){return this.props.children},r}(r.Component),tt=["boxSizing","height","overflow","paddingRight","position"],nt={boxSizing:"border-box",overflow:"hidden",position:"relative",height:"100%"};function rt(e){e.preventDefault()}function ot(e){e.stopPropagation()}function it(){var e=this.scrollTop,t=this.scrollHeight,n=e+this.offsetHeight;0===e?this.scrollTop=1:n===t&&(this.scrollTop=e-1)}function ut(){return"ontouchstart"in window||navigator.maxTouchPoints}var at=!(!window.document||!window.document.createElement),st=0,lt=function(e){var t,n;function r(){for(var t,n=arguments.length,r=new Array(n),o=0;o0,h=c-p-l,m=!1;h>n&&t.isBottom&&(i&&i(e),t.isBottom=!1),d&&t.isTop&&(a&&a(e),t.isTop=!1),d&&n>h?(o&&!t.isBottom&&o(e),f.scrollTop=c,m=!0,t.isBottom=!0):!d&&-n>l&&(u&&!t.isTop&&u(e),f.scrollTop=0,m=!0,t.isTop=!0),m&&t.cancelScroll(e)},t.onWheel=function(e){t.handleEventDelta(e,e.deltaY)},t.onTouchStart=function(e){t.touchStart=e.changedTouches[0].clientY},t.onTouchMove=function(e){var n=t.touchStart-e.changedTouches[0].clientY;t.handleEventDelta(e,n)},t.getScrollTarget=function(e){t.scrollTarget=e},t}n=e,(t=r).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n;var i=r.prototype;return i.componentDidMount=function(){this.startListening(this.scrollTarget)},i.componentWillUnmount=function(){this.stopListening(this.scrollTarget)},i.startListening=function(e){e&&("function"==typeof e.addEventListener&&e.addEventListener("wheel",this.onWheel,!1),"function"==typeof e.addEventListener&&e.addEventListener("touchstart",this.onTouchStart,!1),"function"==typeof e.addEventListener&&e.addEventListener("touchmove",this.onTouchMove,!1))},i.stopListening=function(e){"function"==typeof e.removeEventListener&&e.removeEventListener("wheel",this.onWheel,!1),"function"==typeof e.removeEventListener&&e.removeEventListener("touchstart",this.onTouchStart,!1),"function"==typeof e.removeEventListener&&e.removeEventListener("touchmove",this.onTouchMove,!1)},i.render=function(){return o.a.createElement(et,{innerRef:this.getScrollTarget},this.props.children)},r}(r.Component);function dt(e){var t=e.isEnabled,n=void 0===t||t,r=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r=0||(o[n]=e[n]);return o}(e,["isEnabled"]);return n?o.a.createElement(ft,r):r.children}var ht=function(e,t){void 0===t&&(t={});var n=t,r=n.isSearchable,o=n.isMulti,i=n.label,u=n.isDisabled;switch(e){case"menu":return"Use Up and Down to choose options"+(u?"":", press Enter to select the currently focused option")+", press Escape to exit the menu, press Tab to select the option and exit the menu.";case"input":return(i||"Select")+" is focused "+(r?",type to refine list":"")+", press Down to open the menu, "+(o?" press left to focus selected values":"");case"value":return"Use left and right to toggle between focused values, press Backspace to remove the currently focused value"}},mt=function(e,t){var n=t.value,r=t.isDisabled;if(n)switch(e){case"deselect-option":case"pop-value":case"remove-value":return"option "+n+", deselected.";case"select-option":return r?"option "+n+" is disabled. Select another option.":"option "+n+", selected."}},vt=function(e){return!!e.isDisabled};var gt={clearIndicator:xe,container:function(e){var t=e.isDisabled;return{label:"container",direction:e.isRtl?"rtl":null,pointerEvents:t?"none":null,position:"relative"}},control:function(e){var t=e.isDisabled,n=e.isFocused,r=e.theme,o=r.colors,i=r.borderRadius,u=r.spacing;return{label:"control",alignItems:"center",backgroundColor:t?o.neutral5:o.neutral0,borderColor:t?o.neutral10:n?o.primary:o.neutral20,borderRadius:i,borderStyle:"solid",borderWidth:1,boxShadow:n?"0 0 0 1px "+o.primary:null,cursor:"default",display:"flex",flexWrap:"wrap",justifyContent:"space-between",minHeight:u.controlHeight,outline:"0 !important",position:"relative",transition:"all 100ms","&:hover":{borderColor:n?o.primary:o.neutral30}}},dropdownIndicator:Fe,group:function(e){var t=e.theme.spacing;return{paddingBottom:2*t.baseUnit,paddingTop:2*t.baseUnit}},groupHeading:function(e){var t=e.theme.spacing;return{label:"group",color:"#999",cursor:"default",display:"block",fontSize:"75%",fontWeight:"500",marginBottom:"0.25em",paddingLeft:3*t.baseUnit,paddingRight:3*t.baseUnit,textTransform:"uppercase"}},indicatorsContainer:function(){return{alignItems:"center",alignSelf:"stretch",display:"flex",flexShrink:0}},indicatorSeparator:function(e){var t=e.isDisabled,n=e.theme,r=n.spacing.baseUnit,o=n.colors;return{label:"indicatorSeparator",alignSelf:"stretch",backgroundColor:t?o.neutral10:o.neutral20,marginBottom:2*r,marginTop:2*r,width:1}},input:function(e){var t=e.isDisabled,n=e.theme,r=n.spacing,o=n.colors;return{margin:r.baseUnit/2,paddingBottom:r.baseUnit/2,paddingTop:r.baseUnit/2,visibility:t?"hidden":"visible",color:o.neutral80}},loadingIndicator:function(e){var t=e.isFocused,n=e.size,r=e.theme,o=r.colors,i=r.spacing.baseUnit;return{label:"loadingIndicator",color:t?o.neutral60:o.neutral20,display:"flex",padding:2*i,transition:"color 150ms",alignSelf:"center",fontSize:n,lineHeight:1,marginRight:n,textAlign:"center",verticalAlign:"middle"}},loadingMessage:le,menu:function(e){var t,n=e.placement,r=e.theme,o=r.borderRadius,i=r.spacing,u=r.colors;return(t={label:"menu"})[function(e){return e?{bottom:"top",top:"bottom"}[e]:"bottom"}(n)]="100%",t.backgroundColor=u.neutral0,t.borderRadius=o,t.boxShadow="0 0 0 1px hsla(0, 0%, 0%, 0.1), 0 4px 11px hsla(0, 0%, 0%, 0.1)",t.marginBottom=i.menuGutter,t.marginTop=i.menuGutter,t.position="absolute",t.width="100%",t.zIndex=1,t},menuList:function(e){var t=e.maxHeight,n=e.theme.spacing.baseUnit;return{maxHeight:t,overflowY:"auto",paddingBottom:n,paddingTop:n,position:"relative",WebkitOverflowScrolling:"touch"}},menuPortal:function(e){var t=e.rect,n=e.offset,r=e.position;return{left:t.left,position:r,top:n,width:t.width,zIndex:1}},multiValue:function(e){var t=e.theme,n=t.spacing,r=t.borderRadius;return{label:"multiValue",backgroundColor:t.colors.neutral10,borderRadius:r/2,display:"flex",margin:n.baseUnit/2,minWidth:0}},multiValueLabel:function(e){var t=e.theme,n=t.borderRadius,r=t.colors,o=e.cropWithEllipsis;return{borderRadius:n/2,color:r.neutral80,fontSize:"85%",overflow:"hidden",padding:3,paddingLeft:6,textOverflow:o?"ellipsis":null,whiteSpace:"nowrap"}},multiValueRemove:function(e){var t=e.theme,n=t.spacing,r=t.borderRadius,o=t.colors;return{alignItems:"center",borderRadius:r/2,backgroundColor:e.isFocused&&o.dangerLight,display:"flex",paddingLeft:n.baseUnit,paddingRight:n.baseUnit,":hover":{backgroundColor:o.dangerLight,color:o.danger}}},noOptionsMessage:se,option:function(e){var t=e.isDisabled,n=e.isFocused,r=e.isSelected,o=e.theme,i=o.spacing,u=o.colors;return{label:"option",backgroundColor:r?u.primary:n?u.primary25:"transparent",color:t?u.neutral20:r?u.neutral0:"inherit",cursor:"default",display:"block",fontSize:"inherit",padding:2*i.baseUnit+"px "+3*i.baseUnit+"px",width:"100%",userSelect:"none",WebkitTapHighlightColor:"rgba(0, 0, 0, 0)",":active":{backgroundColor:!t&&(r?u.primary:u.primary50)}}},placeholder:function(e){var t=e.theme,n=t.spacing;return{label:"placeholder",color:t.colors.neutral50,marginLeft:n.baseUnit/2,marginRight:n.baseUnit/2,position:"absolute",top:"50%",transform:"translateY(-50%)"}},singleValue:function(e){var t=e.isDisabled,n=e.theme,r=n.spacing,o=n.colors;return{label:"singleValue",color:t?o.neutral40:o.neutral80,marginLeft:r.baseUnit/2,marginRight:r.baseUnit/2,maxWidth:"calc(100% - "+2*r.baseUnit+"px)",overflow:"hidden",position:"absolute",textOverflow:"ellipsis",whiteSpace:"nowrap",top:"50%",transform:"translateY(-50%)"}},valueContainer:function(e){var t=e.theme.spacing;return{alignItems:"center",display:"flex",flex:1,flexWrap:"wrap",padding:t.baseUnit/2+"px "+2*t.baseUnit+"px",WebkitOverflowScrolling:"touch",position:"relative",overflow:"hidden"}}};var bt={borderRadius:4,colors:{primary:"#2684FF",primary75:"#4C9AFF",primary50:"#B2D4FF",primary25:"#DEEBFF",danger:"#DE350B",dangerLight:"#FFBDAD",neutral0:"hsl(0, 0%, 100%)",neutral5:"hsl(0, 0%, 95%)",neutral10:"hsl(0, 0%, 90%)",neutral20:"hsl(0, 0%, 80%)",neutral30:"hsl(0, 0%, 70%)",neutral40:"hsl(0, 0%, 60%)",neutral50:"hsl(0, 0%, 50%)",neutral60:"hsl(0, 0%, 40%)",neutral70:"hsl(0, 0%, 30%)",neutral80:"hsl(0, 0%, 20%)",neutral90:"hsl(0, 0%, 10%)"},spacing:{baseUnit:4,controlHeight:38,menuGutter:8}};function Et(){return(Et=Object.assign||function(e){for(var t=1;t-1},formatGroupLabel:function(e){return e.label},getOptionLabel:function(e){return e.label},getOptionValue:function(e){return e.value},isDisabled:!1,isLoading:!1,isMulti:!1,isRtl:!1,isSearchable:!0,isOptionDisabled:vt,loadingMessage:function(){return"Loading..."},maxMenuHeight:300,minMenuHeight:140,menuIsOpen:!1,menuPlacement:"bottom",menuPosition:"absolute",menuShouldBlockScroll:!1,menuShouldScrollIntoView:!function(){try{return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)}catch(e){return!1}}(),noOptionsMessage:function(){return"No options"},openMenuOnFocus:!1,openMenuOnClick:!0,options:[],pageSize:5,placeholder:"Select...",screenReaderStatus:function(e){var t=e.count;return t+" result"+(1!==t?"s":"")+" available"},styles:{},tabIndex:"0",tabSelectsValue:!0},At=1,wt=function(e){var t,n;function r(t){var n;(n=e.call(this,t)||this).state={ariaLiveSelection:"",ariaLiveContext:"",focusedOption:null,focusedValue:null,inputIsHidden:!1,isFocused:!1,menuOptions:{render:[],focusable:[]},selectValue:[]},n.blockOptionHover=!1,n.isComposing=!1,n.clearFocusValueOnUpdate=!1,n.commonProps=void 0,n.components=void 0,n.hasGroups=!1,n.initialTouchX=0,n.initialTouchY=0,n.inputIsHiddenAfterUpdate=void 0,n.instancePrefix="",n.openAfterFocus=!1,n.scrollToFocusedOptionOnUpdate=!1,n.userIsDragging=void 0,n.controlRef=null,n.getControlRef=function(e){n.controlRef=e},n.focusedOptionRef=null,n.getFocusedOptionRef=function(e){n.focusedOptionRef=e},n.menuListRef=null,n.getMenuListRef=function(e){n.menuListRef=e},n.inputRef=null,n.getInputRef=function(e){n.inputRef=e},n.cacheComponents=function(e){n.components=Ue({},ze,{components:e}.components)},n.focus=n.focusInput,n.blur=n.blurInput,n.onChange=function(e,t){var r=n.props;(0,r.onChange)(e,Et({},t,{name:r.name}))},n.setValue=function(e,t,r){void 0===t&&(t="set-value");var o=n.props,i=o.closeMenuOnSelect,u=o.isMulti;n.onInputChange("",{action:"set-value"}),i&&(n.inputIsHiddenAfterUpdate=!u,n.onMenuClose()),n.clearFocusValueOnUpdate=!0,n.onChange(e,{action:t,option:r})},n.selectOption=function(e){var t=n.props,r=t.blurInputOnSelect,o=t.isMulti,i=n.state.selectValue;if(o)if(n.isOptionSelected(e,i)){var u=n.getOptionValue(e);n.setValue(i.filter((function(e){return n.getOptionValue(e)!==u})),"deselect-option",e),n.announceAriaLiveSelection({event:"deselect-option",context:{value:n.getOptionLabel(e)}})}else n.isOptionDisabled(e,i)?n.announceAriaLiveSelection({event:"select-option",context:{value:n.getOptionLabel(e),isDisabled:!0}}):(n.setValue([].concat(i,[e]),"select-option",e),n.announceAriaLiveSelection({event:"select-option",context:{value:n.getOptionLabel(e)}}));else n.isOptionDisabled(e,i)?n.announceAriaLiveSelection({event:"select-option",context:{value:n.getOptionLabel(e),isDisabled:!0}}):(n.setValue(e,"select-option"),n.announceAriaLiveSelection({event:"select-option",context:{value:n.getOptionLabel(e)}}));r&&n.blurInput()},n.removeValue=function(e){var t=n.state.selectValue,r=n.getOptionValue(e),o=t.filter((function(e){return n.getOptionValue(e)!==r}));n.onChange(o.length?o:null,{action:"remove-value",removedValue:e}),n.announceAriaLiveSelection({event:"remove-value",context:{value:e?n.getOptionLabel(e):""}}),n.focusInput()},n.clearValue=function(){var e=n.props.isMulti;n.onChange(e?[]:null,{action:"clear"})},n.popValue=function(){var e=n.state.selectValue,t=e[e.length-1],r=e.slice(0,e.length-1);n.announceAriaLiveSelection({event:"pop-value",context:{value:t?n.getOptionLabel(t):""}}),n.onChange(r.length?r:null,{action:"pop-value",removedValue:t})},n.getOptionLabel=function(e){return n.props.getOptionLabel(e)},n.getOptionValue=function(e){return n.props.getOptionValue(e)},n.getStyles=function(e,t){var r=gt[e](t);r.boxSizing="border-box";var o=n.props.styles[e];return o?o(r,t):r},n.getElementId=function(e){return n.instancePrefix+"-"+e},n.getActiveDescendentId=function(){var e=n.props.menuIsOpen,t=n.state,r=t.menuOptions,o=t.focusedOption;if(o&&e){var i=r.focusable.indexOf(o),u=r.render[i];return u&&u.key}},n.announceAriaLiveSelection=function(e){var t=e.event,r=e.context;n.setState({ariaLiveSelection:mt(t,r)})},n.announceAriaLiveContext=function(e){var t=e.event,r=e.context;n.setState({ariaLiveContext:ht(t,Et({},r,{label:n.props["aria-label"]}))})},n.onMenuMouseDown=function(e){0===e.button&&(e.stopPropagation(),e.preventDefault(),n.focusInput())},n.onMenuMouseMove=function(e){n.blockOptionHover=!1},n.onControlMouseDown=function(e){var t=n.props.openMenuOnClick;n.state.isFocused?n.props.menuIsOpen?"INPUT"!==e.target.tagName&&"TEXTAREA"!==e.target.tagName&&n.onMenuClose():t&&n.openMenu("first"):(t&&(n.openAfterFocus=!0),n.focusInput()),"INPUT"!==e.target.tagName&&"TEXTAREA"!==e.target.tagName&&e.preventDefault()},n.onDropdownIndicatorMouseDown=function(e){if(!(e&&"mousedown"===e.type&&0!==e.button||n.props.isDisabled)){var t=n.props,r=t.isMulti,o=t.menuIsOpen;n.focusInput(),o?(n.inputIsHiddenAfterUpdate=!r,n.onMenuClose()):n.openMenu("first"),e.preventDefault(),e.stopPropagation()}},n.onClearIndicatorMouseDown=function(e){e&&"mousedown"===e.type&&0!==e.button||(n.clearValue(),e.stopPropagation(),n.openAfterFocus=!1,"touchend"===e.type?n.focusInput():setTimeout((function(){return n.focusInput()})))},n.onScroll=function(e){"boolean"==typeof n.props.closeMenuOnScroll?e.target instanceof HTMLElement&&K(e.target)&&n.props.onMenuClose():"function"==typeof n.props.closeMenuOnScroll&&n.props.closeMenuOnScroll(e)&&n.props.onMenuClose()},n.onCompositionStart=function(){n.isComposing=!0},n.onCompositionEnd=function(){n.isComposing=!1},n.onTouchStart=function(e){var t=e.touches.item(0);t&&(n.initialTouchX=t.clientX,n.initialTouchY=t.clientY,n.userIsDragging=!1)},n.onTouchMove=function(e){var t=e.touches.item(0);if(t){var r=Math.abs(t.clientX-n.initialTouchX),o=Math.abs(t.clientY-n.initialTouchY);n.userIsDragging=r>5||o>5}},n.onTouchEnd=function(e){n.userIsDragging||(n.controlRef&&!n.controlRef.contains(e.target)&&n.menuListRef&&!n.menuListRef.contains(e.target)&&n.blurInput(),n.initialTouchX=0,n.initialTouchY=0)},n.onControlTouchEnd=function(e){n.userIsDragging||n.onControlMouseDown(e)},n.onClearIndicatorTouchEnd=function(e){n.userIsDragging||n.onClearIndicatorMouseDown(e)},n.onDropdownIndicatorTouchEnd=function(e){n.userIsDragging||n.onDropdownIndicatorMouseDown(e)},n.handleInputChange=function(e){var t=e.currentTarget.value;n.inputIsHiddenAfterUpdate=!1,n.onInputChange(t,{action:"input-change"}),n.onMenuOpen()},n.onInputFocus=function(e){var t=n.props,r=t.isSearchable,o=t.isMulti;n.props.onFocus&&n.props.onFocus(e),n.inputIsHiddenAfterUpdate=!1,n.announceAriaLiveContext({event:"input",context:{isSearchable:r,isMulti:o}}),n.setState({isFocused:!0}),(n.openAfterFocus||n.props.openMenuOnFocus)&&n.openMenu("first"),n.openAfterFocus=!1},n.onInputBlur=function(e){n.menuListRef&&n.menuListRef.contains(document.activeElement)?n.inputRef.focus():(n.props.onBlur&&n.props.onBlur(e),n.onInputChange("",{action:"input-blur"}),n.onMenuClose(),n.setState({focusedValue:null,isFocused:!1}))},n.onOptionHover=function(e){n.blockOptionHover||n.state.focusedOption===e||n.setState({focusedOption:e})},n.shouldHideSelectedOptions=function(){var e=n.props,t=e.hideSelectedOptions,r=e.isMulti;return void 0===t?r:t},n.onKeyDown=function(e){var t=n.props,r=t.isMulti,o=t.backspaceRemovesValue,i=t.escapeClearsValue,u=t.inputValue,a=t.isClearable,s=t.isDisabled,l=t.menuIsOpen,c=t.onKeyDown,p=t.tabSelectsValue,f=t.openMenuOnFocus,d=n.state,h=d.focusedOption,m=d.focusedValue,v=d.selectValue;if(!(s||"function"==typeof c&&(c(e),e.defaultPrevented))){switch(n.blockOptionHover=!0,e.key){case"ArrowLeft":if(!r||u)return;n.focusValue("previous");break;case"ArrowRight":if(!r||u)return;n.focusValue("next");break;case"Delete":case"Backspace":if(u)return;if(m)n.removeValue(m);else{if(!o)return;r?n.popValue():a&&n.clearValue()}break;case"Tab":if(n.isComposing)return;if(e.shiftKey||!l||!p||!h||f&&n.isOptionSelected(h,v))return;n.selectOption(h);break;case"Enter":if(229===e.keyCode)break;if(l){if(!h)return;if(n.isComposing)return;n.selectOption(h);break}return;case"Escape":l?(n.inputIsHiddenAfterUpdate=!1,n.onInputChange("",{action:"menu-close"}),n.onMenuClose()):a&&i&&n.clearValue();break;case" ":if(u)return;if(!l){n.openMenu("first");break}if(!h)return;n.selectOption(h);break;case"ArrowUp":l?n.focusOption("up"):n.openMenu("last");break;case"ArrowDown":l?n.focusOption("down"):n.openMenu("first");break;case"PageUp":if(!l)return;n.focusOption("pageup");break;case"PageDown":if(!l)return;n.focusOption("pagedown");break;case"Home":if(!l)return;n.focusOption("first");break;case"End":if(!l)return;n.focusOption("last");break;default:return}e.preventDefault()}},n.buildMenuOptions=function(e,t){var r=e.inputValue,o=void 0===r?"":r,i=e.options,u=function(e,r){var i=n.isOptionDisabled(e,t),u=n.isOptionSelected(e,t),a=n.getOptionLabel(e),s=n.getOptionValue(e);if(!(n.shouldHideSelectedOptions()&&u||!n.filterOption({label:a,value:s,data:e},o))){var l=i?void 0:function(){return n.onOptionHover(e)},c=i?void 0:function(){return n.selectOption(e)},p=n.getElementId("option")+"-"+r;return{innerProps:{id:p,onClick:c,onMouseMove:l,onMouseOver:l,tabIndex:-1},data:e,isDisabled:i,isSelected:u,key:p,label:a,type:"option",value:s}}};return i.reduce((function(e,t,r){if(t.options){n.hasGroups||(n.hasGroups=!0);var o=t.options.map((function(t,n){var o=u(t,r+"-"+n);return o&&e.focusable.push(t),o})).filter(Boolean);if(o.length){var i=n.getElementId("group")+"-"+r;e.render.push({type:"group",key:i,data:t,options:o})}}else{var a=u(t,""+r);a&&(e.render.push(a),e.focusable.push(t))}return e}),{render:[],focusable:[]})};var r=t.value;n.cacheComponents=u(n.cacheComponents,ve).bind(yt(yt(n))),n.cacheComponents(t.components),n.instancePrefix="react-select-"+(n.props.instanceId||++At);var o=X(r);n.buildMenuOptions=u(n.buildMenuOptions,(function(e,t){var n=e,r=n[0],o=n[1],i=t,u=i[0];return ve(o,i[1])&&ve(r.inputValue,u.inputValue)&&ve(r.options,u.options)})).bind(yt(yt(n)));var i=t.menuIsOpen?n.buildMenuOptions(t,o):{render:[],focusable:[]};return n.state.menuOptions=i,n.state.selectValue=o,n}n=e,(t=r).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n;var i=r.prototype;return i.componentDidMount=function(){this.startListeningComposition(),this.startListeningToTouch(),this.props.closeMenuOnScroll&&document&&document.addEventListener&&document.addEventListener("scroll",this.onScroll,!0),this.props.autoFocus&&this.focusInput()},i.UNSAFE_componentWillReceiveProps=function(e){var t=this.props,n=t.options,r=t.value,o=t.menuIsOpen,i=t.inputValue;if(this.cacheComponents(e.components),e.value!==r||e.options!==n||e.menuIsOpen!==o||e.inputValue!==i){var u=X(e.value),a=e.menuIsOpen?this.buildMenuOptions(e,u):{render:[],focusable:[]},s=this.getNextFocusedValue(u),l=this.getNextFocusedOption(a.focusable);this.setState({menuOptions:a,selectValue:u,focusedOption:l,focusedValue:s})}null!=this.inputIsHiddenAfterUpdate&&(this.setState({inputIsHidden:this.inputIsHiddenAfterUpdate}),delete this.inputIsHiddenAfterUpdate)},i.componentDidUpdate=function(e){var t,n,r,o,i,u=this.props,a=u.isDisabled,s=u.menuIsOpen,l=this.state.isFocused;(l&&!a&&e.isDisabled||l&&s&&!e.menuIsOpen)&&this.focusInput(),this.menuListRef&&this.focusedOptionRef&&this.scrollToFocusedOptionOnUpdate&&(t=this.menuListRef,n=this.focusedOptionRef,r=t.getBoundingClientRect(),o=n.getBoundingClientRect(),i=n.offsetHeight/3,o.bottom+i>r.bottom?q(t,Math.min(n.offsetTop+n.clientHeight-t.offsetHeight+i,t.scrollHeight)):o.top-i-1&&(a=s)}this.scrollToFocusedOptionOnUpdate=!(o&&this.menuListRef),this.inputIsHiddenAfterUpdate=!1,this.setState({menuOptions:i,focusedValue:null,focusedOption:i.focusable[a]},(function(){t.onMenuOpen(),t.announceAriaLiveContext({event:"menu"})}))},i.focusValue=function(e){var t=this.props,n=t.isMulti,r=t.isSearchable,o=this.state,i=o.selectValue,u=o.focusedValue;if(n){this.setState({focusedOption:null});var a=i.indexOf(u);u||(a=-1,this.announceAriaLiveContext({event:"value"}));var s=i.length-1,l=-1;if(i.length){switch(e){case"previous":l=0===a?0:-1===a?s:a-1;break;case"next":a>-1&&a0?u-1:o.length-1:"down"===e?i=(u+1)%o.length:"pageup"===e?(i=u-t)<0&&(i=0):"pagedown"===e?(i=u+t)>o.length-1&&(i=o.length-1):"last"===e&&(i=o.length-1),this.scrollToFocusedOptionOnUpdate=!0,this.setState({focusedOption:o[i],focusedValue:null}),this.announceAriaLiveContext({event:"menu",context:{isDisabled:vt(o[i])}})}},i.getTheme=function(){return this.props.theme?"function"==typeof this.props.theme?this.props.theme(bt):Et({},bt,this.props.theme):bt},i.getCommonProps=function(){var e=this.clearValue,t=this.getStyles,n=this.setValue,r=this.selectOption,o=this.props,i=o.classNamePrefix,u=o.isMulti,a=o.isRtl,s=o.options,l=this.state.selectValue,c=this.hasValue();return{cx:Y.bind(null,i),clearValue:e,getStyles:t,getValue:function(){return l},hasValue:c,isMulti:u,isRtl:a,options:s,selectOption:r,setValue:n,selectProps:o,theme:this.getTheme()}},i.getNextFocusedValue=function(e){if(this.clearFocusValueOnUpdate)return this.clearFocusValueOnUpdate=!1,null;var t=this.state,n=t.focusedValue,r=t.selectValue.indexOf(n);if(r>-1){if(e.indexOf(n)>-1)return n;if(r-1?t:e[0]},i.hasValue=function(){return this.state.selectValue.length>0},i.hasOptions=function(){return!!this.state.menuOptions.render.length},i.countOptions=function(){return this.state.menuOptions.focusable.length},i.isClearable=function(){var e=this.props,t=e.isClearable,n=e.isMulti;return void 0===t?n:t},i.isOptionDisabled=function(e,t){return"function"==typeof this.props.isOptionDisabled&&this.props.isOptionDisabled(e,t)},i.isOptionSelected=function(e,t){var n=this;if(t.indexOf(e)>-1)return!0;if("function"==typeof this.props.isOptionSelected)return this.props.isOptionSelected(e,t);var r=this.getOptionValue(e);return t.some((function(e){return n.getOptionValue(e)===r}))},i.filterOption=function(e,t){return!this.props.filterOption||this.props.filterOption(e,t)},i.formatOptionLabel=function(e,t){if("function"==typeof this.props.formatOptionLabel){var n=this.props.inputValue,r=this.state.selectValue;return this.props.formatOptionLabel(e,{context:t,inputValue:n,selectValue:r})}return this.getOptionLabel(e)},i.formatGroupLabel=function(e){return this.props.formatGroupLabel(e)},i.startListeningComposition=function(){document&&document.addEventListener&&(document.addEventListener("compositionstart",this.onCompositionStart,!1),document.addEventListener("compositionend",this.onCompositionEnd,!1))},i.stopListeningComposition=function(){document&&document.removeEventListener&&(document.removeEventListener("compositionstart",this.onCompositionStart),document.removeEventListener("compositionend",this.onCompositionEnd))},i.startListeningToTouch=function(){document&&document.addEventListener&&(document.addEventListener("touchstart",this.onTouchStart,!1),document.addEventListener("touchmove",this.onTouchMove,!1),document.addEventListener("touchend",this.onTouchEnd,!1))},i.stopListeningToTouch=function(){document&&document.removeEventListener&&(document.removeEventListener("touchstart",this.onTouchStart),document.removeEventListener("touchmove",this.onTouchMove),document.removeEventListener("touchend",this.onTouchEnd))},i.constructAriaLiveMessage=function(){var e=this.state,t=e.ariaLiveContext,n=e.selectValue,r=e.focusedValue,o=e.focusedOption,i=this.props,u=i.options,a=i.menuIsOpen,s=i.inputValue,l=i.screenReaderStatus;return(r?function(e){var t=e.focusedValue,n=e.getOptionLabel,r=e.selectValue;return"value "+n(t)+" focused, "+(r.indexOf(t)+1)+" of "+r.length+"."}({focusedValue:r,getOptionLabel:this.getOptionLabel,selectValue:n}):"")+" "+(o&&a?function(e){var t=e.focusedOption,n=e.getOptionLabel,r=e.options;return"option "+n(t)+" focused"+(t.isDisabled?" disabled":"")+", "+(r.indexOf(t)+1)+" of "+r.length+"."}({focusedOption:o,getOptionLabel:this.getOptionLabel,options:u}):"")+" "+function(e){var t=e.inputValue;return e.screenReaderMessage+(t?" for search term "+t:"")+"."}({inputValue:s,screenReaderMessage:l({count:this.countOptions()})})+" "+t},i.renderInput=function(){var e=this.props,t=e.isDisabled,n=e.isSearchable,r=e.inputId,i=e.inputValue,u=e.tabIndex,a=this.components.Input,s=this.state.inputIsHidden,l=r||this.getElementId("input"),c={"aria-autocomplete":"list","aria-label":this.props["aria-label"],"aria-labelledby":this.props["aria-labelledby"]};if(!n)return o.a.createElement(Qe,Et({id:l,innerRef:this.getInputRef,onBlur:this.onInputBlur,onChange:G,onFocus:this.onInputFocus,readOnly:!0,disabled:t,tabIndex:u,value:""},c));var p=this.commonProps,f=p.cx,d=p.theme,h=p.selectProps;return o.a.createElement(a,Et({autoCapitalize:"none",autoComplete:"off",autoCorrect:"off",cx:f,getStyles:this.getStyles,id:l,innerRef:this.getInputRef,isDisabled:t,isHidden:s,onBlur:this.onInputBlur,onChange:this.handleInputChange,onFocus:this.onInputFocus,selectProps:h,spellCheck:"false",tabIndex:u,theme:d,type:"text",value:i},c))},i.renderPlaceholderOrValue=function(){var e=this,t=this.components,n=t.MultiValue,r=t.MultiValueContainer,i=t.MultiValueLabel,u=t.MultiValueRemove,a=t.SingleValue,s=t.Placeholder,l=this.commonProps,c=this.props,p=c.controlShouldRenderValue,f=c.isDisabled,d=c.isMulti,h=c.inputValue,m=c.placeholder,v=this.state,g=v.selectValue,b=v.focusedValue,E=v.isFocused;if(!this.hasValue()||!p)return h?null:o.a.createElement(s,Et({},l,{key:"placeholder",isDisabled:f,isFocused:E}),m);if(d)return g.map((function(t,a){var s=t===b;return o.a.createElement(n,Et({},l,{components:{Container:r,Label:i,Remove:u},isFocused:s,isDisabled:f,key:e.getOptionValue(t),index:a,removeProps:{onClick:function(){return e.removeValue(t)},onTouchEnd:function(){return e.removeValue(t)},onMouseDown:function(e){e.preventDefault(),e.stopPropagation()}},data:t}),e.formatOptionLabel(t,"value"))}));if(h)return null;var y=g[0];return o.a.createElement(a,Et({},l,{data:y,isDisabled:f}),this.formatOptionLabel(y,"value"))},i.renderClearIndicator=function(){var e=this.components.ClearIndicator,t=this.commonProps,n=this.props,r=n.isDisabled,i=n.isLoading,u=this.state.isFocused;if(!this.isClearable()||!e||r||!this.hasValue()||i)return null;var a={onMouseDown:this.onClearIndicatorMouseDown,onTouchEnd:this.onClearIndicatorTouchEnd,"aria-hidden":"true"};return o.a.createElement(e,Et({},t,{innerProps:a,isFocused:u}))},i.renderLoadingIndicator=function(){var e=this.components.LoadingIndicator,t=this.commonProps,n=this.props,r=n.isDisabled,i=n.isLoading,u=this.state.isFocused;if(!e||!i)return null;return o.a.createElement(e,Et({},t,{innerProps:{"aria-hidden":"true"},isDisabled:r,isFocused:u}))},i.renderIndicatorSeparator=function(){var e=this.components,t=e.DropdownIndicator,n=e.IndicatorSeparator;if(!t||!n)return null;var r=this.commonProps,i=this.props.isDisabled,u=this.state.isFocused;return o.a.createElement(n,Et({},r,{isDisabled:i,isFocused:u}))},i.renderDropdownIndicator=function(){var e=this.components.DropdownIndicator;if(!e)return null;var t=this.commonProps,n=this.props.isDisabled,r=this.state.isFocused,i={onMouseDown:this.onDropdownIndicatorMouseDown,onTouchEnd:this.onDropdownIndicatorTouchEnd,"aria-hidden":"true"};return o.a.createElement(e,Et({},t,{innerProps:i,isDisabled:n,isFocused:r}))},i.renderMenu=function(){var e=this,t=this.components,n=t.Group,r=t.GroupHeading,i=t.Menu,u=t.MenuList,a=t.MenuPortal,s=t.LoadingMessage,l=t.NoOptionsMessage,c=t.Option,p=this.commonProps,f=this.state,d=f.focusedOption,h=f.menuOptions,m=this.props,v=m.captureMenuScroll,g=m.inputValue,b=m.isLoading,E=m.loadingMessage,y=m.minMenuHeight,C=m.maxMenuHeight,O=m.menuIsOpen,A=m.menuPlacement,w=m.menuPosition,F=m.menuPortalTarget,x=m.menuShouldBlockScroll,S=m.menuShouldScrollIntoView,D=m.noOptionsMessage,k=m.onMenuScrollToTop,I=m.onMenuScrollToBottom;if(!O)return null;var M,P=function(t){var n=d===t.data;return t.innerRef=n?e.getFocusedOptionRef:void 0,o.a.createElement(c,Et({},p,t,{isFocused:n}),e.formatOptionLabel(t.data,"menu"))};if(this.hasOptions())M=h.render.map((function(t){if("group"===t.type){t.type;var i=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r=0||(o[n]=e[n]);return o}(t,["type"]),u=t.key+"-heading";return o.a.createElement(n,Et({},p,i,{Heading:r,headingProps:{id:u},label:e.formatGroupLabel(t.data)}),t.options.map((function(e){return P(e)})))}if("option"===t.type)return P(t)}));else if(b){var L=E({inputValue:g});if(null===L)return null;M=o.a.createElement(s,p,L)}else{var V=D({inputValue:g});if(null===V)return null;M=o.a.createElement(l,p,V)}var T={minMenuHeight:y,maxMenuHeight:C,menuPlacement:A,menuPosition:w,menuShouldScrollIntoView:S},R=o.a.createElement(ue,Et({},p,T),(function(t){var n=t.ref,r=t.placerProps,a=r.placement,s=r.maxHeight;return o.a.createElement(i,Et({},p,T,{innerRef:n,innerProps:{onMouseDown:e.onMenuMouseDown,onMouseMove:e.onMenuMouseMove},isLoading:b,placement:a}),o.a.createElement(dt,{isEnabled:v,onTopArrive:k,onBottomArrive:I},o.a.createElement(pt,{isEnabled:x},o.a.createElement(u,Et({},p,{innerRef:e.getMenuListRef,isLoading:b,maxHeight:s}),M))))}));return F||"fixed"===w?o.a.createElement(a,Et({},p,{appendTo:F,controlElement:this.controlRef,menuPlacement:A,menuPosition:w}),R):R},i.renderFormField=function(){var e=this,t=this.props,n=t.delimiter,r=t.isDisabled,i=t.isMulti,u=t.name,a=this.state.selectValue;if(u&&!r){if(i){if(n){var s=a.map((function(t){return e.getOptionValue(t)})).join(n);return o.a.createElement("input",{name:u,type:"hidden",value:s})}var l=a.length>0?a.map((function(t,n){return o.a.createElement("input",{key:"i-"+n,name:u,type:"hidden",value:e.getOptionValue(t)})})):o.a.createElement("input",{name:u,type:"hidden"});return o.a.createElement("div",null,l)}var c=a[0]?this.getOptionValue(a[0]):"";return o.a.createElement("input",{name:u,type:"hidden",value:c})}},i.renderLiveRegion=function(){return this.state.isFocused?o.a.createElement(qe,{"aria-live":"polite"},o.a.createElement("p",{id:"aria-selection-event"},"\xa0",this.state.ariaLiveSelection),o.a.createElement("p",{id:"aria-context"},"\xa0",this.constructAriaLiveMessage())):null},i.render=function(){var e=this.components,t=e.Control,n=e.IndicatorsContainer,r=e.SelectContainer,i=e.ValueContainer,u=this.props,a=u.className,s=u.id,l=u.isDisabled,c=u.menuIsOpen,p=this.state.isFocused,f=this.commonProps=this.getCommonProps();return o.a.createElement(r,Et({},f,{className:a,innerProps:{id:s,onKeyDown:this.onKeyDown},isDisabled:l,isFocused:p}),this.renderLiveRegion(),o.a.createElement(t,Et({},f,{innerRef:this.getControlRef,innerProps:{onMouseDown:this.onControlMouseDown,onTouchEnd:this.onControlTouchEnd},isDisabled:l,isFocused:p,menuIsOpen:c}),o.a.createElement(i,Et({},f,{isDisabled:l}),this.renderPlaceholderOrValue(),this.renderInput()),o.a.createElement(n,Et({},f,{isDisabled:l}),this.renderClearIndicator(),this.renderLoadingIndicator(),this.renderIndicatorSeparator(),this.renderDropdownIndicator())),this.renderMenu(),this.renderFormField())},r}(r.Component);function Ft(){return(Ft=Object.assign||function(e){for(var t=1;t1?n-1:0),o=1;o=0||(o[n]=e[n]);return o}(t,["defaultInputValue","defaultMenuIsOpen","defaultValue"]));return o.a.createElement(St,Ft({},n,{ref:function(t){e.select=t},inputValue:this.getProp("inputValue"),menuIsOpen:this.getProp("menuIsOpen"),onChange:this.onChange,onInputChange:this.onInputChange,onMenuClose:this.onMenuClose,onMenuOpen:this.onMenuOpen,value:this.getProp("value")}))},r}(r.Component),Dt.defaultProps=xt,kt);t.a=It},454:function(e,t,n){"use strict";var r=n(0),o=Object(r.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=o},465:function(e,t,n){var r=n(30),o=n(54),i=n(27),u=n(26),a=n(466);e.exports=function(e,t){var n=1==e,s=2==e,l=3==e,c=4==e,p=6==e,f=5==e||p,d=t||a;return function(t,a,h){for(var m,v,g=i(t),b=o(g),E=r(a,h,3),y=u(b.length),C=0,O=n?d(t,y):s?d(t,0):void 0;y>C;C++)if((f||C in b)&&(v=E(m=b[C],C,g),e))if(n)O[C]=v;else if(v)switch(e){case 3:return!0;case 5:return m;case 6:return C;case 2:O.push(m)}else if(c)return!1;return p?-1:l||c?c:O}}},466:function(e,t,n){var r=n(467);e.exports=function(e,t){return new(r(e))(t)}},467:function(e,t,n){var r=n(13),o=n(468),i=n(2)("species");e.exports=function(e){var t;return o(e)&&("function"!=typeof(t=e.constructor)||t!==Array&&!o(t.prototype)||(t=void 0),r(t)&&null===(t=t[i])&&(t=void 0)),void 0===t?Array:t}},468:function(e,t,n){var r=n(23);e.exports=Array.isArray||function(e){return"Array"==r(e)}},486:function(e,t){e.exports=Object.is||function(e,t){return e===t?0!==e||1/e==1/t:e!=e&&t!=t}},566:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=Object.assign||function(e){for(var t=1;t=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}(this.props,[]);return function(e){c.forEach((function(t){return delete e[t]}))}(o),o.className=this.props.inputClassName,o.id=this.state.inputId,o.style=n,u.default.createElement("div",{className:this.props.className,style:t},this.renderStyles(),u.default.createElement("input",r({},o,{ref:this.inputRef})),u.default.createElement("div",{ref:this.sizerRef,style:l},e),this.props.placeholder?u.default.createElement("div",{ref:this.placeHolderSizerRef,style:l},this.props.placeholder):null)}}]),t}(i.Component);h.propTypes={className:a.default.string,defaultValue:a.default.any,extraWidth:a.default.oneOfType([a.default.number,a.default.string]),id:a.default.string,injectStyles:a.default.bool,inputClassName:a.default.string,inputRef:a.default.func,inputStyle:a.default.object,minWidth:a.default.oneOfType([a.default.number,a.default.string]),onAutosize:a.default.func,onChange:a.default.func,placeholder:a.default.string,placeholderIsMinWidth:a.default.bool,style:a.default.object,value:a.default.any},h.defaultProps={minWidth:1,injectStyles:!0},t.default=h}}]); \ No newline at end of file diff --git a/10c2e3e6.ca812551.js.LICENSE.txt b/1.5236ee97.js.LICENSE.txt similarity index 100% rename from 10c2e3e6.ca812551.js.LICENSE.txt rename to 1.5236ee97.js.LICENSE.txt diff --git a/10c2e3e6.ca812551.js b/10c2e3e6.cd7c29c6.js similarity index 91% rename from 10c2e3e6.ca812551.js rename to 10c2e3e6.cd7c29c6.js index 612ac78c97..f2234f59df 100644 --- a/10c2e3e6.ca812551.js +++ b/10c2e3e6.cd7c29c6.js @@ -1,2 +1,2 @@ -/*! For license information please see 10c2e3e6.ca812551.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[18],{166:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return c})),r.d(t,"metadata",(function(){return u})),r.d(t,"rightToc",(function(){return s})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),o=(r(0),r(422)),i=(r(431),r(426),r(421)),c={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Migration",description:"Learn how to migrate your applications with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Migration",description:"Learn how to migrate your applications with Qovery",permalink:"/guides/advanced/migration",readingTime:"2 min read",source:"@site/guides/advanced/migration.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Migration",truncated:!1,prevItem:{title:"Migrate your application from Heroku to AWS",permalink:"/guides/tutorial/migrate-your-application-from-heroku-to-aws"},nextItem:{title:"Monitoring",permalink:"/guides/advanced/monitoring"}},s=[{value:"Resources",id:"resources",children:[]},{value:"Migration assistance",id:"migration-assistance",children:[]},{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},l,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"You plan to migrate to AWS (Amazon Web Services), GCP (Google Cloud Platform) or Microsoft Azure with Qovery? This guide is for you."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to migrate your applications to your favorite cloud provider with Qovery."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Are you migrating from Digital Ocean, OVH, Netlify or any other cloud provider? You can use the same resources to migrate your applications. Qovery provides the same features for all cloud providers.")),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/migrate-your-application-from-heroku-to-aws/"}),"Migrate from Heroku to AWS")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/migrate-your-application-from-heroku-to-aws/"}),"Complete guide to migrate from Heroku to AWS with Qovery")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Migration checklist"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Comprehensive migration checklist to read before migrating your applications with Qovery (coming soon)"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=migration"}),"Forum")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=migration"}),'List "Migration" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"migration-assistance"},"Migration assistance"),Object(o.b)("p",null,"Qovery provides a migration assistance to help you migrate your applications with Qovery. Contact us via the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://en.wikipedia.org/wiki/System_console"}),"Qovery Console")," and ask for migration assistance via the chat."),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},420:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(r),b=n,d=p["".concat(i,".").concat(b)]||p[b]||m[b]||o;return r?a.a.createElement(d,c({ref:t},s,{components:r})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=b;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s1?arguments[1]:void 0,r),u=i>2?arguments[2]:void 0,s=void 0===u?r:a(u,r);s>c;)t[c++]=e;return t}},425:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,r){"use strict";r(425);var n=r(0),a=r.n(n),o=r(421);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},428:function(e,t,r){"use strict";var n=r(432),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(r(n,e,i.length))})),i.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(420),r(428)),i=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(n.useState)(null),p=l[0],m=l[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return m("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 10c2e3e6.cd7c29c6.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{167:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return c})),r.d(t,"metadata",(function(){return u})),r.d(t,"rightToc",(function(){return s})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),o=(r(0),r(425)),i=(r(434),r(429),r(424)),c={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Migration",description:"Learn how to migrate your applications with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Migration",description:"Learn how to migrate your applications with Qovery",permalink:"/guides/advanced/migration",readingTime:"2 min read",source:"@site/guides/advanced/migration.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Migration",truncated:!1,prevItem:{title:"Migrate your application from Heroku to AWS",permalink:"/guides/tutorial/migrate-your-application-from-heroku-to-aws"},nextItem:{title:"Monitoring",permalink:"/guides/advanced/monitoring"}},s=[{value:"Resources",id:"resources",children:[]},{value:"Migration assistance",id:"migration-assistance",children:[]},{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},l,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"You plan to migrate to AWS (Amazon Web Services), GCP (Google Cloud Platform) or Microsoft Azure with Qovery? This guide is for you."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to migrate your applications to your favorite cloud provider with Qovery."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Are you migrating from Digital Ocean, OVH, Netlify or any other cloud provider? You can use the same resources to migrate your applications. Qovery provides the same features for all cloud providers.")),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/migrate-your-application-from-heroku-to-aws/"}),"Migrate from Heroku to AWS")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/migrate-your-application-from-heroku-to-aws/"}),"Complete guide to migrate from Heroku to AWS with Qovery")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Migration checklist"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Comprehensive migration checklist to read before migrating your applications with Qovery (coming soon)"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=migration"}),"Forum")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=migration"}),'List "Migration" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"migration-assistance"},"Migration assistance"),Object(o.b)("p",null,"Qovery provides a migration assistance to help you migrate your applications with Qovery. Contact us via the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://en.wikipedia.org/wiki/System_console"}),"Qovery Console")," and ask for migration assistance via the chat."),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(r),b=n,d=p["".concat(i,".").concat(b)]||p[b]||m[b]||o;return r?a.a.createElement(d,c({ref:t},s,{components:r})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=b;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s1?arguments[1]:void 0,r),u=i>2?arguments[2]:void 0,s=void 0===u?r:a(u,r);s>c;)t[c++]=e;return t}},428:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,r){"use strict";r(428);var n=r(0),a=r.n(n),o=r(424);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},433:function(e,t,r){"use strict";var n=r(435),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(r(n,e,i.length))})),i.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(423),r(433)),i=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(n.useState)(null),p=l[0],m=l[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return m("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/10dee872.50de68b4.js.LICENSE.txt b/10c2e3e6.cd7c29c6.js.LICENSE.txt similarity index 100% rename from 10dee872.50de68b4.js.LICENSE.txt rename to 10c2e3e6.cd7c29c6.js.LICENSE.txt diff --git a/10dee872.50de68b4.js b/10dee872.673d81ad.js similarity index 96% rename from 10dee872.50de68b4.js rename to 10dee872.673d81ad.js index 7e4b251bec..4785f60fe8 100644 --- a/10dee872.50de68b4.js +++ b/10dee872.673d81ad.js @@ -1,2 +1,2 @@ -/*! For license information please see 10dee872.50de68b4.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{167:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return c})),a.d(t,"metadata",(function(){return s})),a.d(t,"rightToc",(function(){return l})),a.d(t,"default",(function(){return p}));var r=a(1),n=a(9),o=(a(0),a(422)),i=(a(421),a(426),a(429)),c={last_modified_on:"2021-10-18",$schema:"/.meta/.schemas/guides.json",title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1",readingTime:"11 min read",source:"@site/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",truncated:!1,prevItem:{title:"How to activate SSO to connect to your EKS cluster",permalink:"/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster"},nextItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2"}},l=[{value:"Before getting started",id:"before-getting-started",children:[{value:"Motivation",id:"motivation",children:[]},{value:"Why AppWrite",id:"why-appwrite",children:[]}]},{value:"Technologies",id:"technologies",children:[]},{value:"Architecture",id:"architecture",children:[{value:"User flow 1: Customer request an AppWrite instance",id:"user-flow-1-customer-request-an-appwrite-instance",children:[]},{value:"User flow 2: customer deletes an AppWrite instance",id:"user-flow-2-customer-deletes-an-appwrite-instance",children:[]},{value:"AppWrite cloud frontend and backend (control plane)",id:"appwrite-cloud-frontend-and-backend-control-plane",children:[]},{value:"Qovery and AWS",id:"qovery-and-aws",children:[]},{value:"Qovery and other cloud providers",id:"qovery-and-other-cloud-providers",children:[]},{value:"MariaDB - Data persistence and backup",id:"mariadb---data-persistence-and-backup",children:[]}]},{value:"Contributors",id:"contributors",children:[]},{value:"What\u2019s next",id:"whats-next",children:[]}],u={rightToc:l};function p(e){var t=e.components,a=Object(n.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"As a developer, I am super impressed by the number of great open-source projects popping around. I think of ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://supabase.io/"}),"Supabase")," (an open-source alternative to Firebase), ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://strapi.io/"}),"Strapi")," (open-source headless CMS), ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.meilisearch.com/"}),"Meilisearch")," (open-source search engine), ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://posthog.com/"}),"Posthog")," (open-source product analytics tool), and so many others. For me, these are the tools that most developers will use in the future. One common method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. It is exactly what ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hasura.io/cloud/"}),"Hasura")," did with its cloud version - and it is pretty convenient to use their product in production. However, building a cloud version takes months (sometimes years). What takes time? Hiring platform engineers, building the infrastructure, testing it, monitoring it... All of that takes a considerable amount of time and effort. Luckily, at Qovery, we provide the infrastructure stack that every open-source project needs to build 90% of their cloud-managed version. The remaining 10% are the UI and the business model logic. In this 6-part article series, I will attempt to explain how to build a cloud-managed version of AppWrite. Let\u2019s go!"),Object(o.b)("p",null,"Articles:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Part 1: Introduction and architecture"),Object(o.b)("li",{parentName:"ul"},"Part 2: Build our AppWrite cloud backend and integrate it with the Qovery API"),Object(o.b)("li",{parentName:"ul"},"Part 3: Build our AppWrite cloud frontend and combine it with our cloud backend"),Object(o.b)("li",{parentName:"ul"},"Part 4: Monitor our AppWrite cloud version"),Object(o.b)("li",{parentName:"ul"},"Part 5: Integrate the payment system with Stripe (optional)"),Object(o.b)("li",{parentName:"ul"},"Part 6: Integrate email notification with Courier (optional)"),Object(o.b)("li",{parentName:"ul"},"Part 7: Give your customer a production, staging, and dev environment (optional)")),Object(o.b)("h2",{id:"before-getting-started"},"Before getting started"),Object(o.b)("h3",{id:"motivation"},"Motivation"),Object(o.b)("p",null,"Since I launched ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/"}),"Qovery")," in 2019, I have talked to dozens of founders from great open-source software companies. Most of them were looking to build their cloud-managed service at some point. Some of them even asked me for feedback on building one and asked me to use Qovery as a white-label technology when they discovered it was a full-time job. Qovery is a product simplifying app deployment and infrastructure management on AWS. Time flies, and as Qovery evolves, it is now possible for any open-source project to use Qovery as a white-label technology to provide a cloud version of an open-source project. No hidden cost. Just pick the plan that fits you best and build your cloud version in days instead of months. My team will be proud to help you in your success."),Object(o.b)("h3",{id:"why-appwrite"},"Why AppWrite"),Object(o.b)("p",null,Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://appwrite.io/"}),"AppWrite")," is quite representative of a \u201cmodern web open-source project\u201d. In this guide, AppWrite is used as a demo project to demonstrate the concept of building a cloud-managed version for an open-source web project. AppWrite is written in PHP for the backend and JS for the frontend. It provides a user-friendly web interface connected to a web API, and it stores the data in MariaDB and Redis databases. The idea is: if it works for AppWrite, then it is good to work for any other web open-source project with a similar technical stack. Feel free to ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://twitter.com/rophilogene"}),"contact me")," if you have any concerns."),Object(o.b)("h2",{id:"technologies"},"Technologies"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"AppWrite is a Backend as a Service open-source software. It is similar to Supabase and Firebase to create a backend in a few minutes.")),Object(o.b)("p",null,"Our goal is to provide a fully managed cloud version of AppWrite. Meaning we need to deliver to our customers a way to order their AppWrite instance and use it, while the maintenance is handled by us. It is the most common managed version out there - think MongoDB Atlas. To achieve this, we will use the following technologies:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://appwrite.io/"}),"AppWrite")),": We will use ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.docker.com/r/appwrite/appwrite"}),"AppWrite Docker container image")," to run the latest version of AppWrite."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://mariadb.org/"}),"MariaDB")),": AppWrite is using a MariaDB server for managing persistent database data."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://redis.io/"}),"Redis")),": AppWrite uses a Redis server for managing cache, queues, and scheduled tasks."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://aws.amazon.com/fr/"}),"AWS")),": We will host AppWrite on AWS EKS (Kubernetes), Redis (in-memory database), and MariaDB (AWS RDS) for each customer on AWS."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.qovery.com/"}),"Qovery")),": Qovery will create an environment composed of AppWrite, Redis, and MariaDB for each customer on our AWS account."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://hasura.io/"}),"Hasura")),": Low-code GraphQL backend to manage our customers\u2019 data."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.gatsbyjs.com/"}),"GatsbyJS")),": JS frontend framework to provide a web interface to our customers."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.postgresql.org/"}),"PostgreSQL")),": database to store our customers\u2019 data"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://auth0.com/fr"}),"Auth0")),": To manage the auth of our customers."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://stripe.com/fr"}),"Stripe")),": To charge our customers."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.courier.com/"}),"Courier")),": To send an email and Slack notifications to our customers.")),Object(o.b)("p",null,"This bunch of technologies combined enable us to build a cloud version for AppWrite. Let\u2019s take a deeper look at how all of them are interconnected."),Object(o.b)("h2",{id:"architecture"},"Architecture"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/oss-cloud-managed/part-1/architecture.svg",alt:"architecture schema"})),Object(o.b)("p",null,"This schema represents the different layers composing the cloud version of AppWrite. From top to bottom, we will give the details of each layer."),Object(o.b)("h3",{id:"user-flow-1-customer-request-an-appwrite-instance"},"User flow 1: Customer request an AppWrite instance"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/oss-cloud-managed/part-1/flow1.png",alt:"customer request an appwrite instance - behind the scene"})),Object(o.b)("p",null,"Here is what happens when the customer requests a cloud AppWrite instance:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"The customer connects on ",Object(o.b)("inlineCode",{parentName:"li"},"cloud.appwrite.com")," (fake domain to represent \u201cAppWrite cloud frontend\u201d)."),Object(o.b)("li",{parentName:"ol"},"The customer requests a new AppWrite instance."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create an ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/environment/"}),"Environment"),"."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create a MariaDB database."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create a Redis database."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create an AppWrite application."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to bind the AppWrite application to the MariaDB and Redis databases."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to start the Environment."),Object(o.b)("li",{parentName:"ol"},"The Qovery API returns the temporary URL to the AppWrite cloud backend."),Object(o.b)("li",{parentName:"ol"},"The customer receives the URL of his instance via the AppWrite cloud frontend."),Object(o.b)("li",{parentName:"ol"},"The customer can use his AppWrite instance.")),Object(o.b)("h3",{id:"user-flow-2-customer-deletes-an-appwrite-instance"},"User flow 2: customer deletes an AppWrite instance"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/oss-cloud-managed/part-1/flow2.png",alt:"customer deletes an appwrite instance - behind the scene"})),Object(o.b)("p",null,"Let\u2019s say our customer now wants to delete his cloud AppWrite instance; this is what happens:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"The customer connects on ",Object(o.b)("inlineCode",{parentName:"li"},"cloud.appwrite.com")," (fake domain to represent \u201cAppWrite cloud frontend\u201d)."),Object(o.b)("li",{parentName:"ol"},"The customer removes his AppWrite instance."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to delete the customer ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/environment/"}),"Environment"),"."),Object(o.b)("li",{parentName:"ol"},"Qovery deletes the AppWrite application, MariaDB, and Redis databases.")),Object(o.b)("p",null,"We can add other steps like payment (part 5), notifications (part 6), and everything you want - they are not required to make our cloud version functional. Let\u2019s now take a deeper look at the infrastructure."),Object(o.b)("h3",{id:"appwrite-cloud-frontend-and-backend-control-plane"},"AppWrite cloud frontend and backend (control plane)"),Object(o.b)("p",null,"The AppWrite cloud frontend and backend are the two components that we have to build from scratch. It includes our business logic and customer management system. We will use ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hasura.io/"}),"Hasura")," for the backend and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.gatsbyjs.com/"}),"GatsbyJS")," for the frontend. We will connect the frontend to the backend via a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://graphql.org/"}),"GraphQL")," API. The advantage of using Hasura instead of coding our web backend is that we have access to many features (Auth0, Stripe support...) right away. Saving days of work."),Object(o.b)("p",null,"The goal here is to provide to the customers a web interface to:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Create, update, stop, restart, delete AppWrite instances."),Object(o.b)("li",{parentName:"ul"},"Configure their custom domain."),Object(o.b)("li",{parentName:"ul"},"Charge our customers and let them pay for their subscriptions")),Object(o.b)("h3",{id:"qovery-and-aws"},"Qovery and AWS"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/"}),"Qovery")," is the simplest way to deploy apps and manage your infrastructure on AWS. We will use Qovery as an Infrastructure as Code (IaC) API.")),Object(o.b)("p",null,"Qovery provides a production-ready infrastructure on our AWS account in 30 minutes that we will use to host our customers\u2019 instances. The ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API")," provides a high-level abstraction to create for each customer an isolated ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/environment/"}),"Environment")," including:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"An AppWrite app instance with the possibility to scale it horizontally."),Object(o.b)("li",{parentName:"ol"},"A MariaDB database."),Object(o.b)("li",{parentName:"ol"},"A Redis database."),Object(o.b)("li",{parentName:"ol"},"An HTTPS endpoint."),Object(o.b)("li",{parentName:"ol"},"The option to bind a custom domain with TLS."),Object(o.b)("li",{parentName:"ol"},"A secure API to manage Environment variables and Secrets.")),Object(o.b)("p",null,"Each Environment is isolated and will be accessible for only one customer. And as admin, Qovery provides a web interface to manage all our customers\u2019 instances and troubleshoot any of their issues."),Object(o.b)("p",null,Object(o.b)("em",{parentName:"p"},"Curious to know more about how Qovery works? Take a look at ",Object(o.b)("a",Object(r.a)({parentName:"em"},{href:"https://hub.qovery.com/docs/devops/qovery-for-devops-introduction/"}),"this page"),".")),Object(o.b)("h3",{id:"qovery-and-other-cloud-providers"},"Qovery and other cloud providers"),Object(o.b)("p",null,"Qovery supports ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes/"}),"AWS"),", ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-digital-ocean/"}),"Digital Ocean"),", and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-scaleway/"}),"Scaleway"),". In this guide, we will focus on AWS to make it simpler. But keep in mind that you can use another supported cloud provider. You can even imagine a feature where your customers can choose the cloud provider of their choice. This is exactly what \u201cMongoDB Atlas\u201d and \u201cHasura Cloud\u201d do."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Side note"),": Qovery will support ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-google-cloud-platform/"}),"Google Cloud Platform")," and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-microsoft-azure/"}),"Microsoft Azure")," for S1 2022."),Object(o.b)("h3",{id:"mariadb---data-persistence-and-backup"},"MariaDB - Data persistence and backup"),Object(o.b)("p",null,"Our customers expect us to provide a reliable service and manage the database backups by using a cloud version. For AppWrite, MariaDB is the persistent database and needs to be backed up. Four options with pros and cons do exist:"),Object(o.b)("h4",{id:"1st-option-single-tenant-mariadb-container"},"1st option: single-tenant MariaDB container"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Cheap"),Object(o.b)("li",{parentName:"ul"},"Fast to spawn"),Object(o.b)("li",{parentName:"ul"},"Physical isolation per customer"),Object(o.b)("li",{parentName:"ul"},"Decent performance")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have to manage the backups")),Object(o.b)("h4",{id:"2nd-option-multi-tenant-mariadb-container"},"2nd option: multi-tenant MariaDB container"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The cheapest option (1 container divided by the number of customers means higher margins)"),Object(o.b)("li",{parentName:"ul"},"Fast to spawn")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have to manage the backups"),Object(o.b)("li",{parentName:"ul"},"No physical isolation per customer"),Object(o.b)("li",{parentName:"ul"},"The more you have customers, the poorest the performance is."),Object(o.b)("li",{parentName:"ul"},"Potential security breaches as many customers are using the same database instance.")),Object(o.b)("h4",{id:"3rd-option-single-tenant-managed-mariadb-database-aws-rds-mariadb"},"3rd option: single-tenant managed MariaDB database (AWS RDS MariaDB)"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Backup managed by AWS (point-in-time recovery included)"),Object(o.b)("li",{parentName:"ul"},"Physical isolation per customer (security++)"),Object(o.b)("li",{parentName:"ul"},"The most performant"),Object(o.b)("li",{parentName:"ul"},"Scalable (managed by AWS)")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The most expensive option (~$11 per instance for the cheapest one on AWS US-EAST-2)")),Object(o.b)("h4",{id:"4th-option-multi-tenant-managed-mariadb-database-aws-rds-mariadb"},"4th option: multi-tenant managed MariaDB database (AWS RDS MariaDB)"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Backup managed by AWS (point-in-time recovery included)"),Object(o.b)("li",{parentName:"ul"},"Higher performance than container version"),Object(o.b)("li",{parentName:"ul"},"Scalable (managed by AWS)"),Object(o.b)("li",{parentName:"ul"},"Expensive for a few customers, but the more customers you have, the cheaper it is.")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The most expensive option (~$11 per instance for the cheapest one on AWS us-east-2)"),Object(o.b)("li",{parentName:"ul"},"Potential security breaches as many customers are using the same database instance.")),Object(o.b)("p",null,"We will pick the third option (single-tenant with managed MariaDB database) to create a state-of-the-art cloud version, but you are free to choose the one you want for your customer. Do not forget your customer expects you to take care of their business."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Side note"),": AppWrite uses Redis as a caching system. Then, we will use a Redis container instance which is the cheapest."),Object(o.b)("h2",{id:"contributors"},"Contributors"),Object(o.b)("p",null,"Here is the list of contributors to this first part:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Ricardo Sueiras - Principal Advocate in OSS at AWS"),Object(o.b)("li",{parentName:"ul"},"Raman Sharma - VP Product Marketing at DigitalOcean"),Object(o.b)("li",{parentName:"ul"},"Anton Babenko - AWS Community Hero and Hashicorp Ambassador"),Object(o.b)("li",{parentName:"ul"},"Javier Viola Villanueva - Simulation Network Lead at Parity"),Object(o.b)("li",{parentName:"ul"},"Ziad Ghalleb - Product Marketing Manager at Gitguardian"),Object(o.b)("li",{parentName:"ul"},"Oliver Juhl - CTO and co-founder at Medusa"),Object(o.b)("li",{parentName:"ul"},"Yann Irbah - SRE at Fewlines"),Object(o.b)("li",{parentName:"ul"},"Laurent Doguin - ex VP Developer Relation at Clever Cloud"),Object(o.b)("li",{parentName:"ul"},"Qovery Team and our community ambassadors (Aggis, Stun3r, Kartik)")),Object(o.b)("p",null,"Thank you to our contributors for their review and suggestions."),Object(o.b)("h2",{id:"whats-next"},"What\u2019s next"),Object(o.b)("p",null,"Thank you all for taking the time to read until the end. We will build our AppWrite cloud backend and integrate it into the Qovery API in the next part."),Object(o.b)(i.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}p.isMDXComponent=!0},420:function(e,t,a){var r;!function(){"use strict";var a={}.hasOwnProperty;function n(){for(var e=[],t=0;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var l=n.a.createContext({}),u=function(e){var t=n.a.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):c({},t,{},e)),a},p=function(e){var t=u(e.components);return n.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(a),d=r,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return a?n.a.createElement(m,c({ref:t},l,{components:a})):n.a.createElement(m,c({ref:t},l))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,a),s=i>2?arguments[2]:void 0,l=void 0===s?a:n(s,a);l>c;)t[c++]=e;return t}},425:function(e,t,a){var r=a(28).f,n=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in n||a(10)&&r(n,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var r=a(0),n=a.n(r),o=a(421);t.a=function(e){var t=e.children,a=e.name;return n.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},427:function(e,t,a){"use strict";var r=a(1),n=a(0),o=a.n(n),i=a(39),c=a(430),s=a(20),l=a.n(s);t.a=function(e){var t,a=e.to,s=e.href,u=a||s,p=Object(c.a)(u),b=Object(n.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(n.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var a,r;d&&e&&p&&(a=e,r=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),r())}))}))).observe(a))},to:u})):o.a.createElement("a",Object(r.a)({},e,{href:u}))}},429:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=a(427),i=a(420),c=a.n(i);a(133);t.a=function(e){var t=e.children,a=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+l,a),d=n.a.createElement("div",{className:"jump-to--inner"},n.a.createElement("div",{className:"jump-to--inner-2"},i&&n.a.createElement("div",{className:"jump-to--left"},n.a.createElement("i",{className:"feather icon-"+i})),n.a.createElement("div",{className:"jump-to--main"},r?n.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),n.a.createElement("div",{className:"jump-to--right"},n.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?n.a.createElement("a",{href:p,target:u,className:b},d):n.a.createElement(o.a,{to:p,className:b},d)}},430:function(e,t,a){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return r}))}}]); \ No newline at end of file +/*! For license information please see 10dee872.673d81ad.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{168:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return c})),a.d(t,"metadata",(function(){return s})),a.d(t,"rightToc",(function(){return l})),a.d(t,"default",(function(){return p}));var r=a(1),n=a(9),o=(a(0),a(425)),i=(a(424),a(429),a(431)),c={last_modified_on:"2021-10-18",$schema:"/.meta/.schemas/guides.json",title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1",readingTime:"11 min read",source:"@site/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",truncated:!1,prevItem:{title:"How to activate SSO to connect to your EKS cluster",permalink:"/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster"},nextItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2"}},l=[{value:"Before getting started",id:"before-getting-started",children:[{value:"Motivation",id:"motivation",children:[]},{value:"Why AppWrite",id:"why-appwrite",children:[]}]},{value:"Technologies",id:"technologies",children:[]},{value:"Architecture",id:"architecture",children:[{value:"User flow 1: Customer request an AppWrite instance",id:"user-flow-1-customer-request-an-appwrite-instance",children:[]},{value:"User flow 2: customer deletes an AppWrite instance",id:"user-flow-2-customer-deletes-an-appwrite-instance",children:[]},{value:"AppWrite cloud frontend and backend (control plane)",id:"appwrite-cloud-frontend-and-backend-control-plane",children:[]},{value:"Qovery and AWS",id:"qovery-and-aws",children:[]},{value:"Qovery and other cloud providers",id:"qovery-and-other-cloud-providers",children:[]},{value:"MariaDB - Data persistence and backup",id:"mariadb---data-persistence-and-backup",children:[]}]},{value:"Contributors",id:"contributors",children:[]},{value:"What\u2019s next",id:"whats-next",children:[]}],u={rightToc:l};function p(e){var t=e.components,a=Object(n.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"As a developer, I am super impressed by the number of great open-source projects popping around. I think of ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://supabase.io/"}),"Supabase")," (an open-source alternative to Firebase), ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://strapi.io/"}),"Strapi")," (open-source headless CMS), ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.meilisearch.com/"}),"Meilisearch")," (open-source search engine), ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://posthog.com/"}),"Posthog")," (open-source product analytics tool), and so many others. For me, these are the tools that most developers will use in the future. One common method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. It is exactly what ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hasura.io/cloud/"}),"Hasura")," did with its cloud version - and it is pretty convenient to use their product in production. However, building a cloud version takes months (sometimes years). What takes time? Hiring platform engineers, building the infrastructure, testing it, monitoring it... All of that takes a considerable amount of time and effort. Luckily, at Qovery, we provide the infrastructure stack that every open-source project needs to build 90% of their cloud-managed version. The remaining 10% are the UI and the business model logic. In this 6-part article series, I will attempt to explain how to build a cloud-managed version of AppWrite. Let\u2019s go!"),Object(o.b)("p",null,"Articles:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Part 1: Introduction and architecture"),Object(o.b)("li",{parentName:"ul"},"Part 2: Build our AppWrite cloud backend and integrate it with the Qovery API"),Object(o.b)("li",{parentName:"ul"},"Part 3: Build our AppWrite cloud frontend and combine it with our cloud backend"),Object(o.b)("li",{parentName:"ul"},"Part 4: Monitor our AppWrite cloud version"),Object(o.b)("li",{parentName:"ul"},"Part 5: Integrate the payment system with Stripe (optional)"),Object(o.b)("li",{parentName:"ul"},"Part 6: Integrate email notification with Courier (optional)"),Object(o.b)("li",{parentName:"ul"},"Part 7: Give your customer a production, staging, and dev environment (optional)")),Object(o.b)("h2",{id:"before-getting-started"},"Before getting started"),Object(o.b)("h3",{id:"motivation"},"Motivation"),Object(o.b)("p",null,"Since I launched ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/"}),"Qovery")," in 2019, I have talked to dozens of founders from great open-source software companies. Most of them were looking to build their cloud-managed service at some point. Some of them even asked me for feedback on building one and asked me to use Qovery as a white-label technology when they discovered it was a full-time job. Qovery is a product simplifying app deployment and infrastructure management on AWS. Time flies, and as Qovery evolves, it is now possible for any open-source project to use Qovery as a white-label technology to provide a cloud version of an open-source project. No hidden cost. Just pick the plan that fits you best and build your cloud version in days instead of months. My team will be proud to help you in your success."),Object(o.b)("h3",{id:"why-appwrite"},"Why AppWrite"),Object(o.b)("p",null,Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://appwrite.io/"}),"AppWrite")," is quite representative of a \u201cmodern web open-source project\u201d. In this guide, AppWrite is used as a demo project to demonstrate the concept of building a cloud-managed version for an open-source web project. AppWrite is written in PHP for the backend and JS for the frontend. It provides a user-friendly web interface connected to a web API, and it stores the data in MariaDB and Redis databases. The idea is: if it works for AppWrite, then it is good to work for any other web open-source project with a similar technical stack. Feel free to ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://twitter.com/rophilogene"}),"contact me")," if you have any concerns."),Object(o.b)("h2",{id:"technologies"},"Technologies"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"AppWrite is a Backend as a Service open-source software. It is similar to Supabase and Firebase to create a backend in a few minutes.")),Object(o.b)("p",null,"Our goal is to provide a fully managed cloud version of AppWrite. Meaning we need to deliver to our customers a way to order their AppWrite instance and use it, while the maintenance is handled by us. It is the most common managed version out there - think MongoDB Atlas. To achieve this, we will use the following technologies:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://appwrite.io/"}),"AppWrite")),": We will use ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.docker.com/r/appwrite/appwrite"}),"AppWrite Docker container image")," to run the latest version of AppWrite."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://mariadb.org/"}),"MariaDB")),": AppWrite is using a MariaDB server for managing persistent database data."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://redis.io/"}),"Redis")),": AppWrite uses a Redis server for managing cache, queues, and scheduled tasks."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://aws.amazon.com/fr/"}),"AWS")),": We will host AppWrite on AWS EKS (Kubernetes), Redis (in-memory database), and MariaDB (AWS RDS) for each customer on AWS."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.qovery.com/"}),"Qovery")),": Qovery will create an environment composed of AppWrite, Redis, and MariaDB for each customer on our AWS account."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://hasura.io/"}),"Hasura")),": Low-code GraphQL backend to manage our customers\u2019 data."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.gatsbyjs.com/"}),"GatsbyJS")),": JS frontend framework to provide a web interface to our customers."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.postgresql.org/"}),"PostgreSQL")),": database to store our customers\u2019 data"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://auth0.com/fr"}),"Auth0")),": To manage the auth of our customers."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://stripe.com/fr"}),"Stripe")),": To charge our customers."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.courier.com/"}),"Courier")),": To send an email and Slack notifications to our customers.")),Object(o.b)("p",null,"This bunch of technologies combined enable us to build a cloud version for AppWrite. Let\u2019s take a deeper look at how all of them are interconnected."),Object(o.b)("h2",{id:"architecture"},"Architecture"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/oss-cloud-managed/part-1/architecture.svg",alt:"architecture schema"})),Object(o.b)("p",null,"This schema represents the different layers composing the cloud version of AppWrite. From top to bottom, we will give the details of each layer."),Object(o.b)("h3",{id:"user-flow-1-customer-request-an-appwrite-instance"},"User flow 1: Customer request an AppWrite instance"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/oss-cloud-managed/part-1/flow1.png",alt:"customer request an appwrite instance - behind the scene"})),Object(o.b)("p",null,"Here is what happens when the customer requests a cloud AppWrite instance:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"The customer connects on ",Object(o.b)("inlineCode",{parentName:"li"},"cloud.appwrite.com")," (fake domain to represent \u201cAppWrite cloud frontend\u201d)."),Object(o.b)("li",{parentName:"ol"},"The customer requests a new AppWrite instance."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create an ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/environment/"}),"Environment"),"."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create a MariaDB database."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create a Redis database."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create an AppWrite application."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to bind the AppWrite application to the MariaDB and Redis databases."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to start the Environment."),Object(o.b)("li",{parentName:"ol"},"The Qovery API returns the temporary URL to the AppWrite cloud backend."),Object(o.b)("li",{parentName:"ol"},"The customer receives the URL of his instance via the AppWrite cloud frontend."),Object(o.b)("li",{parentName:"ol"},"The customer can use his AppWrite instance.")),Object(o.b)("h3",{id:"user-flow-2-customer-deletes-an-appwrite-instance"},"User flow 2: customer deletes an AppWrite instance"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/oss-cloud-managed/part-1/flow2.png",alt:"customer deletes an appwrite instance - behind the scene"})),Object(o.b)("p",null,"Let\u2019s say our customer now wants to delete his cloud AppWrite instance; this is what happens:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"The customer connects on ",Object(o.b)("inlineCode",{parentName:"li"},"cloud.appwrite.com")," (fake domain to represent \u201cAppWrite cloud frontend\u201d)."),Object(o.b)("li",{parentName:"ol"},"The customer removes his AppWrite instance."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to delete the customer ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/environment/"}),"Environment"),"."),Object(o.b)("li",{parentName:"ol"},"Qovery deletes the AppWrite application, MariaDB, and Redis databases.")),Object(o.b)("p",null,"We can add other steps like payment (part 5), notifications (part 6), and everything you want - they are not required to make our cloud version functional. Let\u2019s now take a deeper look at the infrastructure."),Object(o.b)("h3",{id:"appwrite-cloud-frontend-and-backend-control-plane"},"AppWrite cloud frontend and backend (control plane)"),Object(o.b)("p",null,"The AppWrite cloud frontend and backend are the two components that we have to build from scratch. It includes our business logic and customer management system. We will use ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hasura.io/"}),"Hasura")," for the backend and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.gatsbyjs.com/"}),"GatsbyJS")," for the frontend. We will connect the frontend to the backend via a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://graphql.org/"}),"GraphQL")," API. The advantage of using Hasura instead of coding our web backend is that we have access to many features (Auth0, Stripe support...) right away. Saving days of work."),Object(o.b)("p",null,"The goal here is to provide to the customers a web interface to:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Create, update, stop, restart, delete AppWrite instances."),Object(o.b)("li",{parentName:"ul"},"Configure their custom domain."),Object(o.b)("li",{parentName:"ul"},"Charge our customers and let them pay for their subscriptions")),Object(o.b)("h3",{id:"qovery-and-aws"},"Qovery and AWS"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/"}),"Qovery")," is the simplest way to deploy apps and manage your infrastructure on AWS. We will use Qovery as an Infrastructure as Code (IaC) API.")),Object(o.b)("p",null,"Qovery provides a production-ready infrastructure on our AWS account in 30 minutes that we will use to host our customers\u2019 instances. The ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API")," provides a high-level abstraction to create for each customer an isolated ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/environment/"}),"Environment")," including:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"An AppWrite app instance with the possibility to scale it horizontally."),Object(o.b)("li",{parentName:"ol"},"A MariaDB database."),Object(o.b)("li",{parentName:"ol"},"A Redis database."),Object(o.b)("li",{parentName:"ol"},"An HTTPS endpoint."),Object(o.b)("li",{parentName:"ol"},"The option to bind a custom domain with TLS."),Object(o.b)("li",{parentName:"ol"},"A secure API to manage Environment variables and Secrets.")),Object(o.b)("p",null,"Each Environment is isolated and will be accessible for only one customer. And as admin, Qovery provides a web interface to manage all our customers\u2019 instances and troubleshoot any of their issues."),Object(o.b)("p",null,Object(o.b)("em",{parentName:"p"},"Curious to know more about how Qovery works? Take a look at ",Object(o.b)("a",Object(r.a)({parentName:"em"},{href:"https://hub.qovery.com/docs/devops/qovery-for-devops-introduction/"}),"this page"),".")),Object(o.b)("h3",{id:"qovery-and-other-cloud-providers"},"Qovery and other cloud providers"),Object(o.b)("p",null,"Qovery supports ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes/"}),"AWS"),", ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-digital-ocean/"}),"Digital Ocean"),", and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-scaleway/"}),"Scaleway"),". In this guide, we will focus on AWS to make it simpler. But keep in mind that you can use another supported cloud provider. You can even imagine a feature where your customers can choose the cloud provider of their choice. This is exactly what \u201cMongoDB Atlas\u201d and \u201cHasura Cloud\u201d do."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Side note"),": Qovery will support ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-google-cloud-platform/"}),"Google Cloud Platform")," and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-microsoft-azure/"}),"Microsoft Azure")," for S1 2022."),Object(o.b)("h3",{id:"mariadb---data-persistence-and-backup"},"MariaDB - Data persistence and backup"),Object(o.b)("p",null,"Our customers expect us to provide a reliable service and manage the database backups by using a cloud version. For AppWrite, MariaDB is the persistent database and needs to be backed up. Four options with pros and cons do exist:"),Object(o.b)("h4",{id:"1st-option-single-tenant-mariadb-container"},"1st option: single-tenant MariaDB container"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Cheap"),Object(o.b)("li",{parentName:"ul"},"Fast to spawn"),Object(o.b)("li",{parentName:"ul"},"Physical isolation per customer"),Object(o.b)("li",{parentName:"ul"},"Decent performance")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have to manage the backups")),Object(o.b)("h4",{id:"2nd-option-multi-tenant-mariadb-container"},"2nd option: multi-tenant MariaDB container"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The cheapest option (1 container divided by the number of customers means higher margins)"),Object(o.b)("li",{parentName:"ul"},"Fast to spawn")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have to manage the backups"),Object(o.b)("li",{parentName:"ul"},"No physical isolation per customer"),Object(o.b)("li",{parentName:"ul"},"The more you have customers, the poorest the performance is."),Object(o.b)("li",{parentName:"ul"},"Potential security breaches as many customers are using the same database instance.")),Object(o.b)("h4",{id:"3rd-option-single-tenant-managed-mariadb-database-aws-rds-mariadb"},"3rd option: single-tenant managed MariaDB database (AWS RDS MariaDB)"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Backup managed by AWS (point-in-time recovery included)"),Object(o.b)("li",{parentName:"ul"},"Physical isolation per customer (security++)"),Object(o.b)("li",{parentName:"ul"},"The most performant"),Object(o.b)("li",{parentName:"ul"},"Scalable (managed by AWS)")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The most expensive option (~$11 per instance for the cheapest one on AWS US-EAST-2)")),Object(o.b)("h4",{id:"4th-option-multi-tenant-managed-mariadb-database-aws-rds-mariadb"},"4th option: multi-tenant managed MariaDB database (AWS RDS MariaDB)"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Backup managed by AWS (point-in-time recovery included)"),Object(o.b)("li",{parentName:"ul"},"Higher performance than container version"),Object(o.b)("li",{parentName:"ul"},"Scalable (managed by AWS)"),Object(o.b)("li",{parentName:"ul"},"Expensive for a few customers, but the more customers you have, the cheaper it is.")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The most expensive option (~$11 per instance for the cheapest one on AWS us-east-2)"),Object(o.b)("li",{parentName:"ul"},"Potential security breaches as many customers are using the same database instance.")),Object(o.b)("p",null,"We will pick the third option (single-tenant with managed MariaDB database) to create a state-of-the-art cloud version, but you are free to choose the one you want for your customer. Do not forget your customer expects you to take care of their business."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Side note"),": AppWrite uses Redis as a caching system. Then, we will use a Redis container instance which is the cheapest."),Object(o.b)("h2",{id:"contributors"},"Contributors"),Object(o.b)("p",null,"Here is the list of contributors to this first part:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Ricardo Sueiras - Principal Advocate in OSS at AWS"),Object(o.b)("li",{parentName:"ul"},"Raman Sharma - VP Product Marketing at DigitalOcean"),Object(o.b)("li",{parentName:"ul"},"Anton Babenko - AWS Community Hero and Hashicorp Ambassador"),Object(o.b)("li",{parentName:"ul"},"Javier Viola Villanueva - Simulation Network Lead at Parity"),Object(o.b)("li",{parentName:"ul"},"Ziad Ghalleb - Product Marketing Manager at Gitguardian"),Object(o.b)("li",{parentName:"ul"},"Oliver Juhl - CTO and co-founder at Medusa"),Object(o.b)("li",{parentName:"ul"},"Yann Irbah - SRE at Fewlines"),Object(o.b)("li",{parentName:"ul"},"Laurent Doguin - ex VP Developer Relation at Clever Cloud"),Object(o.b)("li",{parentName:"ul"},"Qovery Team and our community ambassadors (Aggis, Stun3r, Kartik)")),Object(o.b)("p",null,"Thank you to our contributors for their review and suggestions."),Object(o.b)("h2",{id:"whats-next"},"What\u2019s next"),Object(o.b)("p",null,"Thank you all for taking the time to read until the end. We will build our AppWrite cloud backend and integrate it into the Qovery API in the next part."),Object(o.b)(i.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}p.isMDXComponent=!0},423:function(e,t,a){var r;!function(){"use strict";var a={}.hasOwnProperty;function n(){for(var e=[],t=0;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var l=n.a.createContext({}),u=function(e){var t=n.a.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):c({},t,{},e)),a},p=function(e){var t=u(e.components);return n.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(a),d=r,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return a?n.a.createElement(m,c({ref:t},l,{components:a})):n.a.createElement(m,c({ref:t},l))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,a),s=i>2?arguments[2]:void 0,l=void 0===s?a:n(s,a);l>c;)t[c++]=e;return t}},428:function(e,t,a){var r=a(28).f,n=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in n||a(10)&&r(n,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var r=a(0),n=a.n(r),o=a(424);t.a=function(e){var t=e.children,a=e.name;return n.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},430:function(e,t,a){"use strict";var r=a(1),n=a(0),o=a.n(n),i=a(39),c=a(432),s=a(20),l=a.n(s);t.a=function(e){var t,a=e.to,s=e.href,u=a||s,p=Object(c.a)(u),b=Object(n.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(n.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var a,r;d&&e&&p&&(a=e,r=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),r())}))}))).observe(a))},to:u})):o.a.createElement("a",Object(r.a)({},e,{href:u}))}},431:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=a(430),i=a(423),c=a.n(i);a(133);t.a=function(e){var t=e.children,a=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+l,a),d=n.a.createElement("div",{className:"jump-to--inner"},n.a.createElement("div",{className:"jump-to--inner-2"},i&&n.a.createElement("div",{className:"jump-to--left"},n.a.createElement("i",{className:"feather icon-"+i})),n.a.createElement("div",{className:"jump-to--main"},r?n.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),n.a.createElement("div",{className:"jump-to--right"},n.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?n.a.createElement("a",{href:p,target:u,className:b},d):n.a.createElement(o.a,{to:p,className:b},d)}},432:function(e,t,a){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/10ff7003.e3536361.js.LICENSE.txt b/10dee872.673d81ad.js.LICENSE.txt similarity index 100% rename from 10ff7003.e3536361.js.LICENSE.txt rename to 10dee872.673d81ad.js.LICENSE.txt diff --git a/10ff7003.e3536361.js b/10ff7003.3da3b546.js similarity index 92% rename from 10ff7003.e3536361.js rename to 10ff7003.3da3b546.js index bd1823b15c..565cb4af9a 100644 --- a/10ff7003.e3536361.js +++ b/10ff7003.3da3b546.js @@ -1,2 +1,2 @@ -/*! For license information please see 10ff7003.e3536361.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{168:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return c})),r.d(t,"metadata",(function(){return u})),r.d(t,"rightToc",(function(){return s})),r.d(t,"default",(function(){return p}));var n=r(1),o=r(9),a=(r(0),r(422)),i=r(431),c={last_modified_on:"2023-05-19",title:"Database Troubleshoot",description:"Everything you need to troubleshoot your databases with Qovery",hide_pagination:!0},u={id:"using-qovery/troubleshoot/database-troubleshoot",title:"Database Troubleshoot",description:"Everything you need to troubleshoot your databases with Qovery",source:"@site/docs/using-qovery/troubleshoot/database-troubleshoot.md",permalink:"/docs/using-qovery/troubleshoot/database-troubleshoot",sidebar:"docs",previous:{title:"Application Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/application-troubleshoot"},next:{title:"Lifecycle Job Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/lifecycle-troubleshoot"}},s=[{value:"During a managed database delete, I've this error: SnapshotQuotaExceeded",id:"during-a-managed-database-delete-ive-this-error-snapshotquotaexceeded",children:[]}],l={rightToc:s};function p(e){var t=e.components,r=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},l,r,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Within this section you will find the common errors you might encounter when deploying or running your databases with Qovery"),Object(a.b)("h2",{id:"during-a-managed-database-delete-ive-this-error-snapshotquotaexceeded"},"During a managed database delete, I've this error: SnapshotQuotaExceeded"),Object(a.b)("p",null,"This errors occurs because Qovery creates a snapshot before the delete of the database. This to avoid a user mistake who delete a database accidentally."),Object(a.b)("p",null,"To fix this issue, you have 2 solutions:"),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"You certainly have useless snapshots, from old databases or old ones you don't want to keep anymore. Delete them directly from your Cloud Provider web interface. Here is an example on AWS:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Search for the database service (here RDS)"),Object(a.b)("li",{parentName:"ul"},"Select the Snapshots menu"),Object(a.b)("li",{parentName:"ul"},"Select the snapshots to delete")),Object(a.b)("p",{Valign:"center"},Object(a.b)("img",{src:"/img/configuration/database/db-snaptshots-quotas-exceed.png",alt:"Database snapshots"}))),Object(a.b)("li",null,Object(a.b)("p",null,"Open a ticket to the Cloud Provider support, and as to raise this limit.")))))}p.isMDXComponent=!0},420:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(r),b=n,f=p["".concat(i,".").concat(b)]||p[b]||d[b]||a;return r?o.a.createElement(f,c({ref:t},s,{components:r})):o.a.createElement(f,c({ref:t},s))}));function f(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=r.length,i=new Array(a);i[0]=b;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(r),b=n,f=p["".concat(i,".").concat(b)]||p[b]||d[b]||a;return r?o.a.createElement(f,c({ref:t},s,{components:r})):o.a.createElement(f,c({ref:t},s))}));function f(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=r.length,i=new Array(a);i[0]=b;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s \\\n --project \\\n --environment \\\n --container \\\n --tag $CI_COMMIT_SHORT_SHA \\\n --watch\n")),Object(a.b)("h2",{id:"qovery-cli-command-examples"},"Qovery CLI command examples"),Object(a.b)("h3",{id:"deploy-your-application-with-a-specific-commit-id"},"Deploy your application with a specific commit ID"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"qovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n")),Object(a.b)(i.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,Object(a.b)("inlineCode",{parentName:"p"},"--watch")," is an optional parameter that will display the status of the deployment and return 0 if the deployment is successful or 1 if it fails.")),Object(a.b)("h3",{id:"deploy-your-multiple-applications-with-a-different-commit-id"},"Deploy your multiple applications with a different commit ID"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"# deploy the application 1 and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n\n# deploy the application 2 and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n")),Object(a.b)("p",null,"This is also applicable for the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery container deploy"),", ",Object(a.b)("inlineCode",{parentName:"p"},"qovery lifecycle deploy"),", and ",Object(a.b)("inlineCode",{parentName:"p"},"qovery cronjob deploy")," commands."),Object(a.b)("h3",{id:"deploy-your-multiple-applications-with-a-specific-commit-id-monorepo"},"Deploy your multiple applications with a specific commit ID (monorepo)"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),'# deploy the application 1, 2 and 3 with the same commit ID and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --applications ", , " \\\n --commit-id \\\n --watch\n')),Object(a.b)("p",null,"This is also applicable for the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery container deploy"),", ",Object(a.b)("inlineCode",{parentName:"p"},"qovery lifecycle deploy"),", and ",Object(a.b)("inlineCode",{parentName:"p"},"qovery cronjob deploy")," commands."),Object(a.b)("h3",{id:"create-a-preview-environment-for-your-pull-request"},"Create a Preview Environment for your Pull-Request"),Object(a.b)("p",null,"Qovery integrates automatically with GitHub, GitLab and Bitbucket to create a Preview Environment for each Pull-Request. But in case you want to control the creation of the Preview Environment manually, you can use the following commands:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"# Clone your base environment\nqovery environment clone \\\n --organization \\\n --project \\\n --environment \\\n --new-environment-name \n\n# Change your application branch to the Pull-Request branch\nqovery application update \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --branch \n\n# Deploy your new environment\nqovery environment deploy \\\n --organization \\\n --project \\\n --environment \\\n --watch\n")),Object(a.b)("h3",{id:"delete-a-preview-environment"},"Delete a Preview Environment"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"qovery environment delete \\\n --organization \\\n --project \\\n --environment \\\n --watch\n")),Object(a.b)("h3",{id:"terraform"},"Terraform"),Object(a.b)("p",null,"Do you want to include Terraform in your CI? Check out our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"Terraform documentation"),"."),Object(a.b)("h3",{id:"any-other-examples"},"Any other examples?"),Object(a.b)("p",null,"Feel free to share your examples with us, and we'll be happy to share them with the community. Contact us on ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum"),"."))}s.isMDXComponent=!0},420:function(e,n,t){var o;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var p=r.a.createContext({}),u=function(e){var n=r.a.useContext(p),t=n;return e&&(t="function"==typeof e?e(n):c({},n,{},e)),t},m=function(e){var n=u(e.components);return r.a.createElement(p.Provider,{value:n},e.children)},s={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},y=Object(o.forwardRef)((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),m=u(t),y=o,b=m["".concat(i,".").concat(y)]||m[y]||s[y]||a;return t?r.a.createElement(b,c({ref:n},p,{components:t})):r.a.createElement(b,c({ref:n},p))}));function b(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=y;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var p=2;p1?arguments[1]:void 0,t),l=i>2?arguments[2]:void 0,p=void 0===l?t:r(l,t);p>c;)n[c++]=e;return n}},425:function(e,n,t){var o=t(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||t(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,n,t){"use strict";t(425);var o=t(0),r=t.n(o),a=t(421);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}}}]); \ No newline at end of file +/*! For license information please see 120e882c.75e21d91.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{170:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return l})),t.d(n,"metadata",(function(){return p})),t.d(n,"rightToc",(function(){return u})),t.d(n,"default",(function(){return s}));var o=t(1),r=t(9),a=(t(0),t(425)),i=t(424),c=t(429),l={last_modified_on:"2023-09-27",title:"GitLab CI",description:"Learn how to connect GitLab CI to Qovery"},p={id:"using-qovery/integration/continuous-integration/gitlab-ci",title:"GitLab CI",description:"Learn how to connect GitLab CI to Qovery",source:"@site/docs/using-qovery/integration/continuous-integration/gitlab-ci.md",permalink:"/docs/using-qovery/integration/continuous-integration/gitlab-ci",sidebar:"docs",previous:{title:"GitHub Actions",permalink:"/docs/using-qovery/integration/continuous-integration/github-actions"},next:{title:"Circle CI",permalink:"/docs/using-qovery/integration/continuous-integration/circle-ci"}},u=[{value:"Prerequisites",id:"prerequisites",children:[]},{value:"GitLab CI Examples",id:"gitlab-ci-examples",children:[{value:"Deploy a container application",id:"deploy-a-container-application",children:[]}]},{value:"Qovery CLI command examples",id:"qovery-cli-command-examples",children:[{value:"Deploy your application with a specific commit ID",id:"deploy-your-application-with-a-specific-commit-id",children:[]},{value:"Deploy your multiple applications with a different commit ID",id:"deploy-your-multiple-applications-with-a-different-commit-id",children:[]},{value:"Deploy your multiple applications with a specific commit ID (monorepo)",id:"deploy-your-multiple-applications-with-a-specific-commit-id-monorepo",children:[]},{value:"Create a Preview Environment for your Pull-Request",id:"create-a-preview-environment-for-your-pull-request",children:[]},{value:"Delete a Preview Environment",id:"delete-a-preview-environment",children:[]},{value:"Terraform",id:"terraform",children:[]},{value:"Any other examples?",id:"any-other-examples",children:[]}]}],m={rightToc:u};function s(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},m,t,{components:n,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Using Gitlab CI with Qovery is super powerful and gives you the ability to manage the way that you want to deploy your applications. As the possibility are endless, I will share with you a couple of examples that you can use. Feel free to adapt them to your need."),Object(a.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(a.b)("p",null,"Before using the examples below, you need to:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Install the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI"),"."),Object(a.b)("li",{parentName:"ol"},"Generate an API token via ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/#generate-api-token"}),"the CLI")," or the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/api-token/"}),"Console")," ."),Object(a.b)("li",{parentName:"ol"},"Set the environment variable ",Object(a.b)("inlineCode",{parentName:"li"},"Q_CLI_ACCESS_TOKEN")," or ",Object(a.b)("inlineCode",{parentName:"li"},"QOVERY_CLI_ACCESS_TOKEN")," (both are valid) with your API token. E.g. ",Object(a.b)("inlineCode",{parentName:"li"},"export QOVERY_CLI_ACCESS_TOKEN=your-api-token")),Object(a.b)("li",{parentName:"ol"},"You have turned off the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Qovery Auto Deployment")," for every service that you want to deploy manually.")),Object(a.b)("h2",{id:"gitlab-ci-examples"},"GitLab CI Examples"),Object(a.b)("h3",{id:"deploy-a-container-application"},"Deploy a container application"),Object(a.b)(c.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"connected your Container Registry with Qovery"),"."),Object(a.b)("li",{parentName:"ul"},"You have a container application that you want to deploy on Qovery."),Object(a.b)("li",{parentName:"ul"},"You have set the ",Object(a.b)("inlineCode",{parentName:"li"},"QOVERY_CLI_ACCESS_TOKEN")," environment variable in your GitLab CI project."))),Object(a.b)("p",null,"This example will deploy a container application with Qovery from your GitLab CI pipeline. Feel free to adapt it to your need."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-yaml",metastring:'title=".gitlab-ci.yml"',title:'".gitlab-ci.yml"'}),"# 1. Build and Push image to a remote registry\n# 2. Deploy with Qovery\n\nstages:\n - build-and-push\n - deploy\n\nbuild-and-push-image:\n stage: build-and-push\n script:\n - docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY\n - docker build . --tag my-registry-group/your-app:$CI_COMMIT_SHORT_SHA\n - docker push my-registry-group/your-app:$CI_COMMIT_SHORT_SHA\n\ndeploy-image-with-qovery:\n stage: deploy\n script:\n - curl -s https://get.qovery.com | bash # Download and install Qovery CLI\n - |\n qovery container deploy \\\n --organization \\\n --project \\\n --environment \\\n --container \\\n --tag $CI_COMMIT_SHORT_SHA \\\n --watch\n")),Object(a.b)("h2",{id:"qovery-cli-command-examples"},"Qovery CLI command examples"),Object(a.b)("h3",{id:"deploy-your-application-with-a-specific-commit-id"},"Deploy your application with a specific commit ID"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"qovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n")),Object(a.b)(i.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,Object(a.b)("inlineCode",{parentName:"p"},"--watch")," is an optional parameter that will display the status of the deployment and return 0 if the deployment is successful or 1 if it fails.")),Object(a.b)("h3",{id:"deploy-your-multiple-applications-with-a-different-commit-id"},"Deploy your multiple applications with a different commit ID"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"# deploy the application 1 and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n\n# deploy the application 2 and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n")),Object(a.b)("p",null,"This is also applicable for the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery container deploy"),", ",Object(a.b)("inlineCode",{parentName:"p"},"qovery lifecycle deploy"),", and ",Object(a.b)("inlineCode",{parentName:"p"},"qovery cronjob deploy")," commands."),Object(a.b)("h3",{id:"deploy-your-multiple-applications-with-a-specific-commit-id-monorepo"},"Deploy your multiple applications with a specific commit ID (monorepo)"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),'# deploy the application 1, 2 and 3 with the same commit ID and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --applications ", , " \\\n --commit-id \\\n --watch\n')),Object(a.b)("p",null,"This is also applicable for the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery container deploy"),", ",Object(a.b)("inlineCode",{parentName:"p"},"qovery lifecycle deploy"),", and ",Object(a.b)("inlineCode",{parentName:"p"},"qovery cronjob deploy")," commands."),Object(a.b)("h3",{id:"create-a-preview-environment-for-your-pull-request"},"Create a Preview Environment for your Pull-Request"),Object(a.b)("p",null,"Qovery integrates automatically with GitHub, GitLab and Bitbucket to create a Preview Environment for each Pull-Request. But in case you want to control the creation of the Preview Environment manually, you can use the following commands:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"# Clone your base environment\nqovery environment clone \\\n --organization \\\n --project \\\n --environment \\\n --new-environment-name \n\n# Change your application branch to the Pull-Request branch\nqovery application update \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --branch \n\n# Deploy your new environment\nqovery environment deploy \\\n --organization \\\n --project \\\n --environment \\\n --watch\n")),Object(a.b)("h3",{id:"delete-a-preview-environment"},"Delete a Preview Environment"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"qovery environment delete \\\n --organization \\\n --project \\\n --environment \\\n --watch\n")),Object(a.b)("h3",{id:"terraform"},"Terraform"),Object(a.b)("p",null,"Do you want to include Terraform in your CI? Check out our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"Terraform documentation"),"."),Object(a.b)("h3",{id:"any-other-examples"},"Any other examples?"),Object(a.b)("p",null,"Feel free to share your examples with us, and we'll be happy to share them with the community. Contact us on ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum"),"."))}s.isMDXComponent=!0},423:function(e,n,t){var o;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var p=r.a.createContext({}),u=function(e){var n=r.a.useContext(p),t=n;return e&&(t="function"==typeof e?e(n):c({},n,{},e)),t},m=function(e){var n=u(e.components);return r.a.createElement(p.Provider,{value:n},e.children)},s={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},y=Object(o.forwardRef)((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),m=u(t),y=o,b=m["".concat(i,".").concat(y)]||m[y]||s[y]||a;return t?r.a.createElement(b,c({ref:n},p,{components:t})):r.a.createElement(b,c({ref:n},p))}));function b(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=y;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var p=2;p1?arguments[1]:void 0,t),l=i>2?arguments[2]:void 0,p=void 0===l?t:r(l,t);p>c;)n[c++]=e;return n}},428:function(e,n,t){var o=t(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||t(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,n,t){"use strict";t(428);var o=t(0),r=t.n(o),a=t(424);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}}}]); \ No newline at end of file diff --git a/16557ade.4a5ef5be.js.LICENSE.txt b/120e882c.75e21d91.js.LICENSE.txt similarity index 100% rename from 16557ade.4a5ef5be.js.LICENSE.txt rename to 120e882c.75e21d91.js.LICENSE.txt diff --git a/16557ade.4a5ef5be.js b/16557ade.13e4779d.js similarity index 89% rename from 16557ade.4a5ef5be.js rename to 16557ade.13e4779d.js index b53943b01e..07a3f913a8 100644 --- a/16557ade.4a5ef5be.js +++ b/16557ade.13e4779d.js @@ -1,2 +1,2 @@ -/*! For license information please see 16557ade.4a5ef5be.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{170:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return d}));var o=n(1),a=n(9),i=(n(0),n(422)),r=n(431),l=(n(429),n(421)),c=n(426),s={last_modified_on:"2023-09-27",title:"Lifecycle Job",description:"Learn how to configure your Lifecycle job on Qovery"},u={id:"using-qovery/configuration/lifecycle-job",title:"Lifecycle Job",description:"Learn how to configure your Lifecycle job on Qovery",source:"@site/docs/using-qovery/configuration/lifecycle-job.md",permalink:"/docs/using-qovery/configuration/lifecycle-job",sidebar:"docs",previous:{title:"Cronjob",permalink:"/docs/using-qovery/configuration/cronjob"},next:{title:"Environment Variable & Secrets",permalink:"/docs/using-qovery/configuration/environment-variable"}},b=[{value:"Deploying from a Git Repository",id:"deploying-from-a-git-repository",children:[]},{value:"Deploying from a Container Registry",id:"deploying-from-a-container-registry",children:[]},{value:"Create a Job",id:"create-a-job",children:[]},{value:"Deployment Management",id:"deployment-management",children:[]},{value:"Force Run",id:"force-run",children:[]},{value:"Configuration",id:"configuration",children:[{value:"General",id:"general",children:[]},{value:"JOB Configuration",id:"job-configuration",children:[]},{value:"Resources",id:"resources",children:[]},{value:"Health Checks",id:"health-checks",children:[]}]},{value:"Environment Variable",id:"environment-variable",children:[]},{value:"Secrets",id:"secrets",children:[]},{value:"Logs",id:"logs",children:[]},{value:"Job output",id:"job-output",children:[]},{value:"Clone",id:"clone",children:[]},{value:"Delete a job",id:"delete-a-job",children:[]}],p={rightToc:b};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(c.a,{name:"documentation",mdxType:"Assumptions"},Object(i.b)("p",null,"You have created an ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment"),".")),Object(i.b)("p",null,"A ",Object(i.b)("strong",{parentName:"p"},"Lifecycle Job")," is a job that runs on your kubernetes cluster with the following characteristics:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"it is executed ONLY when the selected environment event occurs (unless its execution is forced, ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"#force-execution"}),"see the Force execution section"),")."),Object(i.b)("li",{parentName:"ul"},"any output file created at the end of the execution will be automatically injected as environment variable to any service within the same environment (",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"#job-output"}),"see the Job Output section"),").")),Object(i.b)("p",null,"Given its characteristics, lifecycle jobs are particularly useful for:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Seed your database on your preview environment: you can create a custom job that will seed a database when the preview environment is deployed"),Object(i.b)("li",{parentName:"ul"},"Create an external resources not natively managed by Qovery: you can create a custom job that will create the external resource. By writing the connection strings in an output file, those information will be injected as environment variables on any service of the environment (so that they can consume this new resource).")),Object(i.b)("p",null,"A lifecycle job can be executed on the following environment events:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Start"),': the job is executed when the environment starts. Note that a start event is generated on both the "Deploy" and "Redeploy" actions so you should take care of managing this in your code to avoid executing it twice (on the first deploy and on the re-deploy).'),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Stop"),": the job is executed when the environment stops."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Delete"),": the job is executed when the environment is deleted.")),Object(i.b)(l.a,{type:"success",mdxType:"Alert"},Object(i.b)("p",null,"Check out ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"this complete example")," on how to deploy a Terraform module with the Lifecycle Job feature")),Object(i.b)("p",null,"Qovery allows you to create and deploy jobs from two different sources: Git Repository or Container Registry"),Object(i.b)("h2",{id:"deploying-from-a-git-repository"},"Deploying from a Git Repository"),Object(i.b)("p",null,"In this configuration, Qovery will pull the code from the chosen repository, build the application and deploy it on your kubernetes cluster."),Object(i.b)("p",null,"The list of Git repositories available during the setup is strictly tied to the permissions of your git account (by default Qovery can access all your repositories). If you want to restrict the Qovery access only to a few repositories, user the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/git-repository-access/"}),"GitHub Qovery Application")," (only for Github)."),Object(i.b)("h2",{id:"deploying-from-a-container-registry"},"Deploying from a Container Registry"),Object(i.b)("p",null,"In this configuration, Qovery will pull the chosen container registry an image you have pre-built and deploy it on your kubernetes cluster."),Object(i.b)("p",null,"To improve the security and avoid deploying images from non-authorized registries, we have decided to restrict the list of Container Registry you can use during the setup process. Only an administrator with the right permissions can manage it from the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")),Object(i.b)("h2",{id:"create-a-job"},"Create a Job"),Object(i.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,'Go into the chosen environment and press the "New Service" button and then the "Create Lifecycle job" button'),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/environments/service_creation.png",alt:"Creation"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Select the following fields:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Name: give a name to your application"),Object(i.b)("li",{parentName:"ul"},"Source: Chose between Git Repository or Container Registry, depending on the source location of your application")),Object(i.b)("p",null,"If you want to deploy a cronjob from a Git Repository you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Git Repository: Select the git provider hosting your code (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Branch: Select branch that Qovery should use to deploy your code"),Object(i.b)("li",{parentName:"ul"},"Root Application Path: base folder in which the code resides in your repository"),Object(i.b)("li",{parentName:"ul"},"Build Mode: only Docker is supported")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"A Dockerfile is necessary to build and deploy your job")),Object(i.b)("p",null,"If you want to deploy a job from a Container Registry you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Registry: select the container registry storing the image of your job. Note: only pre-configured registry are available in this list, check the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," for more information."),Object(i.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this job (example: postgres)"),Object(i.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this job (example: 12)")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"The tag 'latest' is not supported, please use a specific tag.")),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Auto Deploy ")),Object(i.b)("p",null,"See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section.")),Object(i.b)("li",null,Object(i.b)("p",null,"Specify the configuration of your job:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Event: select the environment event which should trigger the execution of the job (Environment start, stop, delete)"),Object(i.b)("li",{parentName:"ul"},"Image Entrypoint: the entrypoint to be used to launch your job (not mandatory)."),Object(i.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your job (not mandatory). We expect the format to be an array. Example ",'["rails", "-h", "0.0.0.0", "-p", "8080", "string"]'),Object(i.b)("li",{parentName:"ul"},"Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure)"),Object(i.b)("li",{parentName:"ul"},"Max duration time in seconds: Maximum duration allowed for the job to run before killing it and mark it as failed"),Object(i.b)("li",{parentName:"ul"},"Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,'Entrypoint and Arguments can be customized for each event. This will allow your job to behave differently depending on the environment status (example: you might want to run a "create" command when the environment starts and a "destroy" command when the environment is deleted)'))),Object(i.b)("li",null,"Within this section, you will need to define the resources to be assigned to your job at run time.",Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"vCPU: the vCPU assigned to each instance of your application. The default is 500m (0.5 vCPU)."),Object(i.b)("li",{parentName:"ul"},"RAM: the amount of RAM assigned to each instance of your application. The default is 512MB.")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Please note that in this section you configure the CPU/RAM allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU/RAM."))),Object(i.b)("li",null,Object(i.b)("p",null,"Define any input variable required by your job to run. Any declared variable will be injected as environment variables based on the selected scope (project, environment, service)\nAny additional environment variable can be added later from the environment variable section"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/job/variables.png",alt:"Input Variables"}))),Object(i.b)("li",null,Object(i.b)("p",null,"You will find a recap of your job setup and you can now decide to:\n1. Go back to one of the previous steps and change your settings\n2. Create your job without deploying it\n3. Create and deploy your job"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/job/cronjob_recap.png",alt:"Recap"}))))),Object(i.b)("h2",{id:"deployment-management"},"Deployment Management"),Object(i.b)("p",null,"Have a look at the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/"}),"Deployment Management")," section for more information."),Object(i.b)("h2",{id:"force-run"},"Force Run"),Object(i.b)("p",null,"You can force the execution of a job independently its deployment status by:"),Object(i.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Select the job that you want to force")),Object(i.b)("li",null,Object(i.b)("p",null,"click on the ",Object(i.b)("inlineCode",{parentName:"p"},"Play")," button of the cronjob you want to force and select the ",Object(i.b)("inlineCode",{parentName:"p"},"Force Run")," option. Note: the same option is available on the service list as well")),Object(i.b)("li",null,Object(i.b)("p",null,"Select the environment event you want to force. ")),Object(i.b)("li",null,Object(i.b)("p",null,"Once you click, the job will be deployed and executed with the entrypoint and arguments associated to the selected event. You will be able to follow its execution within the application logs")))),Object(i.b)("h2",{id:"configuration"},"Configuration"),Object(i.b)("p",null,"Once created, you can access the configuration at any time via the Settings tab available on the service section"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/settings.png",alt:"Settings"})),Object(i.b)("p",null,"You can find below the description of each of the tabs available in this section"),Object(i.b)("h3",{id:"general"},"General"),Object(i.b)("p",null,"General settings section allows you to set up your application name and the source code location (git repository or image registry) ."),Object(i.b)("h4",{id:"git-repository"},"Git Repository"),Object(i.b)("p",null,"If your job is built and deployed from a git repository, within this section you can:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Modify the git provider where your code is stored (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Modify the branch that Qovery should use for deploying your code"),Object(i.b)("li",{parentName:"ul"},"Modify ",Object(i.b)("inlineCode",{parentName:"li"},"Root Application Path")," - base folder in which the application resides in your repository")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Qovery supports mono repositories. ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/advanced/monorepository/"}),"See our advanced guide for more details."))),Object(i.b)(l.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"If your repository contains private submodules using SSH protocol, you will need to add a secret beginning with GIT",Object(i.b)("em",{parentName:"p"},"SSH_KEY"),", containing a private SSH key with access rights to your sumbodules repositories."),Object(i.b)("p",null,"Secret names examples:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITHUB"),Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITLAB"),Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_MYAPP"))),Object(i.b)("h4",{id:"container-registry"},"Container Registry"),Object(i.b)("p",null,"If your application is deployed from an image registry, within this section you can modify:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Registry: select the container registry storing the image of your application. Note: only pre-configured registry are available in this list, check the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," for more information."),Object(i.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this application (example: postgres)"),Object(i.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this application (example: 12)")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"The tag 'latest' is not supported, please use a specific tag.")),Object(i.b)("h4",{id:"build-mode"},"Build Mode"),Object(i.b)("p",null,'This option is available only if you have selected "Git Repository" as source. Only Docker is supported'),Object(i.b)("p",null,"Qovery runs your application within the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://www.docker.com/resources/what-container"}),"Container technology"),". To build and run your application, you need to provide a valid ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.docker.com/engine/reference/builder"}),"Dockerfile"),"."),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-Dockerfile",metastring:'title="Valid NodeJS Dockerfile"',title:'"Valid',NodeJS:!0,'Dockerfile"':!0}),"FROM node:13-alpine\nRUN mkdir -p /usr/src/app\nWORKDIR /usr/src/app\nCOPY . .\nRUN npm install\nEXPOSE 3000\nCMD node ./bin/www\n")),Object(i.b)("p",null,"After creating a Dockerfile, specify the location of your Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"Dockefile path")," field."),Object(i.b)("p",null,"Configuration from above will make Qovery look for the Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"/timescale/Dockerfile")," path of your repository (",Object(i.b)("inlineCode",{parentName:"p"},"Root Application Path")," + ",Object(i.b)("inlineCode",{parentName:"p"},"Dockerfile Path"),")."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Auto Deploy ")),Object(i.b)("p",null,"See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section."),Object(i.b)("h3",{id:"job-configuration"},"JOB Configuration"),Object(i.b)("p",null,"You can modify here the configuration of your job:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"CRON Schedule: specify a valid CRON expression (see ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"https://crontab.guru/"}),"Crontab guru")," for help). After being deployed, the job will be executed following the defined schedule."),Object(i.b)("li",{parentName:"ul"},"Image Entrypoint: the entrypoint to be used to launch your job (not mandatory)"),Object(i.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your job (not mandatory). We expect the format to be an array. Example ",'["rails", "-h", "0.0.0.0", "-p", "8080", "string"]'),Object(i.b)("li",{parentName:"ul"},"Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure)"),Object(i.b)("li",{parentName:"ul"},"Max duration time in seconds: Maximum duration allowed for the job to run before killing it and mark it as failed"),Object(i.b)("li",{parentName:"ul"},"Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally")),Object(i.b)("h3",{id:"resources"},"Resources"),Object(i.b)("h4",{id:"cpu"},"CPU"),Object(i.b)("p",null,"To configure the number of CPUs that your job needs, adjust the setting in the ",Object(i.b)("inlineCode",{parentName:"p"},"Resources")," section."),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Default is 500m (0.5 vCPU).")),Object(i.b)("p",null,"Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU."),Object(i.b)("h4",{id:"ram"},"RAM"),Object(i.b)("p",null,"To configure the amount of RAM that your app needs, adjust the setting in ",Object(i.b)("inlineCode",{parentName:"p"},"Resources")," section."),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Default is 512MB.")),Object(i.b)("p",null,"Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU. If your application requires more RAM than requested, it will be killed by the kubernetes scheduler."),Object(i.b)("h3",{id:"health-checks"},"Health Checks"),Object(i.b)("p",null,"To know more about how to configure your Liveness and Readiness probes, have a look at ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application-health-checks/"}),"the health-checks section")),Object(i.b)("h2",{id:"environment-variable"},"Environment Variable"),Object(i.b)("p",null,"To learn how to set up environment variables in your projects and applications, navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Environment Variables")," section."),Object(i.b)("h2",{id:"secrets"},"Secrets"),Object(i.b)("p",null,"To learn how to set up secrets in your projects and applications, navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Secrets")," section."),Object(i.b)("h2",{id:"logs"},"Logs"),Object(i.b)("p",null,"To learn how to display your application logs, navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#live-logs"}),"logs section")),Object(i.b)("h2",{id:"job-output"},"Job output"),Object(i.b)("p",null,"Qovery expects the output file to be written in the following path ",Object(i.b)("inlineCode",{parentName:"p"},"/qovery-output/qovery-output.json")," (the ",Object(i.b)("inlineCode",{parentName:"p"},"output")," folder is automatically mounted by Qovery).\nThe file should follow this format:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-json"}),'{\n "varname1": {\n "sensitive": true,\n "value": "myvalue"\n },\n "varname2": {\n "sensitive": false,\n "value": "myvalue"\n }\n}\n...\n')),Object(i.b)("p",null,"At the end of the job execution, this file will be processed by Qovery and a set of environment variables will be created, one for each element in the json. The information in the json file will be mapped to an environment variables in this way:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Variable Name: ",Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_OUTPUT_JOB__")," , where ",Object(i.b)("inlineCode",{parentName:"li"},"")," is the id of the Job on Qovery side and ",Object(i.b)("inlineCode",{parentName:"li"},"")," is the name of the element in the output file."),Object(i.b)("li",{parentName:"ul"},'Variable Value: field "value"'),Object(i.b)("li",{parentName:"ul"},'Secret: field "sensitive"')),Object(i.b)("p",null,"An alias ",Object(i.b)("inlineCode",{parentName:"p"},"")," will be automatically created to simplify your setup."),Object(i.b)("p",null,"Example\nLet's say that the code of our job creates a PostgreSQL RDS on AWS. At the end of its execution, the job should know the connection Once created, the job should know the connection string of the PostgreSQL. The job can now create a file ",Object(i.b)("inlineCode",{parentName:"p"},"/qovery-output/qovery-output.json")," with the following structure:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-json"}),'{\n "POSTGRES_DB_HOST": {\n "sensitive": False,\n "value": "zf138d9c8-postgresql"\n },\n "POSTGRES_DB_USER": {\n "sensitive": False,\n "value": "root"\n },\n "POSTGRES_DB_PASS": {\n "sensitive": True,\n "value": "mypassword"\n },\n "POSTGRES_DB_TABLE": {\n "sensitive": False,\n "value": "MYDB"\n },\n "POSTGRES_DB_PORT": {\n "sensitive": False,\n "value": "3600"\n }\n}\n')),Object(i.b)("p",null,"This file will be processed by Qovery and the following environment variables will be created:"),Object(i.b)("p",null,"Var ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_OUTPUT_JOB__POSTGRES_DB_HOST")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},'Value: "zf138d9c8-postgresql"'),Object(i.b)("li",{parentName:"ul"},"Secret: false"),Object(i.b)("li",{parentName:"ul"},"Alias: POSTGRES_DB_HOST")),Object(i.b)("p",null,"Var ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_OUTPUT_JOB__POSTGRES_DB_USER")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},'Value: "root"'),Object(i.b)("li",{parentName:"ul"},"Secret: false"),Object(i.b)("li",{parentName:"ul"},"Alias: POSTGRES_DB_USER")),Object(i.b)("p",null,"Var ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_OUTPUT_JOB__POSTGRES_DB_PASS")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},'Value: "mypassword"'),Object(i.b)("li",{parentName:"ul"},"Secret: true"),Object(i.b)("li",{parentName:"ul"},"Alias: POSTGRES_DB_PASS")),Object(i.b)("p",null,"Var ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_OUTPUT_JOB__POSTGRES_DB_TABLE")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},'Value: "MYDB"'),Object(i.b)("li",{parentName:"ul"},"Secret: false"),Object(i.b)("li",{parentName:"ul"},"Alias: POSTGRES_DB_TABLE")),Object(i.b)("p",null,"Var ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_OUTPUT_JOB__DB_PORT")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},'Value: "3600"'),Object(i.b)("li",{parentName:"ul"},"Secret: false"),Object(i.b)("li",{parentName:"ul"},"Alias: POSTGRES_DB_PORT")),Object(i.b)("p",null,"Once the execution of the job is terminated and the environment variables are created, any application within the same environment will be able to access those environment variables and thus connect to the postgres instance."),Object(i.b)("h2",{id:"clone"},"Clone"),Object(i.b)("p",null,"You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/clone_service.png",alt:"Clone Service"})),Object(i.b)("p",null,"The target environment can be the same as the current environment or even another one in a completely different project."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Important information ")),Object(i.b)("p",null,"Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"same environment:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"))),Object(i.b)("li",{parentName:"ul"},"another environment:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"),Object(i.b)("li",{parentName:"ul"},"environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)"),Object(i.b)("li",{parentName:"ul"},"deployment pipeline: stage setup is not copied (since the target stage might not exist)"),Object(i.b)("li",{parentName:"ul"},"number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)")))),Object(i.b)("p",null,"Please check the configuration of the new service before deploying it."),Object(i.b)("h2",{id:"delete-a-job"},"Delete a job"),Object(i.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Select the job you want to delete")),Object(i.b)("li",null,Object(i.b)("p",null,"In the overview, click on the ",Object(i.b)("inlineCode",{parentName:"p"},"3 dots")," button and remove the job. Note: the same option is available on the service list as well"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-1.png",alt:"Application"}))))))}d.isMDXComponent=!0},420:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},b=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,r=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),b=u(n),d=o,m=b["".concat(r,".").concat(d)]||b[d]||p[d]||i;return n?a.a.createElement(m,l({ref:t},s,{components:n})):a.a.createElement(m,l({ref:t},s))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:o,r[1]=l;for(var s=2;s1?arguments[1]:void 0,n),c=r>2?arguments[2]:void 0,s=void 0===c?n:a(c,n);s>l;)t[l++]=e;return t}},425:function(e,t,n){var o=n(28).f,a=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in a||n(10)&&o(a,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var o=n(0),a=n.n(o),i=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var o=n(1),a=n(0),i=n.n(a),r=n(39),l=n(430),c=n(20),s=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,u=n||c,b=Object(l.a)(u),p=Object(a.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,b]),u&&b?i.a.createElement(r.b,Object(o.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,o;d&&e&&b&&(n=e,o=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:u})):i.a.createElement("a",Object(o.a)({},e,{href:u}))}},428:function(e,t,n){"use strict";var o=n(432),a=n(51);function i(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(a),i,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[i(t,e),"[",o,"]"].join(""):[i(t,e),"[",i(o,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var a=e[o];if(void 0===a)return"";if(null===a)return i(o,t);if(Array.isArray(a)){var r=[];return a.slice().forEach((function(e){void 0!==e&&r.push(n(o,e,r.length))})),r.join("&")}return i(o,t)+"="+i(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var o=n(0),a=n.n(o),i=n(427),r=n(420),l=n.n(r);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,r=e.leftIcon,c=e.rightIcon,s=e.size,u=e.target,b=e.to,p=l()("jump-to","jump-to--"+s,n),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},r&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+r})),a.a.createElement("div",{className:"jump-to--main"},o?a.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return u?a.a.createElement("a",{href:b,target:u,className:p},d):a.a.createElement(i.a,{to:b,className:p},d)}},430:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},431:function(e,t,n){"use strict";var o=n(0),a=n.n(o),i=(n(420),n(428)),r=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,c={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+r.a.stringify(c),u=Object(o.useState)(null),b=u[0],p=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 16557ade.13e4779d.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{171:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return d}));var o=n(1),a=n(9),i=(n(0),n(425)),r=n(434),l=(n(431),n(424)),c=n(429),s={last_modified_on:"2023-09-27",title:"Lifecycle Job",description:"Learn how to configure your Lifecycle job on Qovery"},u={id:"using-qovery/configuration/lifecycle-job",title:"Lifecycle Job",description:"Learn how to configure your Lifecycle job on Qovery",source:"@site/docs/using-qovery/configuration/lifecycle-job.md",permalink:"/docs/using-qovery/configuration/lifecycle-job",sidebar:"docs",previous:{title:"Cronjob",permalink:"/docs/using-qovery/configuration/cronjob"},next:{title:"Environment Variable & Secrets",permalink:"/docs/using-qovery/configuration/environment-variable"}},b=[{value:"Deploying from a Git Repository",id:"deploying-from-a-git-repository",children:[]},{value:"Deploying from a Container Registry",id:"deploying-from-a-container-registry",children:[]},{value:"Create a Job",id:"create-a-job",children:[]},{value:"Deployment Management",id:"deployment-management",children:[]},{value:"Force Run",id:"force-run",children:[]},{value:"Configuration",id:"configuration",children:[{value:"General",id:"general",children:[]},{value:"JOB Configuration",id:"job-configuration",children:[]},{value:"Resources",id:"resources",children:[]},{value:"Health Checks",id:"health-checks",children:[]}]},{value:"Environment Variable",id:"environment-variable",children:[]},{value:"Secrets",id:"secrets",children:[]},{value:"Logs",id:"logs",children:[]},{value:"Job output",id:"job-output",children:[]},{value:"Clone",id:"clone",children:[]},{value:"Delete a job",id:"delete-a-job",children:[]}],p={rightToc:b};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(c.a,{name:"documentation",mdxType:"Assumptions"},Object(i.b)("p",null,"You have created an ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment"),".")),Object(i.b)("p",null,"A ",Object(i.b)("strong",{parentName:"p"},"Lifecycle Job")," is a job that runs on your kubernetes cluster with the following characteristics:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"it is executed ONLY when the selected environment event occurs (unless its execution is forced, ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"#force-execution"}),"see the Force execution section"),")."),Object(i.b)("li",{parentName:"ul"},"any output file created at the end of the execution will be automatically injected as environment variable to any service within the same environment (",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"#job-output"}),"see the Job Output section"),").")),Object(i.b)("p",null,"Given its characteristics, lifecycle jobs are particularly useful for:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Seed your database on your preview environment: you can create a custom job that will seed a database when the preview environment is deployed"),Object(i.b)("li",{parentName:"ul"},"Create an external resources not natively managed by Qovery: you can create a custom job that will create the external resource. By writing the connection strings in an output file, those information will be injected as environment variables on any service of the environment (so that they can consume this new resource).")),Object(i.b)("p",null,"A lifecycle job can be executed on the following environment events:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Start"),': the job is executed when the environment starts. Note that a start event is generated on both the "Deploy" and "Redeploy" actions so you should take care of managing this in your code to avoid executing it twice (on the first deploy and on the re-deploy).'),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Stop"),": the job is executed when the environment stops."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Delete"),": the job is executed when the environment is deleted.")),Object(i.b)(l.a,{type:"success",mdxType:"Alert"},Object(i.b)("p",null,"Check out ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"this complete example")," on how to deploy a Terraform module with the Lifecycle Job feature")),Object(i.b)("p",null,"Qovery allows you to create and deploy jobs from two different sources: Git Repository or Container Registry"),Object(i.b)("h2",{id:"deploying-from-a-git-repository"},"Deploying from a Git Repository"),Object(i.b)("p",null,"In this configuration, Qovery will pull the code from the chosen repository, build the application and deploy it on your kubernetes cluster."),Object(i.b)("p",null,"The list of Git repositories available during the setup is strictly tied to the permissions of your git account (by default Qovery can access all your repositories). If you want to restrict the Qovery access only to a few repositories, user the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/git-repository-access/"}),"GitHub Qovery Application")," (only for Github)."),Object(i.b)("h2",{id:"deploying-from-a-container-registry"},"Deploying from a Container Registry"),Object(i.b)("p",null,"In this configuration, Qovery will pull the chosen container registry an image you have pre-built and deploy it on your kubernetes cluster."),Object(i.b)("p",null,"To improve the security and avoid deploying images from non-authorized registries, we have decided to restrict the list of Container Registry you can use during the setup process. Only an administrator with the right permissions can manage it from the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")),Object(i.b)("h2",{id:"create-a-job"},"Create a Job"),Object(i.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,'Go into the chosen environment and press the "New Service" button and then the "Create Lifecycle job" button'),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/environments/service_creation.png",alt:"Creation"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Select the following fields:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Name: give a name to your application"),Object(i.b)("li",{parentName:"ul"},"Source: Chose between Git Repository or Container Registry, depending on the source location of your application")),Object(i.b)("p",null,"If you want to deploy a cronjob from a Git Repository you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Git Repository: Select the git provider hosting your code (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Branch: Select branch that Qovery should use to deploy your code"),Object(i.b)("li",{parentName:"ul"},"Root Application Path: base folder in which the code resides in your repository"),Object(i.b)("li",{parentName:"ul"},"Build Mode: only Docker is supported")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"A Dockerfile is necessary to build and deploy your job")),Object(i.b)("p",null,"If you want to deploy a job from a Container Registry you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Registry: select the container registry storing the image of your job. Note: only pre-configured registry are available in this list, check the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," for more information."),Object(i.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this job (example: postgres)"),Object(i.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this job (example: 12)")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"The tag 'latest' is not supported, please use a specific tag.")),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Auto Deploy ")),Object(i.b)("p",null,"See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section.")),Object(i.b)("li",null,Object(i.b)("p",null,"Specify the configuration of your job:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Event: select the environment event which should trigger the execution of the job (Environment start, stop, delete)"),Object(i.b)("li",{parentName:"ul"},"Image Entrypoint: the entrypoint to be used to launch your job (not mandatory)."),Object(i.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your job (not mandatory). We expect the format to be an array. Example ",'["rails", "-h", "0.0.0.0", "-p", "8080", "string"]'),Object(i.b)("li",{parentName:"ul"},"Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure)"),Object(i.b)("li",{parentName:"ul"},"Max duration time in seconds: Maximum duration allowed for the job to run before killing it and mark it as failed"),Object(i.b)("li",{parentName:"ul"},"Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,'Entrypoint and Arguments can be customized for each event. This will allow your job to behave differently depending on the environment status (example: you might want to run a "create" command when the environment starts and a "destroy" command when the environment is deleted)'))),Object(i.b)("li",null,"Within this section, you will need to define the resources to be assigned to your job at run time.",Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"vCPU: the vCPU assigned to each instance of your application. The default is 500m (0.5 vCPU)."),Object(i.b)("li",{parentName:"ul"},"RAM: the amount of RAM assigned to each instance of your application. The default is 512MB.")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Please note that in this section you configure the CPU/RAM allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU/RAM."))),Object(i.b)("li",null,Object(i.b)("p",null,"Define any input variable required by your job to run. Any declared variable will be injected as environment variables based on the selected scope (project, environment, service)\nAny additional environment variable can be added later from the environment variable section"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/job/variables.png",alt:"Input Variables"}))),Object(i.b)("li",null,Object(i.b)("p",null,"You will find a recap of your job setup and you can now decide to:\n1. Go back to one of the previous steps and change your settings\n2. Create your job without deploying it\n3. Create and deploy your job"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/job/cronjob_recap.png",alt:"Recap"}))))),Object(i.b)("h2",{id:"deployment-management"},"Deployment Management"),Object(i.b)("p",null,"Have a look at the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/"}),"Deployment Management")," section for more information."),Object(i.b)("h2",{id:"force-run"},"Force Run"),Object(i.b)("p",null,"You can force the execution of a job independently its deployment status by:"),Object(i.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Select the job that you want to force")),Object(i.b)("li",null,Object(i.b)("p",null,"click on the ",Object(i.b)("inlineCode",{parentName:"p"},"Play")," button of the cronjob you want to force and select the ",Object(i.b)("inlineCode",{parentName:"p"},"Force Run")," option. Note: the same option is available on the service list as well")),Object(i.b)("li",null,Object(i.b)("p",null,"Select the environment event you want to force. ")),Object(i.b)("li",null,Object(i.b)("p",null,"Once you click, the job will be deployed and executed with the entrypoint and arguments associated to the selected event. You will be able to follow its execution within the application logs")))),Object(i.b)("h2",{id:"configuration"},"Configuration"),Object(i.b)("p",null,"Once created, you can access the configuration at any time via the Settings tab available on the service section"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/settings.png",alt:"Settings"})),Object(i.b)("p",null,"You can find below the description of each of the tabs available in this section"),Object(i.b)("h3",{id:"general"},"General"),Object(i.b)("p",null,"General settings section allows you to set up your application name and the source code location (git repository or image registry) ."),Object(i.b)("h4",{id:"git-repository"},"Git Repository"),Object(i.b)("p",null,"If your job is built and deployed from a git repository, within this section you can:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Modify the git provider where your code is stored (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Modify the branch that Qovery should use for deploying your code"),Object(i.b)("li",{parentName:"ul"},"Modify ",Object(i.b)("inlineCode",{parentName:"li"},"Root Application Path")," - base folder in which the application resides in your repository")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Qovery supports mono repositories. ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/advanced/monorepository/"}),"See our advanced guide for more details."))),Object(i.b)(l.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"If your repository contains private submodules using SSH protocol, you will need to add a secret beginning with GIT",Object(i.b)("em",{parentName:"p"},"SSH_KEY"),", containing a private SSH key with access rights to your sumbodules repositories."),Object(i.b)("p",null,"Secret names examples:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITHUB"),Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITLAB"),Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_MYAPP"))),Object(i.b)("h4",{id:"container-registry"},"Container Registry"),Object(i.b)("p",null,"If your application is deployed from an image registry, within this section you can modify:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Registry: select the container registry storing the image of your application. Note: only pre-configured registry are available in this list, check the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," for more information."),Object(i.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this application (example: postgres)"),Object(i.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this application (example: 12)")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"The tag 'latest' is not supported, please use a specific tag.")),Object(i.b)("h4",{id:"build-mode"},"Build Mode"),Object(i.b)("p",null,'This option is available only if you have selected "Git Repository" as source. Only Docker is supported'),Object(i.b)("p",null,"Qovery runs your application within the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://www.docker.com/resources/what-container"}),"Container technology"),". To build and run your application, you need to provide a valid ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.docker.com/engine/reference/builder"}),"Dockerfile"),"."),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-Dockerfile",metastring:'title="Valid NodeJS Dockerfile"',title:'"Valid',NodeJS:!0,'Dockerfile"':!0}),"FROM node:13-alpine\nRUN mkdir -p /usr/src/app\nWORKDIR /usr/src/app\nCOPY . .\nRUN npm install\nEXPOSE 3000\nCMD node ./bin/www\n")),Object(i.b)("p",null,"After creating a Dockerfile, specify the location of your Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"Dockefile path")," field."),Object(i.b)("p",null,"Configuration from above will make Qovery look for the Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"/timescale/Dockerfile")," path of your repository (",Object(i.b)("inlineCode",{parentName:"p"},"Root Application Path")," + ",Object(i.b)("inlineCode",{parentName:"p"},"Dockerfile Path"),")."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Auto Deploy ")),Object(i.b)("p",null,"See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section."),Object(i.b)("h3",{id:"job-configuration"},"JOB Configuration"),Object(i.b)("p",null,"You can modify here the configuration of your job:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"CRON Schedule: specify a valid CRON expression (see ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"https://crontab.guru/"}),"Crontab guru")," for help). After being deployed, the job will be executed following the defined schedule."),Object(i.b)("li",{parentName:"ul"},"Image Entrypoint: the entrypoint to be used to launch your job (not mandatory)"),Object(i.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your job (not mandatory). We expect the format to be an array. Example ",'["rails", "-h", "0.0.0.0", "-p", "8080", "string"]'),Object(i.b)("li",{parentName:"ul"},"Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure)"),Object(i.b)("li",{parentName:"ul"},"Max duration time in seconds: Maximum duration allowed for the job to run before killing it and mark it as failed"),Object(i.b)("li",{parentName:"ul"},"Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally")),Object(i.b)("h3",{id:"resources"},"Resources"),Object(i.b)("h4",{id:"cpu"},"CPU"),Object(i.b)("p",null,"To configure the number of CPUs that your job needs, adjust the setting in the ",Object(i.b)("inlineCode",{parentName:"p"},"Resources")," section."),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Default is 500m (0.5 vCPU).")),Object(i.b)("p",null,"Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU."),Object(i.b)("h4",{id:"ram"},"RAM"),Object(i.b)("p",null,"To configure the amount of RAM that your app needs, adjust the setting in ",Object(i.b)("inlineCode",{parentName:"p"},"Resources")," section."),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Default is 512MB.")),Object(i.b)("p",null,"Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU. If your application requires more RAM than requested, it will be killed by the kubernetes scheduler."),Object(i.b)("h3",{id:"health-checks"},"Health Checks"),Object(i.b)("p",null,"To know more about how to configure your Liveness and Readiness probes, have a look at ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application-health-checks/"}),"the health-checks section")),Object(i.b)("h2",{id:"environment-variable"},"Environment Variable"),Object(i.b)("p",null,"To learn how to set up environment variables in your projects and applications, navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Environment Variables")," section."),Object(i.b)("h2",{id:"secrets"},"Secrets"),Object(i.b)("p",null,"To learn how to set up secrets in your projects and applications, navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Secrets")," section."),Object(i.b)("h2",{id:"logs"},"Logs"),Object(i.b)("p",null,"To learn how to display your application logs, navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#live-logs"}),"logs section")),Object(i.b)("h2",{id:"job-output"},"Job output"),Object(i.b)("p",null,"Qovery expects the output file to be written in the following path ",Object(i.b)("inlineCode",{parentName:"p"},"/qovery-output/qovery-output.json")," (the ",Object(i.b)("inlineCode",{parentName:"p"},"output")," folder is automatically mounted by Qovery).\nThe file should follow this format:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-json"}),'{\n "varname1": {\n "sensitive": true,\n "value": "myvalue"\n },\n "varname2": {\n "sensitive": false,\n "value": "myvalue"\n }\n}\n...\n')),Object(i.b)("p",null,"At the end of the job execution, this file will be processed by Qovery and a set of environment variables will be created, one for each element in the json. The information in the json file will be mapped to an environment variables in this way:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Variable Name: ",Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_OUTPUT_JOB__")," , where ",Object(i.b)("inlineCode",{parentName:"li"},"")," is the id of the Job on Qovery side and ",Object(i.b)("inlineCode",{parentName:"li"},"")," is the name of the element in the output file."),Object(i.b)("li",{parentName:"ul"},'Variable Value: field "value"'),Object(i.b)("li",{parentName:"ul"},'Secret: field "sensitive"')),Object(i.b)("p",null,"An alias ",Object(i.b)("inlineCode",{parentName:"p"},"")," will be automatically created to simplify your setup."),Object(i.b)("p",null,"Example\nLet's say that the code of our job creates a PostgreSQL RDS on AWS. At the end of its execution, the job should know the connection Once created, the job should know the connection string of the PostgreSQL. The job can now create a file ",Object(i.b)("inlineCode",{parentName:"p"},"/qovery-output/qovery-output.json")," with the following structure:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-json"}),'{\n "POSTGRES_DB_HOST": {\n "sensitive": False,\n "value": "zf138d9c8-postgresql"\n },\n "POSTGRES_DB_USER": {\n "sensitive": False,\n "value": "root"\n },\n "POSTGRES_DB_PASS": {\n "sensitive": True,\n "value": "mypassword"\n },\n "POSTGRES_DB_TABLE": {\n "sensitive": False,\n "value": "MYDB"\n },\n "POSTGRES_DB_PORT": {\n "sensitive": False,\n "value": "3600"\n }\n}\n')),Object(i.b)("p",null,"This file will be processed by Qovery and the following environment variables will be created:"),Object(i.b)("p",null,"Var ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_OUTPUT_JOB__POSTGRES_DB_HOST")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},'Value: "zf138d9c8-postgresql"'),Object(i.b)("li",{parentName:"ul"},"Secret: false"),Object(i.b)("li",{parentName:"ul"},"Alias: POSTGRES_DB_HOST")),Object(i.b)("p",null,"Var ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_OUTPUT_JOB__POSTGRES_DB_USER")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},'Value: "root"'),Object(i.b)("li",{parentName:"ul"},"Secret: false"),Object(i.b)("li",{parentName:"ul"},"Alias: POSTGRES_DB_USER")),Object(i.b)("p",null,"Var ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_OUTPUT_JOB__POSTGRES_DB_PASS")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},'Value: "mypassword"'),Object(i.b)("li",{parentName:"ul"},"Secret: true"),Object(i.b)("li",{parentName:"ul"},"Alias: POSTGRES_DB_PASS")),Object(i.b)("p",null,"Var ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_OUTPUT_JOB__POSTGRES_DB_TABLE")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},'Value: "MYDB"'),Object(i.b)("li",{parentName:"ul"},"Secret: false"),Object(i.b)("li",{parentName:"ul"},"Alias: POSTGRES_DB_TABLE")),Object(i.b)("p",null,"Var ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_OUTPUT_JOB__DB_PORT")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},'Value: "3600"'),Object(i.b)("li",{parentName:"ul"},"Secret: false"),Object(i.b)("li",{parentName:"ul"},"Alias: POSTGRES_DB_PORT")),Object(i.b)("p",null,"Once the execution of the job is terminated and the environment variables are created, any application within the same environment will be able to access those environment variables and thus connect to the postgres instance."),Object(i.b)("h2",{id:"clone"},"Clone"),Object(i.b)("p",null,"You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/clone_service.png",alt:"Clone Service"})),Object(i.b)("p",null,"The target environment can be the same as the current environment or even another one in a completely different project."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Important information ")),Object(i.b)("p",null,"Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"same environment:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"))),Object(i.b)("li",{parentName:"ul"},"another environment:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"),Object(i.b)("li",{parentName:"ul"},"environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)"),Object(i.b)("li",{parentName:"ul"},"deployment pipeline: stage setup is not copied (since the target stage might not exist)"),Object(i.b)("li",{parentName:"ul"},"number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)")))),Object(i.b)("p",null,"Please check the configuration of the new service before deploying it."),Object(i.b)("h2",{id:"delete-a-job"},"Delete a job"),Object(i.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Select the job you want to delete")),Object(i.b)("li",null,Object(i.b)("p",null,"In the overview, click on the ",Object(i.b)("inlineCode",{parentName:"p"},"3 dots")," button and remove the job. Note: the same option is available on the service list as well"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-1.png",alt:"Application"}))))))}d.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},b=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,r=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),b=u(n),d=o,m=b["".concat(r,".").concat(d)]||b[d]||p[d]||i;return n?a.a.createElement(m,l({ref:t},s,{components:n})):a.a.createElement(m,l({ref:t},s))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:o,r[1]=l;for(var s=2;s1?arguments[1]:void 0,n),c=r>2?arguments[2]:void 0,s=void 0===c?n:a(c,n);s>l;)t[l++]=e;return t}},428:function(e,t,n){var o=n(28).f,a=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in a||n(10)&&o(a,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var o=n(0),a=n.n(o),i=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var o=n(1),a=n(0),i=n.n(a),r=n(39),l=n(432),c=n(20),s=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,u=n||c,b=Object(l.a)(u),p=Object(a.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,b]),u&&b?i.a.createElement(r.b,Object(o.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,o;d&&e&&b&&(n=e,o=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:u})):i.a.createElement("a",Object(o.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var o=n(0),a=n.n(o),i=n(430),r=n(423),l=n.n(r);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,r=e.leftIcon,c=e.rightIcon,s=e.size,u=e.target,b=e.to,p=l()("jump-to","jump-to--"+s,n),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},r&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+r})),a.a.createElement("div",{className:"jump-to--main"},o?a.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return u?a.a.createElement("a",{href:b,target:u,className:p},d):a.a.createElement(i.a,{to:b,className:p},d)}},432:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},433:function(e,t,n){"use strict";var o=n(435),a=n(51);function i(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(a),i,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[i(t,e),"[",o,"]"].join(""):[i(t,e),"[",i(o,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var a=e[o];if(void 0===a)return"";if(null===a)return i(o,t);if(Array.isArray(a)){var r=[];return a.slice().forEach((function(e){void 0!==e&&r.push(n(o,e,r.length))})),r.join("&")}return i(o,t)+"="+i(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var o=n(0),a=n.n(o),i=(n(423),n(433)),r=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,c={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+r.a.stringify(c),u=Object(o.useState)(null),b=u[0],p=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/16976906.455056be.js.LICENSE.txt b/16557ade.13e4779d.js.LICENSE.txt similarity index 100% rename from 16976906.455056be.js.LICENSE.txt rename to 16557ade.13e4779d.js.LICENSE.txt diff --git a/16976906.455056be.js b/16976906.4279ae39.js similarity index 92% rename from 16976906.455056be.js rename to 16976906.4279ae39.js index d03781d135..b93c639148 100644 --- a/16976906.455056be.js +++ b/16976906.4279ae39.js @@ -1,2 +1,2 @@ -/*! For license information please see 16976906.455056be.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{171:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),o=(n(0),n(422)),i=(n(431),n(426),n(421),{last_modified_on:"2023-08-31",$schema:"/.meta/.schemas/guides.json",title:"Preview Environments",description:"Learn how to use and leverage Preview Environments with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),c={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Preview Environments",description:"Learn how to use and leverage Preview Environments with Qovery",permalink:"/guides/advanced/use-preview-environments",readingTime:"2 min read",source:"@site/guides/advanced/use-preview-environments.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Preview Environments",truncated:!1,prevItem:{title:"Mono repository",permalink:"/guides/advanced/monorepository"},nextItem:{title:"Production",permalink:"/guides/advanced/production"}},u=[{value:"Recommendations",id:"recommendations",children:[]},{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:u};function l(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Use Preview Environment to get early feedback on your application changes by creating a dedicated environment for each of your pull requests.\nYour production environment runs 24/7, where your other environments may not need to run all day long.\nE.g. you may need to run Environments to get early feedback on your application changes before the changes are merged into production. This is what we call ",Object(o.b)("strong",{parentName:"p"},"Preview Environment"),"."),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"}," Sometimes ",Object(o.b)("strong",{parentName:"p"},"Preview Environment")," is also known as ",Object(o.b)("strong",{parentName:"p"},"Ephemeral Environment"),", ",Object(o.b)("strong",{parentName:"p"},"Temporary Environment"),", ",Object(o.b)("strong",{parentName:"p"},"Development Environment"),", ",Object(o.b)("strong",{parentName:"p"},"Review App"),".")),Object(o.b)("h2",{id:"recommendations"},"Recommendations"),Object(o.b)("p",null,"If you are using Qovery to run your Production, we recommend using Preview Environments on a separate ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/"}),"cluster"),". This will ensure that your Production is not impacted by the Preview Environments and vice versa."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to use and take advantage of Qovery Preview Environments:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners/"}),"Getting Started with Preview Environment")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners/"}),"Learn how to get started with Qovery Preview Environments")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/customizing-preview-url-with-qovery-cli/"}),"Customize preview URL")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/customizing-preview-url-with-qovery-cli/"}),"Learn how to customize your Preview URL with the Qovery CLI")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/deployment-rule/"}),"Automatically stop unused Preview Environments")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/deployment-rule/"}),"Learn how to automatically teardown your Preview Environments on a specific schedule")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/build-e2e-testing-ephemeral-environments/"}),"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/build-e2e-testing-ephemeral-environments/"}),"Step-by-step guide to build e2e testing ephemeral environments with GitHub Actions and Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=preview%20environment"}),'Forum "Preview Environment"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=preview%20environment"}),'List "Preview Environments" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}l.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},b=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},p=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),b=l(n),p=r,d=b["".concat(i,".").concat(p)]||b[p]||m[p]||o;return n?a.a.createElement(d,c({ref:t},s,{components:n})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=p;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:a(u,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),b=l[0],m=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return m("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 16976906.4279ae39.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{172:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),o=(n(0),n(425)),i=(n(434),n(429),n(424),{last_modified_on:"2023-08-31",$schema:"/.meta/.schemas/guides.json",title:"Preview Environments",description:"Learn how to use and leverage Preview Environments with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),c={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Preview Environments",description:"Learn how to use and leverage Preview Environments with Qovery",permalink:"/guides/advanced/use-preview-environments",readingTime:"2 min read",source:"@site/guides/advanced/use-preview-environments.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Preview Environments",truncated:!1,prevItem:{title:"Mono repository",permalink:"/guides/advanced/monorepository"},nextItem:{title:"Production",permalink:"/guides/advanced/production"}},u=[{value:"Recommendations",id:"recommendations",children:[]},{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:u};function l(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Use Preview Environment to get early feedback on your application changes by creating a dedicated environment for each of your pull requests.\nYour production environment runs 24/7, where your other environments may not need to run all day long.\nE.g. you may need to run Environments to get early feedback on your application changes before the changes are merged into production. This is what we call ",Object(o.b)("strong",{parentName:"p"},"Preview Environment"),"."),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"}," Sometimes ",Object(o.b)("strong",{parentName:"p"},"Preview Environment")," is also known as ",Object(o.b)("strong",{parentName:"p"},"Ephemeral Environment"),", ",Object(o.b)("strong",{parentName:"p"},"Temporary Environment"),", ",Object(o.b)("strong",{parentName:"p"},"Development Environment"),", ",Object(o.b)("strong",{parentName:"p"},"Review App"),".")),Object(o.b)("h2",{id:"recommendations"},"Recommendations"),Object(o.b)("p",null,"If you are using Qovery to run your Production, we recommend using Preview Environments on a separate ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/"}),"cluster"),". This will ensure that your Production is not impacted by the Preview Environments and vice versa."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to use and take advantage of Qovery Preview Environments:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners/"}),"Getting Started with Preview Environment")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners/"}),"Learn how to get started with Qovery Preview Environments")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/customizing-preview-url-with-qovery-cli/"}),"Customize preview URL")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/customizing-preview-url-with-qovery-cli/"}),"Learn how to customize your Preview URL with the Qovery CLI")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/deployment-rule/"}),"Automatically stop unused Preview Environments")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/deployment-rule/"}),"Learn how to automatically teardown your Preview Environments on a specific schedule")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/build-e2e-testing-ephemeral-environments/"}),"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/build-e2e-testing-ephemeral-environments/"}),"Step-by-step guide to build e2e testing ephemeral environments with GitHub Actions and Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=preview%20environment"}),'Forum "Preview Environment"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=preview%20environment"}),'List "Preview Environments" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}l.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},b=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},p=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),b=l(n),p=r,d=b["".concat(i,".").concat(p)]||b[p]||m[p]||o;return n?a.a.createElement(d,c({ref:t},s,{components:n})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=p;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:a(u,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),b=l[0],m=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return m("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/16c36934.eef330ff.js.LICENSE.txt b/16976906.4279ae39.js.LICENSE.txt similarity index 100% rename from 16c36934.eef330ff.js.LICENSE.txt rename to 16976906.4279ae39.js.LICENSE.txt diff --git a/16c36934.eef330ff.js b/16c36934.73d907be.js similarity index 94% rename from 16c36934.eef330ff.js rename to 16c36934.73d907be.js index 1b35988c62..e662b4c28b 100644 --- a/16c36934.eef330ff.js +++ b/16c36934.73d907be.js @@ -1,2 +1,2 @@ -/*! For license information please see 16c36934.eef330ff.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{172:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return p})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return b}));var o=n(1),r=n(9),i=(n(0),n(422)),a=n(421),c=n(431),l={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Mono repository",description:"How to deploy applications using Monorepository with Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: guide","technology: qovery"]},p={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Mono repository",description:"How to deploy applications using Monorepository with Qovery",permalink:"/guides/advanced/monorepository",readingTime:"3 min read",source:"@site/guides/advanced/monorepository.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Mono repository",truncated:!1,prevItem:{title:"Monitoring",permalink:"/guides/advanced/monitoring"},nextItem:{title:"Preview Environments",permalink:"/guides/advanced/use-preview-environments"}},s=[{value:"Deploying multiple applications using one repository",id:"deploying-multiple-applications-using-one-repository",children:[{value:"First application",id:"first-application",children:[]},{value:"Second application",id:"second-application",children:[]}]},{value:"Deploying application with multiple configurations using one repository",id:"deploying-application-with-multiple-configurations-using-one-repository",children:[{value:"First application",id:"first-application-1",children:[]},{value:"Second application",id:"second-application-1",children:[]}]},{value:"Q&A",id:"qa",children:[]}],u={rightToc:s};function b(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(a.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"This guide is a bit outdated. We are working on a new version of it. Stay tuned!")),Object(i.b)("p",null,"Qovery provides a very simple way of working with ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://en.wikipedia.org/wiki/Monorepo"}),"monorepositories"),".\nYou can deploy multiple applications using the same git repository or deploy the same application in many different modes/configurations."),Object(i.b)("h2",{id:"deploying-multiple-applications-using-one-repository"},"Deploying multiple applications using one repository"),Object(i.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/getting-started/deploy-your-first-application/"}),"Create new applications")," or navigate to existing ones")),Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to application settings"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-6.png",alt:"Monorepository"}))),Object(i.b)("li",null,Object(i.b)("p",null,"To deploy multiple apps using one repository, set up the app to target your monorepo. Additionally, you need to set up the folder in which your application resides."),Object(i.b)("h3",{id:"first-application"},"First application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-1.png",alt:"Monorepository"})),Object(i.b)("h3",{id:"second-application"},"Second application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-2.png",alt:"Monorepository"})),Object(i.b)("p",null,"As you see in the examples above, we used one repository (",Object(i.b)("inlineCode",{parentName:"p"},"poc-factory/tweetifier"),") in two applications:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"timescale"),Object(i.b)("li",{parentName:"ul"},"core")),Object(i.b)("p",null,"All we need to do to deploy multiple applications using one repository is:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Select the application name"),Object(i.b)("li",{parentName:"ul"},"Select our repository"),Object(i.b)("li",{parentName:"ul"},"Select the application root folder")),Object(i.b)("p",null,"That's it. Using monorepositories with Qovery is that simple."),Object(i.b)("p",null,"Those applications may be a part of the same project or different projects; it's all up to you and your configuration."),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},"Each commit to the repository will make sure all applications affected will be redeployed and up-to-date.")))),Object(i.b)("h2",{id:"deploying-application-with-multiple-configurations-using-one-repository"},"Deploying application with multiple configurations using one repository"),Object(i.b)("p",null,"A special case of monorepository is a situation when one repository is used to deploy multiple applications with the same source code but different configurations or modes. Application behaviour depends on provided config, like environment variables and secrets."),Object(i.b)("p",null,"Qovery supports this case well. The steps do not differ much from the steps from the previous example:"),Object(i.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/getting-started/deploy-your-first-application/"}),"Create new applications")," or navigate to existing ones")),Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to application settings"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-6.png",alt:"Monorepository"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Configure application repositories:"),Object(i.b)("h3",{id:"first-application-1"},"First application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-3.png",alt:"Monorepository"})),Object(i.b)("h3",{id:"second-application-1"},"Second application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-4.png",alt:"Monorepository"}))),Object(i.b)("p",null,"As you see in the examples above, we used one repository (",Object(i.b)("inlineCode",{parentName:"p"},"poc-factory/tweetifier"),") in two applications:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"app-1"),Object(i.b)("li",{parentName:"ul"},"app-2")),Object(i.b)("br",null),Object(i.b)("p",null,"Those applications use the same application root path - ",Object(i.b)("inlineCode",{parentName:"p"},"/"),", so they can be build using the same source code. To adjust the behavior of applications to meet your needs, use ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"environment variables or secrets"),".\nIt allows you to run multiple applications using the same source code in different modes."),Object(i.b)("p",null,"You can set up secret or env variables in your application ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variables")," section:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-5.png",alt:"Monorepository"})))),Object(i.b)("h2",{id:"qa"},"Q&A"),Object(i.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}b.isMDXComponent=!0},420:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=r.a.createContext({}),s=function(e){var t=r.a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=s(e.components);return r.a.createElement(p.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(n),d=o,m=u["".concat(a,".").concat(d)]||u[d]||b[d]||i;return n?r.a.createElement(m,c({ref:t},p,{components:n})):r.a.createElement(m,c({ref:t},p))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,a[1]=c;for(var p=2;p1?arguments[1]:void 0,n),l=a>2?arguments[2]:void 0,p=void 0===l?n:r(l,n);p>c;)t[c++]=e;return t}},428:function(e,t,n){"use strict";var o=n(432),r=n(51);function i(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(r),i,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[i(t,e),"[",o,"]"].join(""):[i(t,e),"[",i(o,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return i(o,t);if(Array.isArray(r)){var a=[];return r.slice().forEach((function(e){void 0!==e&&a.push(n(o,e,a.length))})),a.join("&")}return i(o,t)+"="+i(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(420),n(428)),a=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},p="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(l),s=Object(o.useState)(null),u=s[0],b=s[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:p,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 16c36934.73d907be.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{173:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return p})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return b}));var o=n(1),r=n(9),i=(n(0),n(425)),a=n(424),c=n(434),l={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Mono repository",description:"How to deploy applications using Monorepository with Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: guide","technology: qovery"]},p={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Mono repository",description:"How to deploy applications using Monorepository with Qovery",permalink:"/guides/advanced/monorepository",readingTime:"3 min read",source:"@site/guides/advanced/monorepository.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Mono repository",truncated:!1,prevItem:{title:"Monitoring",permalink:"/guides/advanced/monitoring"},nextItem:{title:"Preview Environments",permalink:"/guides/advanced/use-preview-environments"}},s=[{value:"Deploying multiple applications using one repository",id:"deploying-multiple-applications-using-one-repository",children:[{value:"First application",id:"first-application",children:[]},{value:"Second application",id:"second-application",children:[]}]},{value:"Deploying application with multiple configurations using one repository",id:"deploying-application-with-multiple-configurations-using-one-repository",children:[{value:"First application",id:"first-application-1",children:[]},{value:"Second application",id:"second-application-1",children:[]}]},{value:"Q&A",id:"qa",children:[]}],u={rightToc:s};function b(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(a.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"This guide is a bit outdated. We are working on a new version of it. Stay tuned!")),Object(i.b)("p",null,"Qovery provides a very simple way of working with ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://en.wikipedia.org/wiki/Monorepo"}),"monorepositories"),".\nYou can deploy multiple applications using the same git repository or deploy the same application in many different modes/configurations."),Object(i.b)("h2",{id:"deploying-multiple-applications-using-one-repository"},"Deploying multiple applications using one repository"),Object(i.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/getting-started/deploy-your-first-application/"}),"Create new applications")," or navigate to existing ones")),Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to application settings"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-6.png",alt:"Monorepository"}))),Object(i.b)("li",null,Object(i.b)("p",null,"To deploy multiple apps using one repository, set up the app to target your monorepo. Additionally, you need to set up the folder in which your application resides."),Object(i.b)("h3",{id:"first-application"},"First application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-1.png",alt:"Monorepository"})),Object(i.b)("h3",{id:"second-application"},"Second application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-2.png",alt:"Monorepository"})),Object(i.b)("p",null,"As you see in the examples above, we used one repository (",Object(i.b)("inlineCode",{parentName:"p"},"poc-factory/tweetifier"),") in two applications:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"timescale"),Object(i.b)("li",{parentName:"ul"},"core")),Object(i.b)("p",null,"All we need to do to deploy multiple applications using one repository is:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Select the application name"),Object(i.b)("li",{parentName:"ul"},"Select our repository"),Object(i.b)("li",{parentName:"ul"},"Select the application root folder")),Object(i.b)("p",null,"That's it. Using monorepositories with Qovery is that simple."),Object(i.b)("p",null,"Those applications may be a part of the same project or different projects; it's all up to you and your configuration."),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},"Each commit to the repository will make sure all applications affected will be redeployed and up-to-date.")))),Object(i.b)("h2",{id:"deploying-application-with-multiple-configurations-using-one-repository"},"Deploying application with multiple configurations using one repository"),Object(i.b)("p",null,"A special case of monorepository is a situation when one repository is used to deploy multiple applications with the same source code but different configurations or modes. Application behaviour depends on provided config, like environment variables and secrets."),Object(i.b)("p",null,"Qovery supports this case well. The steps do not differ much from the steps from the previous example:"),Object(i.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/getting-started/deploy-your-first-application/"}),"Create new applications")," or navigate to existing ones")),Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to application settings"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-6.png",alt:"Monorepository"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Configure application repositories:"),Object(i.b)("h3",{id:"first-application-1"},"First application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-3.png",alt:"Monorepository"})),Object(i.b)("h3",{id:"second-application-1"},"Second application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-4.png",alt:"Monorepository"}))),Object(i.b)("p",null,"As you see in the examples above, we used one repository (",Object(i.b)("inlineCode",{parentName:"p"},"poc-factory/tweetifier"),") in two applications:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"app-1"),Object(i.b)("li",{parentName:"ul"},"app-2")),Object(i.b)("br",null),Object(i.b)("p",null,"Those applications use the same application root path - ",Object(i.b)("inlineCode",{parentName:"p"},"/"),", so they can be build using the same source code. To adjust the behavior of applications to meet your needs, use ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"environment variables or secrets"),".\nIt allows you to run multiple applications using the same source code in different modes."),Object(i.b)("p",null,"You can set up secret or env variables in your application ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variables")," section:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-5.png",alt:"Monorepository"})))),Object(i.b)("h2",{id:"qa"},"Q&A"),Object(i.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}b.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=r.a.createContext({}),s=function(e){var t=r.a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=s(e.components);return r.a.createElement(p.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(n),d=o,m=u["".concat(a,".").concat(d)]||u[d]||b[d]||i;return n?r.a.createElement(m,c({ref:t},p,{components:n})):r.a.createElement(m,c({ref:t},p))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,a[1]=c;for(var p=2;p1?arguments[1]:void 0,n),l=a>2?arguments[2]:void 0,p=void 0===l?n:r(l,n);p>c;)t[c++]=e;return t}},433:function(e,t,n){"use strict";var o=n(435),r=n(51);function i(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(r),i,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[i(t,e),"[",o,"]"].join(""):[i(t,e),"[",i(o,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return i(o,t);if(Array.isArray(r)){var a=[];return r.slice().forEach((function(e){void 0!==e&&a.push(n(o,e,a.length))})),a.join("&")}return i(o,t)+"="+i(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(423),n(433)),a=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},p="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(l),s=Object(o.useState)(null),u=s[0],b=s[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:p,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/1772e35f.b5c41084.js.LICENSE.txt b/16c36934.73d907be.js.LICENSE.txt similarity index 100% rename from 1772e35f.b5c41084.js.LICENSE.txt rename to 16c36934.73d907be.js.LICENSE.txt diff --git a/1772e35f.b5c41084.js b/1772e35f.1905be40.js similarity index 91% rename from 1772e35f.b5c41084.js rename to 1772e35f.1905be40.js index 2f4f20d1c0..5d95079bad 100644 --- a/1772e35f.b5c41084.js +++ b/1772e35f.1905be40.js @@ -1,2 +1,2 @@ -/*! For license information please see 1772e35f.b5c41084.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{173:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),i=(n(0),n(422)),a=n(429),c={last_modified_on:"2023-05-20",title:"Continuous Integration",description:"Learn how to configure and plug in Build Platforms",sidebar_label:"hidden",hide_pagination:!0},u={id:"using-qovery/integration/continuous-integration",title:"Continuous Integration",description:"Learn how to configure and plug in Build Platforms",source:"@site/docs/using-qovery/integration/continuous-integration.md",permalink:"/docs/using-qovery/integration/continuous-integration",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Terraform",permalink:"/docs/using-qovery/integration/terraform"},next:{title:"GitHub Actions",permalink:"/docs/using-qovery/integration/continuous-integration/github-actions"}},s=[{value:"FAQ",id:"faq",children:[{value:"I don't find my Continuous Integration platform, what should I do?",id:"i-dont-find-my-continuous-integration-platform-what-should-i-do",children:[]},{value:"Do you need help?",id:"do-you-need-help",children:[]}]}],l={rightToc:s};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Select the CI/CD system that you use today:"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/continuous-integration/gitlab-ci",mdxType:"Jump"},"Gitlab CI"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/continuous-integration/circle-ci",mdxType:"Jump"},"Circle CI"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/continuous-integration/github-actions",mdxType:"Jump"},"Github Actions"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/continuous-integration/jenkins",mdxType:"Jump"},"Jenkins"),Object(i.b)("h2",{id:"faq"},"FAQ"),Object(i.b)("h3",{id:"i-dont-find-my-continuous-integration-platform-what-should-i-do"},"I don't find my Continuous Integration platform, what should I do?"),Object(i.b)("p",null,"Your CI platform is probably going to be officially supported in the near future. In the meantime, you can use our ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI")," and make the integration yourself (it is super easy)."),Object(i.b)("h3",{id:"do-you-need-help"},"Do you need help?"),Object(i.b)("p",null,"Feel free to open a thread on our ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community Forum"),". We will be happy to help you."))}p.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,a=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(n),f=r,m=p["".concat(a,".").concat(f)]||p[f]||d[f]||i;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=f;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,a[1]=c;for(var s=2;s0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:l})):i.a.createElement("a",Object(r.a)({},e,{href:l}))}},429:function(e,t,n){"use strict";var r=n(0),o=n.n(r),i=n(427),a=n(420),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,a=e.leftIcon,u=e.rightIcon,s=e.size,l=e.target,p=e.to,d=c()("jump-to","jump-to--"+s,n),f=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},a&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+a})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return l?o.a.createElement("a",{href:p,target:l,className:d},f):o.a.createElement(i.a,{to:p,className:d},f)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file +/*! For license information please see 1772e35f.1905be40.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{174:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),i=(n(0),n(425)),a=n(431),c={last_modified_on:"2023-05-20",title:"Continuous Integration",description:"Learn how to configure and plug in Build Platforms",sidebar_label:"hidden",hide_pagination:!0},u={id:"using-qovery/integration/continuous-integration",title:"Continuous Integration",description:"Learn how to configure and plug in Build Platforms",source:"@site/docs/using-qovery/integration/continuous-integration.md",permalink:"/docs/using-qovery/integration/continuous-integration",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Terraform",permalink:"/docs/using-qovery/integration/terraform"},next:{title:"GitHub Actions",permalink:"/docs/using-qovery/integration/continuous-integration/github-actions"}},s=[{value:"FAQ",id:"faq",children:[{value:"I don't find my Continuous Integration platform, what should I do?",id:"i-dont-find-my-continuous-integration-platform-what-should-i-do",children:[]},{value:"Do you need help?",id:"do-you-need-help",children:[]}]}],l={rightToc:s};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Select the CI/CD system that you use today:"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/continuous-integration/gitlab-ci",mdxType:"Jump"},"Gitlab CI"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/continuous-integration/circle-ci",mdxType:"Jump"},"Circle CI"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/continuous-integration/github-actions",mdxType:"Jump"},"Github Actions"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/continuous-integration/jenkins",mdxType:"Jump"},"Jenkins"),Object(i.b)("h2",{id:"faq"},"FAQ"),Object(i.b)("h3",{id:"i-dont-find-my-continuous-integration-platform-what-should-i-do"},"I don't find my Continuous Integration platform, what should I do?"),Object(i.b)("p",null,"Your CI platform is probably going to be officially supported in the near future. In the meantime, you can use our ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI")," and make the integration yourself (it is super easy)."),Object(i.b)("h3",{id:"do-you-need-help"},"Do you need help?"),Object(i.b)("p",null,"Feel free to open a thread on our ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community Forum"),". We will be happy to help you."))}p.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,a=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(n),f=r,m=p["".concat(a,".").concat(f)]||p[f]||d[f]||i;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=f;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,a[1]=c;for(var s=2;s0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:l})):i.a.createElement("a",Object(r.a)({},e,{href:l}))}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),i=n(430),a=n(423),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,a=e.leftIcon,u=e.rightIcon,s=e.size,l=e.target,p=e.to,d=c()("jump-to","jump-to--"+s,n),f=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},a&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+a})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return l?o.a.createElement("a",{href:p,target:l,className:d},f):o.a.createElement(i.a,{to:p,className:d},f)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/18415bef.da7f717c.js.LICENSE.txt b/1772e35f.1905be40.js.LICENSE.txt similarity index 100% rename from 18415bef.da7f717c.js.LICENSE.txt rename to 1772e35f.1905be40.js.LICENSE.txt diff --git a/17896441.b26c0425.js b/17896441.5deb0378.js similarity index 93% rename from 17896441.b26c0425.js rename to 17896441.5deb0378.js index a5b5386075..36e9d57e31 100644 --- a/17896441.b26c0425.js +++ b/17896441.5deb0378.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{174:function(e,t,a){"use strict";a.r(t);a(443),a(444),a(29),a(22),a(21),a(77);var n=a(0),l=a.n(n),s=a(440),r=a(427),c=a(524),i=a(448),o=a.n(i),m=a(420),d=a.n(m),p=a(175),u=a.n(p),E=a(435),g=a(433),v=a(525);function h(e){var t=e.headings,a=e.isChild;if(Object(v.a)("contents__link","contents__link--active",100),!t.length)return null;var n=o.a.uniqBy(t,(function(e){return e.value}));return l.a.createElement("ul",{className:a?"":"contents"},n.map((function(e){var t=e.value.replace("<","<").replace(">",">");return l.a.createElement("li",{key:e.id},l.a.createElement("a",{href:"#"+e.id,className:"contents__link",dangerouslySetInnerHTML:{__html:t}}),l.a.createElement(h,{isChild:!0,headings:e.children}))})))}function _(e){var t=e.values,a=Object(g.a)().siteConfig,n=(void 0===a?{}:a).customFields.metadata.event_types,s=[];return n.forEach((function(e){t.includes(e)?s.push(l.a.createElement("span",{key:e,className:"text--primary"},o.a.capitalize(e))):s.push(l.a.createElement("del",{key:e,className:"text--warning"},o.a.capitalize(e))),s.push(l.a.createElement("span",{key:e+"-comma"},", "))})),s.pop(),s}function f(e){var t=e.operatingSystems,a=e.unsupportedOperatingSystems,n=[];return(t||[]).forEach((function(e){n.push(l.a.createElement("span",{key:e,className:"text--primary"},e)),n.push(l.a.createElement("span",{key:e+"-comma"},", "))})),(a||[]).forEach((function(e){n.push(l.a.createElement("del",{key:e,className:"text--warning"},e)),n.push(l.a.createElement("span",{key:e+"-comma"},", "))})),n.pop(),n}function N(e){var t=e.deliveryGuarantee,a=e.eventTypes,n=e.operatingSystems,s=e.status,c=e.unsupportedOperatingSystems;return s||t||n||c?l.a.createElement("div",{className:"section"},l.a.createElement("div",{className:"title"},"Support"),"beta"==s&&l.a.createElement("div",null,l.a.createElement(r.a,{to:"/docs/getting-started/whats-next/#beta",className:"text--warning",title:"This component is in beta and is not recommended for production environments. Click to learn more."},l.a.createElement("i",{className:"feather icon-alert-triangle"})," Beta Status")),"prod-ready"==s&&l.a.createElement("div",null,l.a.createElement(r.a,{to:"/docs/getting-started/whats-next/#prod-ready",className:"text--primary",title:"This component has passed reliability standards that make it production ready. Click to learn more."},l.a.createElement("i",{className:"feather icon-award"})," Prod-Ready Status")),"best_effort"==t&&l.a.createElement("div",null,l.a.createElement(r.a,{to:"/docs/getting-started/whats-next/#best-effort",className:"text--warning",title:"This component makes a best-effort delivery guarantee, and in rare cases can lose data. Click to learn more."},l.a.createElement("i",{className:"feather icon-shield-off"})," Best-Effort Delivery")),"at_least_once"==t&&l.a.createElement("div",null,l.a.createElement(r.a,{to:"/docs/getting-started/whats-next/#at-least-once",className:"text--primary",title:"This component offers an at-least-once delivery guarantee. Click to learn more."},l.a.createElement("i",{className:"feather icon-shield"})," At-Least-Once")),a&&l.a.createElement("div",null,l.a.createElement(r.a,{to:"/docs/getting-started/data-model/",title:"This component works on the these event types."},l.a.createElement("i",{className:"feather icon-database"})," ",l.a.createElement(_,{values:a}))),n&&c&&l.a.createElement("div",null,l.a.createElement(r.a,{to:"/docs/setup/installation/operating-systems/",title:"This component works on the "+n.join(", ")+" operating systems."},l.a.createElement("i",{className:"feather icon-cpu"})," ",l.a.createElement(f,{operatingSystems:n,unsupportedOperatingSystems:c})))):null}t.default=function(e){var t=Object(g.a)().siteConfig,a=void 0===t?{}:t,n=a.title,i=a.url,o=e.content,m=o.metadata,p=m.description,v=m.editUrl,_=m.image,f=m.keywords,y=m.lastUpdatedAt,k=m.lastUpdatedBy,b=m.permalink,w=m.title,x=m.version,S=o.frontMatter,C=(S.component_title,S.delivery_guarantee),T=S.event_types,O=S.function_category,j=(S.hide_title,S.hide_table_of_contents,S.issues_url),B=S.operating_systems,D=S.posts_path,I=S.source_url,L=S.status,V=S.unsupported_operating_systems,A=i+Object(E.a)(_);return l.a.createElement("div",null,l.a.createElement(s.a,null,w&&l.a.createElement("title",null,w," | Docs | ",n),p&&l.a.createElement("meta",{name:"description",content:p}),p&&l.a.createElement("meta",{property:"og:description",content:p}),f&&f.length&&l.a.createElement("meta",{name:"keywords",content:f.join(",")}),_&&l.a.createElement("meta",{property:"og:image",content:A}),_&&l.a.createElement("meta",{property:"twitter:image",content:A}),_&&l.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+w}),b&&l.a.createElement("meta",{property:"og:url",content:i+b})),l.a.createElement("div",{className:u.a.container},l.a.createElement("div",{className:u.a.leftCol},l.a.createElement("div",{className:"docItemContainer_"},l.a.createElement("article",null,x&&l.a.createElement("span",{style:{verticalAlign:"top"},className:"badge badge--info"},"Version: ",x),!m.hide_title&&l.a.createElement("header",null,l.a.createElement("div",{className:"badges"},O&&l.a.createElement(r.a,{to:"/components?functions[]="+O,className:"badge badge--primary"},O)),l.a.createElement("h1",{className:u.a.docTitle},m.title)),l.a.createElement("div",{className:"markdown"},l.a.createElement(o,null)))),!m.hide_pagination&&(m.next||m.previous)&&l.a.createElement("div",{className:u.a.paginator},l.a.createElement(c.a,{next:m.next,previous:m.previous}))),o.rightToc&&l.a.createElement("div",{className:u.a.rightCol},l.a.createElement("div",{className:d()("table-of-contents",u.a.tableOfContents)},l.a.createElement(N,{deliveryGuarantee:C,eventTypes:T,operatingSystems:B,status:L,unsupportedOperatingSystems:V}),o.rightToc.length>0&&l.a.createElement("div",{className:"section"},l.a.createElement("div",{className:"title"},"Contents"),l.a.createElement(h,{headings:o.rightToc})),l.a.createElement("div",{className:"section"},l.a.createElement("div",{className:"title"},"Resources"),l.a.createElement("ul",{className:"contents"},v&&l.a.createElement("li",null,l.a.createElement("a",{href:v,className:"contents__link",target:"_blank"},l.a.createElement("i",{className:"feather icon-edit-1"})," Edit this page")),D&&l.a.createElement("li",null,l.a.createElement(r.a,{to:D,className:"contents__link"},l.a.createElement("i",{className:"feather icon-book-open"})," View Blog Posts")),j&&l.a.createElement("li",null,l.a.createElement("a",{href:j,className:"contents__link",target:"_blank"},l.a.createElement("i",{className:"feather icon-message-circle"})," View Issues")),I&&l.a.createElement("li",null,l.a.createElement("a",{href:I,className:"contents__link",target:"_blank"},l.a.createElement("i",{className:"feather icon-github"})," View Source")))),(y||k)&&l.a.createElement("div",{className:"section"},"Last updated"," ",y&&l.a.createElement(l.a.Fragment,null,"on"," ",l.a.createElement("strong",null,new Date(1e3*y).toLocaleDateString()),k&&" "),k&&l.a.createElement(l.a.Fragment,null,"by ",l.a.createElement("strong",null,k)))))))}},524:function(e,t,a){"use strict";var n=a(0),l=a.n(n),s=a(427),r=a(420),c=a.n(r);a(147);t.a=function(e){var t=e.className,a=e.previous,n=e.next;return l.a.createElement("nav",{className:c()("pagination-nav",t)},l.a.createElement("div",{className:"pagination-nav__item"},a&&l.a.createElement(s.a,{className:"pagination-nav__link",to:a.permalink},l.a.createElement("h5",{className:"pagination-nav__link--sublabel"},"Previous"),l.a.createElement("h4",{className:"pagination-nav__link--label"},"\xab ",a.title))),l.a.createElement("div",{className:"pagination-nav__item pagination-nav__item--next"},n&&l.a.createElement(s.a,{className:"pagination-nav__link",to:n.permalink},l.a.createElement("h5",{className:"pagination-nav__link--sublabel"},"Next"),l.a.createElement("h4",{className:"pagination-nav__link--label"},n.title," \xbb"))))}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{175:function(e,t,a){"use strict";a.r(t);a(446),a(447),a(29),a(22),a(21),a(77);var n=a(0),l=a.n(n),s=a(443),r=a(430),c=a(527),i=a(451),o=a.n(i),m=a(423),d=a.n(m),p=a(176),u=a.n(p),E=a(438),g=a(436),v=a(528);function h(e){var t=e.headings,a=e.isChild;if(Object(v.a)("contents__link","contents__link--active",100),!t.length)return null;var n=o.a.uniqBy(t,(function(e){return e.value}));return l.a.createElement("ul",{className:a?"":"contents"},n.map((function(e){var t=e.value.replace("<","<").replace(">",">");return l.a.createElement("li",{key:e.id},l.a.createElement("a",{href:"#"+e.id,className:"contents__link",dangerouslySetInnerHTML:{__html:t}}),l.a.createElement(h,{isChild:!0,headings:e.children}))})))}function _(e){var t=e.values,a=Object(g.a)().siteConfig,n=(void 0===a?{}:a).customFields.metadata.event_types,s=[];return n.forEach((function(e){t.includes(e)?s.push(l.a.createElement("span",{key:e,className:"text--primary"},o.a.capitalize(e))):s.push(l.a.createElement("del",{key:e,className:"text--warning"},o.a.capitalize(e))),s.push(l.a.createElement("span",{key:e+"-comma"},", "))})),s.pop(),s}function f(e){var t=e.operatingSystems,a=e.unsupportedOperatingSystems,n=[];return(t||[]).forEach((function(e){n.push(l.a.createElement("span",{key:e,className:"text--primary"},e)),n.push(l.a.createElement("span",{key:e+"-comma"},", "))})),(a||[]).forEach((function(e){n.push(l.a.createElement("del",{key:e,className:"text--warning"},e)),n.push(l.a.createElement("span",{key:e+"-comma"},", "))})),n.pop(),n}function N(e){var t=e.deliveryGuarantee,a=e.eventTypes,n=e.operatingSystems,s=e.status,c=e.unsupportedOperatingSystems;return s||t||n||c?l.a.createElement("div",{className:"section"},l.a.createElement("div",{className:"title"},"Support"),"beta"==s&&l.a.createElement("div",null,l.a.createElement(r.a,{to:"/docs/getting-started/whats-next/#beta",className:"text--warning",title:"This component is in beta and is not recommended for production environments. Click to learn more."},l.a.createElement("i",{className:"feather icon-alert-triangle"})," Beta Status")),"prod-ready"==s&&l.a.createElement("div",null,l.a.createElement(r.a,{to:"/docs/getting-started/whats-next/#prod-ready",className:"text--primary",title:"This component has passed reliability standards that make it production ready. Click to learn more."},l.a.createElement("i",{className:"feather icon-award"})," Prod-Ready Status")),"best_effort"==t&&l.a.createElement("div",null,l.a.createElement(r.a,{to:"/docs/getting-started/whats-next/#best-effort",className:"text--warning",title:"This component makes a best-effort delivery guarantee, and in rare cases can lose data. Click to learn more."},l.a.createElement("i",{className:"feather icon-shield-off"})," Best-Effort Delivery")),"at_least_once"==t&&l.a.createElement("div",null,l.a.createElement(r.a,{to:"/docs/getting-started/whats-next/#at-least-once",className:"text--primary",title:"This component offers an at-least-once delivery guarantee. Click to learn more."},l.a.createElement("i",{className:"feather icon-shield"})," At-Least-Once")),a&&l.a.createElement("div",null,l.a.createElement(r.a,{to:"/docs/getting-started/data-model/",title:"This component works on the these event types."},l.a.createElement("i",{className:"feather icon-database"})," ",l.a.createElement(_,{values:a}))),n&&c&&l.a.createElement("div",null,l.a.createElement(r.a,{to:"/docs/setup/installation/operating-systems/",title:"This component works on the "+n.join(", ")+" operating systems."},l.a.createElement("i",{className:"feather icon-cpu"})," ",l.a.createElement(f,{operatingSystems:n,unsupportedOperatingSystems:c})))):null}t.default=function(e){var t=Object(g.a)().siteConfig,a=void 0===t?{}:t,n=a.title,i=a.url,o=e.content,m=o.metadata,p=m.description,v=m.editUrl,_=m.image,f=m.keywords,y=m.lastUpdatedAt,k=m.lastUpdatedBy,b=m.permalink,w=m.title,x=m.version,S=o.frontMatter,C=(S.component_title,S.delivery_guarantee),T=S.event_types,O=S.function_category,j=(S.hide_title,S.hide_table_of_contents,S.issues_url),B=S.operating_systems,D=S.posts_path,I=S.source_url,L=S.status,V=S.unsupported_operating_systems,A=i+Object(E.a)(_);return l.a.createElement("div",null,l.a.createElement(s.a,null,w&&l.a.createElement("title",null,w," | Docs | ",n),p&&l.a.createElement("meta",{name:"description",content:p}),p&&l.a.createElement("meta",{property:"og:description",content:p}),f&&f.length&&l.a.createElement("meta",{name:"keywords",content:f.join(",")}),_&&l.a.createElement("meta",{property:"og:image",content:A}),_&&l.a.createElement("meta",{property:"twitter:image",content:A}),_&&l.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+w}),b&&l.a.createElement("meta",{property:"og:url",content:i+b})),l.a.createElement("div",{className:u.a.container},l.a.createElement("div",{className:u.a.leftCol},l.a.createElement("div",{className:"docItemContainer_"},l.a.createElement("article",null,x&&l.a.createElement("span",{style:{verticalAlign:"top"},className:"badge badge--info"},"Version: ",x),!m.hide_title&&l.a.createElement("header",null,l.a.createElement("div",{className:"badges"},O&&l.a.createElement(r.a,{to:"/components?functions[]="+O,className:"badge badge--primary"},O)),l.a.createElement("h1",{className:u.a.docTitle},m.title)),l.a.createElement("div",{className:"markdown"},l.a.createElement(o,null)))),!m.hide_pagination&&(m.next||m.previous)&&l.a.createElement("div",{className:u.a.paginator},l.a.createElement(c.a,{next:m.next,previous:m.previous}))),o.rightToc&&l.a.createElement("div",{className:u.a.rightCol},l.a.createElement("div",{className:d()("table-of-contents",u.a.tableOfContents)},l.a.createElement(N,{deliveryGuarantee:C,eventTypes:T,operatingSystems:B,status:L,unsupportedOperatingSystems:V}),o.rightToc.length>0&&l.a.createElement("div",{className:"section"},l.a.createElement("div",{className:"title"},"Contents"),l.a.createElement(h,{headings:o.rightToc})),l.a.createElement("div",{className:"section"},l.a.createElement("div",{className:"title"},"Resources"),l.a.createElement("ul",{className:"contents"},v&&l.a.createElement("li",null,l.a.createElement("a",{href:v,className:"contents__link",target:"_blank"},l.a.createElement("i",{className:"feather icon-edit-1"})," Edit this page")),D&&l.a.createElement("li",null,l.a.createElement(r.a,{to:D,className:"contents__link"},l.a.createElement("i",{className:"feather icon-book-open"})," View Blog Posts")),j&&l.a.createElement("li",null,l.a.createElement("a",{href:j,className:"contents__link",target:"_blank"},l.a.createElement("i",{className:"feather icon-message-circle"})," View Issues")),I&&l.a.createElement("li",null,l.a.createElement("a",{href:I,className:"contents__link",target:"_blank"},l.a.createElement("i",{className:"feather icon-github"})," View Source")))),(y||k)&&l.a.createElement("div",{className:"section"},"Last updated"," ",y&&l.a.createElement(l.a.Fragment,null,"on"," ",l.a.createElement("strong",null,new Date(1e3*y).toLocaleDateString()),k&&" "),k&&l.a.createElement(l.a.Fragment,null,"by ",l.a.createElement("strong",null,k)))))))}},527:function(e,t,a){"use strict";var n=a(0),l=a.n(n),s=a(430),r=a(423),c=a.n(r);a(147);t.a=function(e){var t=e.className,a=e.previous,n=e.next;return l.a.createElement("nav",{className:c()("pagination-nav",t)},l.a.createElement("div",{className:"pagination-nav__item"},a&&l.a.createElement(s.a,{className:"pagination-nav__link",to:a.permalink},l.a.createElement("h5",{className:"pagination-nav__link--sublabel"},"Previous"),l.a.createElement("h4",{className:"pagination-nav__link--label"},"\xab ",a.title))),l.a.createElement("div",{className:"pagination-nav__item pagination-nav__item--next"},n&&l.a.createElement(s.a,{className:"pagination-nav__link",to:n.permalink},l.a.createElement("h5",{className:"pagination-nav__link--sublabel"},"Next"),l.a.createElement("h4",{className:"pagination-nav__link--label"},n.title," \xbb"))))}}}]); \ No newline at end of file diff --git a/18415bef.da7f717c.js b/18415bef.e4ae9e9b.js similarity index 88% rename from 18415bef.da7f717c.js rename to 18415bef.e4ae9e9b.js index 923cc20806..43f01fa5a1 100644 --- a/18415bef.da7f717c.js +++ b/18415bef.e4ae9e9b.js @@ -1,2 +1,2 @@ -/*! For license information please see 18415bef.da7f717c.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{176:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),a=(n(0),n(422)),i=(n(431),n(426),n(421)),c={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Monitoring",description:"Learn how to monitor your infrastructure and your apps with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Monitoring",description:"Learn how to monitor your infrastructure and your apps with Qovery",permalink:"/guides/advanced/monitoring",readingTime:"1 min read",source:"@site/guides/advanced/monitoring.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Monitoring",truncated:!1,prevItem:{title:"Migration",permalink:"/guides/advanced/migration"},nextItem:{title:"Mono repository",permalink:"/guides/advanced/monorepository"}},s=[{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},"WIP"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Prometheus & Grafana"),Object(a.b)("li",{parentName:"ul"},"Datadog")),Object(a.b)("h2",{id:"qa"},"Q&A"),Object(a.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:o(u,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),p=l[0],f=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return f("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 18415bef.e4ae9e9b.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{177:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),a=(n(0),n(425)),i=(n(434),n(429),n(424)),c={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Monitoring",description:"Learn how to monitor your infrastructure and your apps with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Monitoring",description:"Learn how to monitor your infrastructure and your apps with Qovery",permalink:"/guides/advanced/monitoring",readingTime:"1 min read",source:"@site/guides/advanced/monitoring.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Monitoring",truncated:!1,prevItem:{title:"Migration",permalink:"/guides/advanced/migration"},nextItem:{title:"Mono repository",permalink:"/guides/advanced/monorepository"}},s=[{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},"WIP"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Prometheus & Grafana"),Object(a.b)("li",{parentName:"ul"},"Datadog")),Object(a.b)("h2",{id:"qa"},"Q&A"),Object(a.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:o(u,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),p=l[0],f=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return f("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/1a1dfe25.c95b18d0.js.LICENSE.txt b/18415bef.e4ae9e9b.js.LICENSE.txt similarity index 100% rename from 1a1dfe25.c95b18d0.js.LICENSE.txt rename to 18415bef.e4ae9e9b.js.LICENSE.txt diff --git a/1a1dfe25.c95b18d0.js b/1a1dfe25.40373275.js similarity index 93% rename from 1a1dfe25.c95b18d0.js rename to 1a1dfe25.40373275.js index b04eac3130..b5aad62c44 100644 --- a/1a1dfe25.c95b18d0.js +++ b/1a1dfe25.40373275.js @@ -1,2 +1,2 @@ -/*! For license information please see 1a1dfe25.c95b18d0.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{177:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),o=(n(0),n(422)),c=n(421),l=n(429),i={last_modified_on:"2023-11-24",title:"Install Qovery",description:"How to install Qovery"},b={id:"getting-started/install-qovery",title:"Install Qovery",description:"How to install Qovery",source:"@site/docs/getting-started/install-qovery.md",permalink:"/docs/getting-started/install-qovery",sidebar:"docs",previous:{title:"Basic Concepts",permalink:"/docs/getting-started/basic-concepts"},next:{title:"Deploy my application",permalink:"/docs/getting-started/deploy-my-app"}},u=[{value:"Easy: Kubernetes Managed by Qovery",id:"easy-kubernetes-managed-by-qovery",children:[]},{value:"Advanced: Bring Your Own Kubernetes (BYOK)",id:"advanced-bring-your-own-kubernetes-byok",children:[]}],s={rightToc:u};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery offers two distinct approaches to Kubernetes management: Kubernetes managed by Qovery and self-managed Kubernetes (Bring Your Own Kubernetes - BYOK)"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"In a nutshell, choose Kubernetes Managed by Qovery if you are not familiar with Kubernetes or you don't want to bother with it and delegate infrastructure management to Qovery. Choose BYOK otherwise.")),Object(o.b)("p",null,"Here is a table to help you to choose between both:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Feature/Aspect"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Kubernetes Managed by Qovery"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"BYOK (Bring Your Own Kubernetes)"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Management")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Fully managed by Qovery"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Self-managed by the organization")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Control")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Limited control over Kubernetes infrastructure"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Full control over Kubernetes setup")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Supported Cloud Service Providers")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"AWS, GCP, Scaleway"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Customization")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Standard Qovery configuration"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"High customization and configuration freedom")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Expertise Required")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"None"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Requires Kubernetes expertise")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Responsibility")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Qovery is responsible for maintenance"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Organization is responsible for maintenance")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Developer Experience")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Streamlined and simplified"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Streamlined and simplified (no difference)")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Setup Complexity")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Just a AWS, GCP or Scaleway account"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Requires infrastructure and Kubernetes knowledge")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Flexibility in Usage")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Standardized to Qovery's environment"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Flexible to meet specific organizational needs")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Ideal Use Case")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Organizations preferring a hands-off approach"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Organizations with specific Kubernetes needs")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Managed Services")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Cf. list below"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A")))),Object(o.b)("p",null,"Note that the Qovery Managed Kubernetes also support out of the box the following capabilities:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Vertical Pod Autoscaler"),Object(o.b)("li",{parentName:"ul"},"Cluster Autoscaler"),Object(o.b)("li",{parentName:"ul"},"CoreDNS"),Object(o.b)("li",{parentName:"ul"},"Cert-manager"),Object(o.b)("li",{parentName:"ul"},"Cert-manager Qovery Webhook"),Object(o.b)("li",{parentName:"ul"},"Nginx Ingress"),Object(o.b)("li",{parentName:"ul"},"Metrics Server"),Object(o.b)("li",{parentName:"ul"},"External DNS"),Object(o.b)("li",{parentName:"ul"},"Promtail"),Object(o.b)("li",{parentName:"ul"},"Loki"),Object(o.b)("li",{parentName:"ul"},"AWS",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"AWS EBS Driver"),Object(o.b)("li",{parentName:"ul"},"AWS Kubeproxy"),Object(o.b)("li",{parentName:"ul"},"AWS CNI"),Object(o.b)("li",{parentName:"ul"},"IAM EKS User Mapper"),Object(o.b)("li",{parentName:"ul"},"Karpenter"),Object(o.b)("li",{parentName:"ul"},"AWS Node Term Handler")))),Object(o.b)("h2",{id:"easy-kubernetes-managed-by-qovery"},"Easy: Kubernetes Managed by Qovery"),Object(o.b)(l.a,{to:"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes",mdxType:"Jump"},"Deploy Qovery on AWS"),Object(o.b)(l.a,{to:"/guides/cloud-provider/guide-google-cloud-platform/",mdxType:"Jump"},"Deploy Qovery on GCP"),Object(o.b)(l.a,{to:"/guides/cloud-provider/guide-microsoft-azure/",mdxType:"Jump"},"Deploy Qovery on Azure"),Object(o.b)(l.a,{to:"/guides/cloud-provider/guide-scaleway",mdxType:"Jump"},"Deploy Qovery on Scaleway"),Object(o.b)("h2",{id:"advanced-bring-your-own-kubernetes-byok"},"Advanced: Bring Your Own Kubernetes (BYOK)"),Object(o.b)(l.a,{to:"/guides/provider/guide-kubernetes",mdxType:"Jump"},"Deploy Qovery on Kubernetes"))}p.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var b=r.a.createContext({}),u=function(e){var t=r.a.useContext(b),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},s=function(e){var t=u(e.components);return r.a.createElement(b.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,b=i(e,["components","mdxType","originalType","parentName"]),s=u(n),d=a,m=s["".concat(c,".").concat(d)]||s[d]||p[d]||o;return n?r.a.createElement(m,l({ref:t},b,{components:n})):r.a.createElement(m,l({ref:t},b))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,c=new Array(o);c[0]=d;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l.mdxType="string"==typeof e?e:a,c[1]=l;for(var b=2;b1?arguments[1]:void 0,n),i=c>2?arguments[2]:void 0,b=void 0===i?n:r(i,n);b>l;)t[l++]=e;return t}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),c=n(39),l=n(430),i=n(20),b=n.n(i);t.a=function(e){var t,n=e.to,i=e.href,u=n||i,s=Object(l.a)(u),p=Object(r.useRef)(!1),d=b.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&s&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,s]),u&&s?o.a.createElement(c.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,a;d&&e&&s&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),c=n(420),l=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,c=e.leftIcon,i=e.rightIcon,b=e.size,u=e.target,s=e.to,p=l()("jump-to","jump-to--"+b,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(i||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:s,target:u,className:p},d):r.a.createElement(o.a,{to:s,className:p},d)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see 1a1dfe25.40373275.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{178:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),o=(n(0),n(425)),c=n(424),l=n(431),i={last_modified_on:"2023-11-24",title:"Install Qovery",description:"How to install Qovery"},b={id:"getting-started/install-qovery",title:"Install Qovery",description:"How to install Qovery",source:"@site/docs/getting-started/install-qovery.md",permalink:"/docs/getting-started/install-qovery",sidebar:"docs",previous:{title:"Basic Concepts",permalink:"/docs/getting-started/basic-concepts"},next:{title:"Deploy my application",permalink:"/docs/getting-started/deploy-my-app"}},u=[{value:"Easy: Kubernetes Managed by Qovery",id:"easy-kubernetes-managed-by-qovery",children:[]},{value:"Advanced: Bring Your Own Kubernetes (BYOK)",id:"advanced-bring-your-own-kubernetes-byok",children:[]}],s={rightToc:u};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery offers two distinct approaches to Kubernetes management: Kubernetes managed by Qovery and self-managed Kubernetes (Bring Your Own Kubernetes - BYOK)"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"In a nutshell, choose Kubernetes Managed by Qovery if you are not familiar with Kubernetes or you don't want to bother with it and delegate infrastructure management to Qovery. Choose BYOK otherwise.")),Object(o.b)("p",null,"Here is a table to help you to choose between both:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Feature/Aspect"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Kubernetes Managed by Qovery"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"BYOK (Bring Your Own Kubernetes)"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Management")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Fully managed by Qovery"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Self-managed by the organization")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Control")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Limited control over Kubernetes infrastructure"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Full control over Kubernetes setup")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Supported Cloud Service Providers")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"AWS, GCP, Scaleway"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Customization")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Standard Qovery configuration"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"High customization and configuration freedom")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Expertise Required")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"None"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Requires Kubernetes expertise")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Responsibility")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Qovery is responsible for maintenance"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Organization is responsible for maintenance")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Developer Experience")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Streamlined and simplified"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Streamlined and simplified (no difference)")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Setup Complexity")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Just a AWS, GCP or Scaleway account"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Requires infrastructure and Kubernetes knowledge")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Flexibility in Usage")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Standardized to Qovery's environment"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Flexible to meet specific organizational needs")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Ideal Use Case")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Organizations preferring a hands-off approach"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Organizations with specific Kubernetes needs")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Managed Services")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Cf. list below"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A")))),Object(o.b)("p",null,"Note that the Qovery Managed Kubernetes also support out of the box the following capabilities:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Vertical Pod Autoscaler"),Object(o.b)("li",{parentName:"ul"},"Cluster Autoscaler"),Object(o.b)("li",{parentName:"ul"},"CoreDNS"),Object(o.b)("li",{parentName:"ul"},"Cert-manager"),Object(o.b)("li",{parentName:"ul"},"Cert-manager Qovery Webhook"),Object(o.b)("li",{parentName:"ul"},"Nginx Ingress"),Object(o.b)("li",{parentName:"ul"},"Metrics Server"),Object(o.b)("li",{parentName:"ul"},"External DNS"),Object(o.b)("li",{parentName:"ul"},"Promtail"),Object(o.b)("li",{parentName:"ul"},"Loki"),Object(o.b)("li",{parentName:"ul"},"AWS",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"AWS EBS Driver"),Object(o.b)("li",{parentName:"ul"},"AWS Kubeproxy"),Object(o.b)("li",{parentName:"ul"},"AWS CNI"),Object(o.b)("li",{parentName:"ul"},"IAM EKS User Mapper"),Object(o.b)("li",{parentName:"ul"},"Karpenter"),Object(o.b)("li",{parentName:"ul"},"AWS Node Term Handler")))),Object(o.b)("h2",{id:"easy-kubernetes-managed-by-qovery"},"Easy: Kubernetes Managed by Qovery"),Object(o.b)(l.a,{to:"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes",mdxType:"Jump"},"Deploy Qovery on AWS"),Object(o.b)(l.a,{to:"/guides/cloud-provider/guide-google-cloud-platform/",mdxType:"Jump"},"Deploy Qovery on GCP"),Object(o.b)(l.a,{to:"/guides/cloud-provider/guide-microsoft-azure/",mdxType:"Jump"},"Deploy Qovery on Azure"),Object(o.b)(l.a,{to:"/guides/cloud-provider/guide-scaleway",mdxType:"Jump"},"Deploy Qovery on Scaleway"),Object(o.b)("h2",{id:"advanced-bring-your-own-kubernetes-byok"},"Advanced: Bring Your Own Kubernetes (BYOK)"),Object(o.b)(l.a,{to:"/guides/provider/guide-kubernetes",mdxType:"Jump"},"Deploy Qovery on Kubernetes"))}p.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var b=r.a.createContext({}),u=function(e){var t=r.a.useContext(b),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},s=function(e){var t=u(e.components);return r.a.createElement(b.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,b=i(e,["components","mdxType","originalType","parentName"]),s=u(n),d=a,m=s["".concat(c,".").concat(d)]||s[d]||p[d]||o;return n?r.a.createElement(m,l({ref:t},b,{components:n})):r.a.createElement(m,l({ref:t},b))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,c=new Array(o);c[0]=d;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l.mdxType="string"==typeof e?e:a,c[1]=l;for(var b=2;b1?arguments[1]:void 0,n),i=c>2?arguments[2]:void 0,b=void 0===i?n:r(i,n);b>l;)t[l++]=e;return t}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),c=n(39),l=n(432),i=n(20),b=n.n(i);t.a=function(e){var t,n=e.to,i=e.href,u=n||i,s=Object(l.a)(u),p=Object(r.useRef)(!1),d=b.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&s&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,s]),u&&s?o.a.createElement(c.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,a;d&&e&&s&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),c=n(423),l=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,c=e.leftIcon,i=e.rightIcon,b=e.size,u=e.target,s=e.to,p=l()("jump-to","jump-to--"+b,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(i||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:s,target:u,className:p},d):r.a.createElement(o.a,{to:s,className:p},d)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/1a39f24c.3227845c.js.LICENSE.txt b/1a1dfe25.40373275.js.LICENSE.txt similarity index 100% rename from 1a39f24c.3227845c.js.LICENSE.txt rename to 1a1dfe25.40373275.js.LICENSE.txt diff --git a/1a39f24c.3227845c.js b/1a39f24c.ae0c1878.js similarity index 93% rename from 1a39f24c.3227845c.js rename to 1a39f24c.ae0c1878.js index 6f46b6782c..038ac803d6 100644 --- a/1a39f24c.3227845c.js +++ b/1a39f24c.ae0c1878.js @@ -1,2 +1,2 @@ -/*! For license information please see 1a39f24c.3227845c.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{178:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),o=(n(0),n(422)),i=(n(431),n(426),n(421),{last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Continuous Integration",description:"Learn how to integrate your Continuous Integration (CI) platform with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),c={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Continuous Integration",description:"Learn how to integrate your Continuous Integration (CI) platform with Qovery",permalink:"/guides/advanced/continuous-integration",readingTime:"2 min read",source:"@site/guides/advanced/continuous-integration.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Continuous Integration",truncated:!1,prevItem:{title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",permalink:"/guides/tutorial/build-e2e-testing-ephemeral-environments"},nextItem:{title:"Costs Control",permalink:"/guides/advanced/costs-control"}},u=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:u};function l(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery integrates with all existing Continuous Integration platforms. We have a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/"}),"guide for the most popular CI platforms"),". However, even if you don't find your CI platform, ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"you can see here")," that integrating Qovery into a CI is just a matter of:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Adding a new step into your CI pipeline"),Object(o.b)("li",{parentName:"ol"},"Installing the Qovery CLI"),Object(o.b)("li",{parentName:"ol"},"Running the ",Object(o.b)("inlineCode",{parentName:"li"},"qovery deploy ...")," commands")),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to integrate Qovery into your CI platform:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-integrate-qovery-with-github-actions/"}),"Step-by-step guide to integrate GitHub Actions")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-integrate-qovery-with-github-actions/"}),"Step-by-step guide to learn how to integrate GitHub Actions with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"Integrate GitHub Actions")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"Learn how to integrate GitHub Actions with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/gitlab-ci/"}),"Integrate GitLab CI")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/gitlab-ci/"}),"Learn how to integrate GitLab CI with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/circle-ci/"}),"Integrate Circle CI")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/circle-ci/"}),"Learn how to integrate Circle CI with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/jenkins/"}),"Integrate Jenkins")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/jenkins/"}),"Learn how to integrate Jenkins with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=github%20actions"}),'Forum "GitHub Actions"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=github%20actions"}),'List "GitHub Actions" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=gitlab%25ci"}),'Forum "GitLab CI"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=gitlab%20ci"}),'List "GitLab CI" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=circle%20ci"}),'Forum "Circle CI"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=circle%20ci"}),'List "Circle CI" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=jenkins"}),'Forum "Jenkins"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=jenkins"}),'List "Jenkins" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}l.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},b=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),b=l(n),m=r,d=b["".concat(i,".").concat(m)]||b[m]||p[m]||o;return n?a.a.createElement(d,c({ref:t},s,{components:n})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:a(u,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),b=l[0],p=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 1a39f24c.ae0c1878.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{179:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),o=(n(0),n(425)),i=(n(434),n(429),n(424),{last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Continuous Integration",description:"Learn how to integrate your Continuous Integration (CI) platform with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),c={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Continuous Integration",description:"Learn how to integrate your Continuous Integration (CI) platform with Qovery",permalink:"/guides/advanced/continuous-integration",readingTime:"2 min read",source:"@site/guides/advanced/continuous-integration.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Continuous Integration",truncated:!1,prevItem:{title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",permalink:"/guides/tutorial/build-e2e-testing-ephemeral-environments"},nextItem:{title:"Costs Control",permalink:"/guides/advanced/costs-control"}},u=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:u};function l(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery integrates with all existing Continuous Integration platforms. We have a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/"}),"guide for the most popular CI platforms"),". However, even if you don't find your CI platform, ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"you can see here")," that integrating Qovery into a CI is just a matter of:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Adding a new step into your CI pipeline"),Object(o.b)("li",{parentName:"ol"},"Installing the Qovery CLI"),Object(o.b)("li",{parentName:"ol"},"Running the ",Object(o.b)("inlineCode",{parentName:"li"},"qovery deploy ...")," commands")),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to integrate Qovery into your CI platform:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-integrate-qovery-with-github-actions/"}),"Step-by-step guide to integrate GitHub Actions")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-integrate-qovery-with-github-actions/"}),"Step-by-step guide to learn how to integrate GitHub Actions with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"Integrate GitHub Actions")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"Learn how to integrate GitHub Actions with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/gitlab-ci/"}),"Integrate GitLab CI")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/gitlab-ci/"}),"Learn how to integrate GitLab CI with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/circle-ci/"}),"Integrate Circle CI")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/circle-ci/"}),"Learn how to integrate Circle CI with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/jenkins/"}),"Integrate Jenkins")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/integration/continuous-integration/jenkins/"}),"Learn how to integrate Jenkins with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=github%20actions"}),'Forum "GitHub Actions"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=github%20actions"}),'List "GitHub Actions" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=gitlab%25ci"}),'Forum "GitLab CI"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=gitlab%20ci"}),'List "GitLab CI" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=circle%20ci"}),'Forum "Circle CI"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=circle%20ci"}),'List "Circle CI" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=jenkins"}),'Forum "Jenkins"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=jenkins"}),'List "Jenkins" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}l.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},b=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),b=l(n),m=r,d=b["".concat(i,".").concat(m)]||b[m]||p[m]||o;return n?a.a.createElement(d,c({ref:t},s,{components:n})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:a(u,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),b=l[0],p=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/1aa86e56.eeb01a2a.js.LICENSE.txt b/1a39f24c.ae0c1878.js.LICENSE.txt similarity index 100% rename from 1aa86e56.eeb01a2a.js.LICENSE.txt rename to 1a39f24c.ae0c1878.js.LICENSE.txt diff --git a/1a3e0044.6908c156.js b/1a3e0044.410046e9.js similarity index 96% rename from 1a3e0044.6908c156.js rename to 1a3e0044.410046e9.js index 8f16f116c9..7124f4dca6 100644 --- a/1a3e0044.6908c156.js +++ b/1a3e0044.410046e9.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{179:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return m}));var a=n(1),r=n(9),i=(n(0),n(422)),o=n(421),l=(n(434),n(426)),c={last_modified_on:"2023-05-29",$schema:"/.meta/.schemas/guides.json",title:"Getting Started with Preview Environments on AWS",description:"Step-by-step guide to get started with the preview environment on AWS",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},b={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Getting Started with Preview Environments on AWS",description:"Step-by-step guide to get started with the preview environment on AWS",permalink:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners",readingTime:"6 min read",source:"@site/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Getting Started with Preview Environments on AWS",truncated:!1,prevItem:{title:"Deploy Temporal on Kubernetes",permalink:"/guides/tutorial/deploy-temporal-on-kubernetes"},nextItem:{title:"Grafana setup with Qovery",permalink:"/guides/tutorial/grafana-install"}},s=[{value:"Steps",id:"steps",children:[]},{value:"Create your Blueprint Environment",id:"create-your-blueprint-environment",children:[{value:"Enable Preview Environment",id:"enable-preview-environment",children:[]},{value:"Change your base branch",id:"change-your-base-branch",children:[]}]},{value:"Validate your Blueprint Environment",id:"validate-your-blueprint-environment",children:[]},{value:"Create a Preview Environment",id:"create-a-preview-environment",children:[]},{value:"Delete a Preview Environment",id:"delete-a-preview-environment",children:[]},{value:"Advanced",id:"advanced",children:[]},{value:"Wrapping up",id:"wrapping-up",children:[]}],u={rightToc:s};function m(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"It is critical to have testing and staging environments accurately reflect production, but achieving this can be a major operational hassle. Most engineering teams use a single staging environment which makes it hard for developers to test their changes in isolation; the alternative is for DevOps teams to spin up new testing or staging environments manually and tear them down after testing is done."),Object(i.b)("p",null,"Qovery\u2019s Preview Environments solve this problem by automatically creating a clone of your production environment (including applications, databases and configuration) on every pull request, so you can test your changes with confidence without affecting your production."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/preview-environment-on-aws-for-beginner/preview_env_flow_schema.jpg",alt:"Flow on how Qovery Preview Environment works"})),Object(i.b)("p",null,"Qovery keeps your preview environments up to date on every commit and automatically destroys them when the original pull request is merged or closed. You can also set up an expiry time to automatically clean up preview environments after a period of inactivity."),Object(i.b)("p",null,"Preview Environments can be helpful in a lot of cases:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Share your changes live in code reviews: no more Git diffs for visual changes!"),Object(i.b)("li",{parentName:"ul"},"Get shareable links for upcoming features and collaborate more effectively with internal and external stakeholders."),Object(i.b)("li",{parentName:"ul"},"Run CI tests against a high fidelity copy of your production environment before merging.")),Object(i.b)("p",null,"In this step-by-step guide you will learn how to get started using the Preview Environments on AWS with Qovery."),Object(i.b)(o.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"This guide also works with other cloud service providers supported by Qovery.")),Object(i.b)("blockquote",null,Object(i.b)("p",{parentName:"blockquote"},"Please contact us via ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum")," if you have any questions concerning the Preview Environments")),Object(i.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"You have ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"https://start.qovery.com"}),"sign in on Qovery")),Object(i.b)("li",{parentName:"ul"},"You have ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes/"}),"installed Qovery on your AWS account")),Object(i.b)("li",{parentName:"ul"},"You have at least already ",Object(i.b)("strong",{parentName:"li"},"deployed successfully")," a first application"))),Object(i.b)("h2",{id:"steps"},"Steps"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#create-a-blueprint-environment"}),'Create a "Blueprint" environment')),Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#enable-preview-environment"}),"Enable Preview Environment feature")),Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#create-a-preview-environment"}),"Create a Preview Environment")),Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#delete-a-preview-environment"}),"Delete a Preview Environment")),Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#seed-your-database"}),"Seed your database")),Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#auto-stop-and-start-your-preview-environments"}),"Auto stop and start your Preview Environments")),Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#integrate-your-ci-platform"}),"Integrate your CI (Continuous Deployment) platform"))),Object(i.b)("h2",{id:"create-your-blueprint-environment"},"Create your Blueprint Environment"),Object(i.b)("p",null,"Even if not required, we recommend creating an ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"environment"),' that will serve as a root to create your Preview Environments. The idea is to keep this environment as a template of a fully working environment. This environment should not be directly used. This is what we call "blueprint environment".'),Object(i.b)("p",null,"I assume you already have a working environment, so to create a blueprint environment you need to:"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"Go to your working environment"),Object(i.b)("li",{parentName:"ol"},'Click on "Actions" > "Clone"'),Object(i.b)("li",{parentName:"ol"},'Name your environment "blueprint"'),Object(i.b)("li",{parentName:"ol"},'Click on "Create"')),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/a282d6b832794671a3582550aa45f9ae",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)(o.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"We recommend using a different cluster than your production for your Preview Environments.")),Object(i.b)("h3",{id:"enable-preview-environment"},"Enable Preview Environment"),Object(i.b)("p",null,"Now, you can go to turn on Preview Environments by:"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"Click on your ",Object(i.b)("inlineCode",{parentName:"li"},"Blueprint"),' environment "Settings".'),Object(i.b)("li",{parentName:"ol"},"Click on the ",Object(i.b)("inlineCode",{parentName:"li"},"Preview Env.")," tab"),Object(i.b)("li",{parentName:"ol"},"Turn on Preview Environment feature for all your applications by clicking on ",Object(i.b)("inlineCode",{parentName:"li"},"Activate preview environment for all apps"),".")),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/55b9d99a59524e1cb7875f7db7691fbe",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)("h3",{id:"change-your-base-branch"},"Change your base branch"),Object(i.b)("p",null,"Now that you have turned on the Preview Environment feature, you need to change the base branch from your applications inside your Blueprint Environment. Let's say, every new feature branch you create are coming from ",Object(i.b)("inlineCode",{parentName:"p"},"staging"),". Then you will need to change all your applications to target the ",Object(i.b)("inlineCode",{parentName:"p"},"staging")," branch."),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/67df458d340d484fa1e675cc20e36caf",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)("p",null,"Here is a flow example showing what happen when you create a new Pull Request from a ",Object(i.b)("inlineCode",{parentName:"p"},"feat/xxx")," branch that has been created from the base branch ",Object(i.b)("inlineCode",{parentName:"p"},"staging"),"."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/preview-environment-on-aws-for-beginner/preview_env_branching.jpg",alt:"Flow on how Qovery Preview Environment Branching works"})),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"A developer creates a git branch ",Object(i.b)("inlineCode",{parentName:"li"},"feat/xxx")," is created from ",Object(i.b)("inlineCode",{parentName:"li"},"staging"),"."),Object(i.b)("li",{parentName:"ol"},"A developer creates a Pull Request for ",Object(i.b)("inlineCode",{parentName:"li"},"feat/xxx"),"."),Object(i.b)("li",{parentName:"ol"},"Qovery creates a Preview Environment ",Object(i.b)("inlineCode",{parentName:"li"},"feat/xxx")," from the ",Object(i.b)("inlineCode",{parentName:"li"},"blueprint")," environment. ",Object(i.b)("strong",{parentName:"li"},"The frontend, backend, PostgreSQL and Redis instances are cloned!")),Object(i.b)("li",{parentName:"ol"},"The frontend app from the environment ",Object(i.b)("inlineCode",{parentName:"li"},"feat/xxx")," is accessible via a dedicated URL.")),Object(i.b)("h2",{id:"validate-your-blueprint-environment"},"Validate your Blueprint Environment"),Object(i.b)("p",null,"Before creating a Preview Environment, validate that your Blueprint environment works."),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/3dd4d9aee9ac44a9af0cb8eddee7735c",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)("p",null,"Once done, you need to:"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},'Stop your Blueprint environment by clicking on "Actions" > "Stop".'),Object(i.b)("li",{parentName:"ol"},'Turn off "auto-deploy" by clicking on "Settings" > "Deployment" > "Auto-deploy off" > "Save".')),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/36b0bb48346f40f6ac8569a7b8dbc5b3",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)("p",null,"We are now ready to try out our Preview Environment configuration."),Object(i.b)("h2",{id:"create-a-preview-environment"},"Create a Preview Environment"),Object(i.b)("p",null,"To create a Preview Environment, here are the steps:"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"Checkout your ",Object(i.b)("inlineCode",{parentName:"li"},"staging")," branch."),Object(i.b)("li",{parentName:"ol"},"Create a branch ",Object(i.b)("inlineCode",{parentName:"li"},"test_qovery_preview_environment")," and push it."),Object(i.b)("li",{parentName:"ol"},"Create a Pull Request/Merge Request.")),Object(i.b)(o.a,{type:"success",mdxType:"Alert"},Object(i.b)("p",null,"Qovery take care of cloning all your services and the configuration as well (Environment Variables and Secrets included).")),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/2266d0897c964635b37447ae9ef2acea",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)("p",null,"You must see a new environment appearing in your environment list on Qovery. Wait until it is fully deployed, then you will be able to connect to it. This environment is fully isolated from your base environment."),Object(i.b)("h2",{id:"delete-a-preview-environment"},"Delete a Preview Environment"),Object(i.b)("p",null,"To delete you need to merge ",Object(i.b)("inlineCode",{parentName:"p"},"test_qovery_preview_environment")," into ",Object(i.b)("inlineCode",{parentName:"p"},"staging"),". You also have the ability to delete it manually on Qovery."),Object(i.b)(o.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"By merging into ",Object(i.b)("inlineCode",{parentName:"p"},"staging"),", Qovery will auto-redeploy the new version in your ",Object(i.b)("inlineCode",{parentName:"p"},"staging")," environment. Turn off ",Object(i.b)("inlineCode",{parentName:"p"},"auto-deploy")," from the ",Object(i.b)("inlineCode",{parentName:"p"},"staging")," environment settings if you want to manually deploy new version in staging.")),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/1feb31f4bbec4d54b0764dfa1271dd0d",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)("h2",{id:"advanced"},"Advanced"),Object(i.b)("p",null,"Eager to know how to go integrate Qovery Preview Environments with your CI and much more? Check out our the following guides:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/qovery/lifecycle-job-examples/tree/main/examples/seed-postgres-database-with-sql-script"}),"Seed your Preview Environment database")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/integration/continuous-integration/"}),"Integrate your CI platform")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/environment/#deployment-rule"}),"Auto-stop and start your Preview Environment")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/guides/tutorial/customizing-preview-url-with-qovery-cli/"}),"Set up a custom domain for your Preview Environment"))),Object(i.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(i.b)("p",null,"Congrats! You have set up your Preview Environments features. Feel free to check out our ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"forum")," and open a thread if you have any question. In the next guide, we will go deeper configuration to integrate the Preview Environment with your existing products and workflow."))}m.isMDXComponent=!0},421:function(e,t,n){"use strict";n(423);var a=n(0),r=n.n(a),i=n(420),o=n.n(i);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,i=e.icon,l=e.type,c=null;switch(l){case"danger":c="alert-triangle";break;case"success":c="check-circle";break;case"warning":c="alert-triangle";break;default:c="info"}return r.a.createElement("div",{className:o()(n,"alert","alert--"+l,{"alert--fill":a,"alert--icon":!1!==i}),role:"alert"},!1!==i&&r.a.createElement("i",{className:o()("feather","icon-"+(i||c))}),t)}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),i=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},434:function(e,t,n){"use strict";var a=n(1),r=(n(439),n(436),n(52),n(29),n(22),n(21),n(0)),i=n.n(r),o=n(446),l=n(420),c=n.n(l),b=n(428),s=n.n(b),u=n(445),m=37,p=39;function d(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,r=e.className,o=e.handleKeydown,l=e.style,b=e.values,s=e.selectedValue,u=e.tabRefs;return i.a.createElement("div",{className:n?"tabs--centered":null},i.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:c()("tabs",r,{"tabs--block":t}),style:l},b.map((function(e){var t=e.value,n=e.label;return i.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":s===t,className:c()("tab-item",{"tab-item--active":s===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return o(u,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function v(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,r=e.size,l=e.values,c=l;if(c[0].group){var b=_.groupBy(c,"group");c=Object.keys(b).map((function(e){return{label:e,options:b[e]}}))}return i.a.createElement(o.a,{className:"react-select-container react-select--"+r,classNamePrefix:"react-select",options:c,isClearable:n,placeholder:t,value:l.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,o=e.groupId,l=e.label,c=e.placeholder,b=e.select,h=e.size,f=(e.style,e.values),g=e.urlKey,w=Object(u.a)(),y=w.tabGroupChoices,j=w.setTabGroupChoices,O=Object(r.useState)(n),N=O[0],E=O[1];if(null!=o){var k=y[o];null!=k&&k!==N&&E(k)}var C=function(e){E(e),null!=o&&j(o,e)},P=[],x=function(e,t,n){switch(n.keyCode){case p:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case m:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(r.useEffect)((function(){if("undefined"!=typeof window&&window.location&&g){var e=s.a.parse(window.location.search);e[g]&&E(e[g])}}),[]),i.a.createElement(i.a.Fragment,null,i.a.createElement("div",{className:"margin-bottom--"+(h||"md")},l&&i.a.createElement("div",{className:"margin-vert--sm"},l),f.length>1&&(b?i.a.createElement(v,Object(a.a)({changeSelectedValue:C,handleKeydown:x,placeholder:c,selectedValue:N,size:h,tabRefs:P},e)):i.a.createElement(d,Object(a.a)({changeSelectedValue:C,handleKeydown:x,selectedValue:N,tabRefs:P},e)))),r.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[31],{180:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return m}));var a=n(1),r=n(9),i=(n(0),n(425)),o=n(424),l=(n(437),n(429)),c={last_modified_on:"2023-05-29",$schema:"/.meta/.schemas/guides.json",title:"Getting Started with Preview Environments on AWS",description:"Step-by-step guide to get started with the preview environment on AWS",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},b={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Getting Started with Preview Environments on AWS",description:"Step-by-step guide to get started with the preview environment on AWS",permalink:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners",readingTime:"6 min read",source:"@site/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Getting Started with Preview Environments on AWS",truncated:!1,prevItem:{title:"Deploy Temporal on Kubernetes",permalink:"/guides/tutorial/deploy-temporal-on-kubernetes"},nextItem:{title:"Grafana setup with Qovery",permalink:"/guides/tutorial/grafana-install"}},s=[{value:"Steps",id:"steps",children:[]},{value:"Create your Blueprint Environment",id:"create-your-blueprint-environment",children:[{value:"Enable Preview Environment",id:"enable-preview-environment",children:[]},{value:"Change your base branch",id:"change-your-base-branch",children:[]}]},{value:"Validate your Blueprint Environment",id:"validate-your-blueprint-environment",children:[]},{value:"Create a Preview Environment",id:"create-a-preview-environment",children:[]},{value:"Delete a Preview Environment",id:"delete-a-preview-environment",children:[]},{value:"Advanced",id:"advanced",children:[]},{value:"Wrapping up",id:"wrapping-up",children:[]}],u={rightToc:s};function m(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"It is critical to have testing and staging environments accurately reflect production, but achieving this can be a major operational hassle. Most engineering teams use a single staging environment which makes it hard for developers to test their changes in isolation; the alternative is for DevOps teams to spin up new testing or staging environments manually and tear them down after testing is done."),Object(i.b)("p",null,"Qovery\u2019s Preview Environments solve this problem by automatically creating a clone of your production environment (including applications, databases and configuration) on every pull request, so you can test your changes with confidence without affecting your production."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/preview-environment-on-aws-for-beginner/preview_env_flow_schema.jpg",alt:"Flow on how Qovery Preview Environment works"})),Object(i.b)("p",null,"Qovery keeps your preview environments up to date on every commit and automatically destroys them when the original pull request is merged or closed. You can also set up an expiry time to automatically clean up preview environments after a period of inactivity."),Object(i.b)("p",null,"Preview Environments can be helpful in a lot of cases:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Share your changes live in code reviews: no more Git diffs for visual changes!"),Object(i.b)("li",{parentName:"ul"},"Get shareable links for upcoming features and collaborate more effectively with internal and external stakeholders."),Object(i.b)("li",{parentName:"ul"},"Run CI tests against a high fidelity copy of your production environment before merging.")),Object(i.b)("p",null,"In this step-by-step guide you will learn how to get started using the Preview Environments on AWS with Qovery."),Object(i.b)(o.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"This guide also works with other cloud service providers supported by Qovery.")),Object(i.b)("blockquote",null,Object(i.b)("p",{parentName:"blockquote"},"Please contact us via ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum")," if you have any questions concerning the Preview Environments")),Object(i.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"You have ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"https://start.qovery.com"}),"sign in on Qovery")),Object(i.b)("li",{parentName:"ul"},"You have ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes/"}),"installed Qovery on your AWS account")),Object(i.b)("li",{parentName:"ul"},"You have at least already ",Object(i.b)("strong",{parentName:"li"},"deployed successfully")," a first application"))),Object(i.b)("h2",{id:"steps"},"Steps"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#create-a-blueprint-environment"}),'Create a "Blueprint" environment')),Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#enable-preview-environment"}),"Enable Preview Environment feature")),Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#create-a-preview-environment"}),"Create a Preview Environment")),Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#delete-a-preview-environment"}),"Delete a Preview Environment")),Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#seed-your-database"}),"Seed your database")),Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#auto-stop-and-start-your-preview-environments"}),"Auto stop and start your Preview Environments")),Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#integrate-your-ci-platform"}),"Integrate your CI (Continuous Deployment) platform"))),Object(i.b)("h2",{id:"create-your-blueprint-environment"},"Create your Blueprint Environment"),Object(i.b)("p",null,"Even if not required, we recommend creating an ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"environment"),' that will serve as a root to create your Preview Environments. The idea is to keep this environment as a template of a fully working environment. This environment should not be directly used. This is what we call "blueprint environment".'),Object(i.b)("p",null,"I assume you already have a working environment, so to create a blueprint environment you need to:"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"Go to your working environment"),Object(i.b)("li",{parentName:"ol"},'Click on "Actions" > "Clone"'),Object(i.b)("li",{parentName:"ol"},'Name your environment "blueprint"'),Object(i.b)("li",{parentName:"ol"},'Click on "Create"')),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/a282d6b832794671a3582550aa45f9ae",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)(o.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"We recommend using a different cluster than your production for your Preview Environments.")),Object(i.b)("h3",{id:"enable-preview-environment"},"Enable Preview Environment"),Object(i.b)("p",null,"Now, you can go to turn on Preview Environments by:"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"Click on your ",Object(i.b)("inlineCode",{parentName:"li"},"Blueprint"),' environment "Settings".'),Object(i.b)("li",{parentName:"ol"},"Click on the ",Object(i.b)("inlineCode",{parentName:"li"},"Preview Env.")," tab"),Object(i.b)("li",{parentName:"ol"},"Turn on Preview Environment feature for all your applications by clicking on ",Object(i.b)("inlineCode",{parentName:"li"},"Activate preview environment for all apps"),".")),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/55b9d99a59524e1cb7875f7db7691fbe",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)("h3",{id:"change-your-base-branch"},"Change your base branch"),Object(i.b)("p",null,"Now that you have turned on the Preview Environment feature, you need to change the base branch from your applications inside your Blueprint Environment. Let's say, every new feature branch you create are coming from ",Object(i.b)("inlineCode",{parentName:"p"},"staging"),". Then you will need to change all your applications to target the ",Object(i.b)("inlineCode",{parentName:"p"},"staging")," branch."),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/67df458d340d484fa1e675cc20e36caf",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)("p",null,"Here is a flow example showing what happen when you create a new Pull Request from a ",Object(i.b)("inlineCode",{parentName:"p"},"feat/xxx")," branch that has been created from the base branch ",Object(i.b)("inlineCode",{parentName:"p"},"staging"),"."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/preview-environment-on-aws-for-beginner/preview_env_branching.jpg",alt:"Flow on how Qovery Preview Environment Branching works"})),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"A developer creates a git branch ",Object(i.b)("inlineCode",{parentName:"li"},"feat/xxx")," is created from ",Object(i.b)("inlineCode",{parentName:"li"},"staging"),"."),Object(i.b)("li",{parentName:"ol"},"A developer creates a Pull Request for ",Object(i.b)("inlineCode",{parentName:"li"},"feat/xxx"),"."),Object(i.b)("li",{parentName:"ol"},"Qovery creates a Preview Environment ",Object(i.b)("inlineCode",{parentName:"li"},"feat/xxx")," from the ",Object(i.b)("inlineCode",{parentName:"li"},"blueprint")," environment. ",Object(i.b)("strong",{parentName:"li"},"The frontend, backend, PostgreSQL and Redis instances are cloned!")),Object(i.b)("li",{parentName:"ol"},"The frontend app from the environment ",Object(i.b)("inlineCode",{parentName:"li"},"feat/xxx")," is accessible via a dedicated URL.")),Object(i.b)("h2",{id:"validate-your-blueprint-environment"},"Validate your Blueprint Environment"),Object(i.b)("p",null,"Before creating a Preview Environment, validate that your Blueprint environment works."),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/3dd4d9aee9ac44a9af0cb8eddee7735c",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)("p",null,"Once done, you need to:"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},'Stop your Blueprint environment by clicking on "Actions" > "Stop".'),Object(i.b)("li",{parentName:"ol"},'Turn off "auto-deploy" by clicking on "Settings" > "Deployment" > "Auto-deploy off" > "Save".')),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/36b0bb48346f40f6ac8569a7b8dbc5b3",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)("p",null,"We are now ready to try out our Preview Environment configuration."),Object(i.b)("h2",{id:"create-a-preview-environment"},"Create a Preview Environment"),Object(i.b)("p",null,"To create a Preview Environment, here are the steps:"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"Checkout your ",Object(i.b)("inlineCode",{parentName:"li"},"staging")," branch."),Object(i.b)("li",{parentName:"ol"},"Create a branch ",Object(i.b)("inlineCode",{parentName:"li"},"test_qovery_preview_environment")," and push it."),Object(i.b)("li",{parentName:"ol"},"Create a Pull Request/Merge Request.")),Object(i.b)(o.a,{type:"success",mdxType:"Alert"},Object(i.b)("p",null,"Qovery take care of cloning all your services and the configuration as well (Environment Variables and Secrets included).")),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/2266d0897c964635b37447ae9ef2acea",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)("p",null,"You must see a new environment appearing in your environment list on Qovery. Wait until it is fully deployed, then you will be able to connect to it. This environment is fully isolated from your base environment."),Object(i.b)("h2",{id:"delete-a-preview-environment"},"Delete a Preview Environment"),Object(i.b)("p",null,"To delete you need to merge ",Object(i.b)("inlineCode",{parentName:"p"},"test_qovery_preview_environment")," into ",Object(i.b)("inlineCode",{parentName:"p"},"staging"),". You also have the ability to delete it manually on Qovery."),Object(i.b)(o.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"By merging into ",Object(i.b)("inlineCode",{parentName:"p"},"staging"),", Qovery will auto-redeploy the new version in your ",Object(i.b)("inlineCode",{parentName:"p"},"staging")," environment. Turn off ",Object(i.b)("inlineCode",{parentName:"p"},"auto-deploy")," from the ",Object(i.b)("inlineCode",{parentName:"p"},"staging")," environment settings if you want to manually deploy new version in staging.")),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/1feb31f4bbec4d54b0764dfa1271dd0d",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)("h2",{id:"advanced"},"Advanced"),Object(i.b)("p",null,"Eager to know how to go integrate Qovery Preview Environments with your CI and much more? Check out our the following guides:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/qovery/lifecycle-job-examples/tree/main/examples/seed-postgres-database-with-sql-script"}),"Seed your Preview Environment database")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/integration/continuous-integration/"}),"Integrate your CI platform")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/environment/#deployment-rule"}),"Auto-stop and start your Preview Environment")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/guides/tutorial/customizing-preview-url-with-qovery-cli/"}),"Set up a custom domain for your Preview Environment"))),Object(i.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(i.b)("p",null,"Congrats! You have set up your Preview Environments features. Feel free to check out our ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"forum")," and open a thread if you have any question. In the next guide, we will go deeper configuration to integrate the Preview Environment with your existing products and workflow."))}m.isMDXComponent=!0},424:function(e,t,n){"use strict";n(426);var a=n(0),r=n.n(a),i=n(423),o=n.n(i);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,i=e.icon,l=e.type,c=null;switch(l){case"danger":c="alert-triangle";break;case"success":c="check-circle";break;case"warning":c="alert-triangle";break;default:c="info"}return r.a.createElement("div",{className:o()(n,"alert","alert--"+l,{"alert--fill":a,"alert--icon":!1!==i}),role:"alert"},!1!==i&&r.a.createElement("i",{className:o()("feather","icon-"+(i||c))}),t)}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),i=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},437:function(e,t,n){"use strict";var a=n(1),r=(n(442),n(439),n(52),n(29),n(22),n(21),n(0)),i=n.n(r),o=n(449),l=n(423),c=n.n(l),b=n(433),s=n.n(b),u=n(448),m=37,p=39;function d(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,r=e.className,o=e.handleKeydown,l=e.style,b=e.values,s=e.selectedValue,u=e.tabRefs;return i.a.createElement("div",{className:n?"tabs--centered":null},i.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:c()("tabs",r,{"tabs--block":t}),style:l},b.map((function(e){var t=e.value,n=e.label;return i.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":s===t,className:c()("tab-item",{"tab-item--active":s===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return o(u,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function v(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,r=e.size,l=e.values,c=l;if(c[0].group){var b=_.groupBy(c,"group");c=Object.keys(b).map((function(e){return{label:e,options:b[e]}}))}return i.a.createElement(o.a,{className:"react-select-container react-select--"+r,classNamePrefix:"react-select",options:c,isClearable:n,placeholder:t,value:l.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,o=e.groupId,l=e.label,c=e.placeholder,b=e.select,h=e.size,f=(e.style,e.values),g=e.urlKey,w=Object(u.a)(),y=w.tabGroupChoices,j=w.setTabGroupChoices,O=Object(r.useState)(n),N=O[0],E=O[1];if(null!=o){var k=y[o];null!=k&&k!==N&&E(k)}var C=function(e){E(e),null!=o&&j(o,e)},P=[],x=function(e,t,n){switch(n.keyCode){case p:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case m:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(r.useEffect)((function(){if("undefined"!=typeof window&&window.location&&g){var e=s.a.parse(window.location.search);e[g]&&E(e[g])}}),[]),i.a.createElement(i.a.Fragment,null,i.a.createElement("div",{className:"margin-bottom--"+(h||"md")},l&&i.a.createElement("div",{className:"margin-vert--sm"},l),f.length>1&&(b?i.a.createElement(v,Object(a.a)({changeSelectedValue:C,handleKeydown:x,placeholder:c,selectedValue:N,size:h,tabRefs:P},e)):i.a.createElement(d,Object(a.a)({changeSelectedValue:C,handleKeydown:x,selectedValue:N,tabRefs:P},e)))),r.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}}}]); \ No newline at end of file diff --git a/410a9ba0.01abc0b5.js b/1a6d3985.2998ed19.js similarity index 94% rename from 410a9ba0.01abc0b5.js rename to 1a6d3985.2998ed19.js index ad65c55918..b49bf5ea0a 100644 --- a/410a9ba0.01abc0b5.js +++ b/1a6d3985.2998ed19.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[72],{224:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var a=n(1),o=n(9),r=(n(0),n(422)),i=n(421),l=(n(434),n(426)),c={last_modified_on:"2022-07-25",$schema:"/.meta/.schemas/guides.json",title:"Create your Staging environment from your Production environment on AWS",description:"Step-by-step guide to create your Staging environment from your Production environment on AWS",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Create your Staging environment from your Production environment on AWS",description:"Step-by-step guide to create your Staging environment from your Production environment on AWS",permalink:"/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws",readingTime:"4 min read",source:"@site/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Create your Staging environment from your Production environment on AWS",truncated:!1,prevItem:{title:"Create a Playground Environment on AWS",permalink:"/guides/tutorial/create-a-playground-environment-on-aws"},nextItem:{title:"Creating API clients using OpenAPI Tools",permalink:"/guides/tutorial/generate-qovery-api-client"}},u=[{value:"Create a Staging cluster",id:"create-a-staging-cluster",children:[]},{value:"Create your Staging environment from your Production environment",id:"create-your-staging-environment-from-your-production-environment",children:[]},{value:"Update your Staging applications",id:"update-your-staging-applications",children:[]},{value:"Override your environment variables and secrets",id:"override-your-environment-variables-and-secrets",children:[]},{value:"Deploy your Staging environment",id:"deploy-your-staging-environment",children:[]},{value:"Wrapping up",id:"wrapping-up",children:[]}],b={rightToc:u};function d(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Let's say you have your production environment deployed, and you want to create a staging environment. You have two options:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Create a staging environment from scratch."),Object(r.b)("li",{parentName:"ol"},"Clone your production environment and create a staging environment from it.")),Object(r.b)("p",null,"This is where the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#clone-environment"}),"Environment Clone")," feature of Qovery is useful. No need to create a new environment, just clone your production environment and create a staging environment from it."),Object(r.b)("p",null,"In this guide, we will go through the steps to create a staging environment from your production environment. While applying the best practices by isolating the staging and production environments on two separated clusters and VPCs."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/staging-from-production/complete_schema.jpg",alt:"Complete Production and Staging infrastructure"})),Object(r.b)(l.a,{mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You already have a production environment deployed with Qovery."))),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/5a76704a196341deb5384b2883113adf",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"create-a-staging-cluster"},"Create a Staging cluster"),Object(r.b)("p",null,"Isolating the staging and production environments on two separate clusters and VPCs is a good practice to avoid any potential issues on your production caused by your staging. This is not a mandatory step, but it is well recommended."),Object(r.b)("p",null,"To create your staging cluster it's also recommended creating a new AWS IAM access key and secret access key in a dedicated subaccount. Then you are sure that both environment are also isolated at the AWS level:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Go to your Organization cluster settings"),Object(r.b)("li",{parentName:"ol"},'Add a cluster with a name "staging"'),Object(r.b)("li",{parentName:"ol"},"Deploy your staging cluster")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/6f77172ae27f41a5a7c0e3114398b13c",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"create-your-staging-environment-from-your-production-environment"},"Create your Staging environment from your Production environment"),Object(r.b)("p",null,"Now, to create your staging environment from your production environment, you need to:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},'Go inside your production environment and click on the "Clone" button.'),Object(r.b)("li",{parentName:"ol"},'Give a name to your staging environment (E.g "staging")'),Object(r.b)("li",{parentName:"ol"},'Set the mode to "Staging"'),Object(r.b)("li",{parentName:"ol"},'Set the cluster to "staging"'),Object(r.b)("li",{parentName:"ol"},'Click on "Create"'),Object(r.b)("li",{parentName:"ol"},"That's it!")),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Cloning your database does not copy the data (yet). To copy your data in Staging consider using ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.replibyte.com"}),"Replibyte")," in standalone. It will be integrated in Qovery soon.")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/614844644cc34211853de19dafe79343",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Your environment has been created, but it's not deployed yet. Before we will make some adjustment to change the branch of our applications."),Object(r.b)("h2",{id:"update-your-staging-applications"},"Update your Staging applications"),Object(r.b)("p",null,"Your Staging applications have the same branch as your Production applications. To update your Staging applications branch, you need to:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Go into the settings of each of your applications."),Object(r.b)("li",{parentName:"ol"},"Update the branch to your Staging branch."),Object(r.b)("li",{parentName:"ol"},'Click on "Save"')),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/2f4f2a22062a4840ae077285a891e573",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"We are almost done, now we need to smartly change our environment variables and secrets to not use the one used in production."),Object(r.b)("h2",{id:"override-your-environment-variables-and-secrets"},"Override your environment variables and secrets"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Qovery makes the distinction between ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Environment Variables")," and ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Secrets")," even if for your app both will be used as Environment Variables. Check out ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"this documentation")," to learn more about Environment Variables and Secrets.")),Object(r.b)("p",null,"Let's say you have a production environment with the following environment variables:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"NODE_ENV=production"),Object(r.b)("li",{parentName:"ul"},"STRIPE_API_KEY=a-secret-production-key")),Object(r.b)("p",null,"You might need to keep the same keys but change the values. That's exactly what Qovery makes you do with the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#override-environment-variable"}),"Environment Variable Override feature"),". You can keep the same keys but change the values."),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/3d5d37dd9a954500aa559afead5b3981",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"deploy-your-staging-environment"},"Deploy your Staging environment"),Object(r.b)("p",null,'Finally, your Staging environment has been created and set up correctly. To deploy your Staging environment, you just need to go to your Staging environment and click on the "Deploy" button.'),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/04709bb4039447c699477ce01a1aa19b",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(r.b)("p",null,"In this guide, we have covered everything you need to know to create a secure staging environment from your production. Now, you can take a look at ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/data-seeding-in-postgres/"}),"how to seed your Staging database")," (Guide for Postgres but applicable for most databases)."))}d.isMDXComponent=!0},421:function(e,t,n){"use strict";n(423);var a=n(0),o=n.n(a),r=n(420),i=n.n(r);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,r=e.icon,l=e.type,c=null;switch(l){case"danger":c="alert-triangle";break;case"success":c="check-circle";break;case"warning":c="alert-triangle";break;default:c="info"}return o.a.createElement("div",{className:i()(n,"alert","alert--"+l,{"alert--fill":a,"alert--icon":!1!==r}),role:"alert"},!1!==r&&o.a.createElement("i",{className:i()("feather","icon-"+(r||c))}),t)}},425:function(e,t,n){var a=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&a(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),o=n.n(a),r=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},434:function(e,t,n){"use strict";var a=n(1),o=(n(439),n(436),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(446),l=n(420),c=n.n(l),s=n(428),u=n.n(s),b=n(445),d=37,m=39;function p(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,o=e.className,i=e.handleKeydown,l=e.style,s=e.values,u=e.selectedValue,b=e.tabRefs;return r.a.createElement("div",{className:n?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:c()("tabs",o,{"tabs--block":t}),style:l},s.map((function(e){var t=e.value,n=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":u===t,className:c()("tab-item",{"tab-item--active":u===t}),key:t,ref:function(e){return b.push(e)},onKeyDown:function(e){return i(b,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function g(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,o=e.size,l=e.values,c=l;if(c[0].group){var s=_.groupBy(c,"group");c=Object.keys(s).map((function(e){return{label:e,options:s[e]}}))}return r.a.createElement(i.a,{className:"react-select-container react-select--"+o,classNamePrefix:"react-select",options:c,isClearable:n,placeholder:t,value:l.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,i=e.groupId,l=e.label,c=e.placeholder,s=e.select,v=e.size,h=(e.style,e.values),y=e.urlKey,f=Object(b.a)(),w=f.tabGroupChoices,O=f.setTabGroupChoices,j=Object(o.useState)(n),k=j[0],S=j[1];if(null!=i){var N=w[i];null!=N&&N!==k&&S(N)}var C=function(e){S(e),null!=i&&O(i,e)},E=[],T=function(e,t,n){switch(n.keyCode){case m:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case d:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(o.useEffect)((function(){if("undefined"!=typeof window&&window.location&&y){var e=u.a.parse(window.location.search);e[y]&&S(e[y])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(v||"md")},l&&r.a.createElement("div",{className:"margin-vert--sm"},l),h.length>1&&(s?r.a.createElement(g,Object(a.a)({changeSelectedValue:C,handleKeydown:T,placeholder:c,selectedValue:k,size:v,tabRefs:E},e)):r.a.createElement(p,Object(a.a)({changeSelectedValue:C,handleKeydown:T,selectedValue:k,tabRefs:E},e)))),o.Children.toArray(t).filter((function(e){return e.props.value===k}))[0])}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[32],{181:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var a=n(1),o=n(9),r=(n(0),n(425)),i=n(424),l=(n(437),n(429)),c={last_modified_on:"2022-07-25",$schema:"/.meta/.schemas/guides.json",title:"Create your Staging environment from your Production environment on AWS",description:"Step-by-step guide to create your Staging environment from your Production environment on AWS",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Create your Staging environment from your Production environment on AWS",description:"Step-by-step guide to create your Staging environment from your Production environment on AWS",permalink:"/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws",readingTime:"4 min read",source:"@site/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Create your Staging environment from your Production environment on AWS",truncated:!1,prevItem:{title:"Create a Playground Environment on AWS",permalink:"/guides/tutorial/create-a-playground-environment-on-aws"},nextItem:{title:"Creating API clients using OpenAPI Tools",permalink:"/guides/tutorial/generate-qovery-api-client"}},u=[{value:"Create a Staging cluster",id:"create-a-staging-cluster",children:[]},{value:"Create your Staging environment from your Production environment",id:"create-your-staging-environment-from-your-production-environment",children:[]},{value:"Update your Staging applications",id:"update-your-staging-applications",children:[]},{value:"Override your environment variables and secrets",id:"override-your-environment-variables-and-secrets",children:[]},{value:"Deploy your Staging environment",id:"deploy-your-staging-environment",children:[]},{value:"Wrapping up",id:"wrapping-up",children:[]}],b={rightToc:u};function d(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Let's say you have your production environment deployed, and you want to create a staging environment. You have two options:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Create a staging environment from scratch."),Object(r.b)("li",{parentName:"ol"},"Clone your production environment and create a staging environment from it.")),Object(r.b)("p",null,"This is where the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#clone-environment"}),"Environment Clone")," feature of Qovery is useful. No need to create a new environment, just clone your production environment and create a staging environment from it."),Object(r.b)("p",null,"In this guide, we will go through the steps to create a staging environment from your production environment. While applying the best practices by isolating the staging and production environments on two separated clusters and VPCs."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/staging-from-production/complete_schema.jpg",alt:"Complete Production and Staging infrastructure"})),Object(r.b)(l.a,{mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You already have a production environment deployed with Qovery."))),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/5a76704a196341deb5384b2883113adf",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"create-a-staging-cluster"},"Create a Staging cluster"),Object(r.b)("p",null,"Isolating the staging and production environments on two separate clusters and VPCs is a good practice to avoid any potential issues on your production caused by your staging. This is not a mandatory step, but it is well recommended."),Object(r.b)("p",null,"To create your staging cluster it's also recommended creating a new AWS IAM access key and secret access key in a dedicated subaccount. Then you are sure that both environment are also isolated at the AWS level:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Go to your Organization cluster settings"),Object(r.b)("li",{parentName:"ol"},'Add a cluster with a name "staging"'),Object(r.b)("li",{parentName:"ol"},"Deploy your staging cluster")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/6f77172ae27f41a5a7c0e3114398b13c",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"create-your-staging-environment-from-your-production-environment"},"Create your Staging environment from your Production environment"),Object(r.b)("p",null,"Now, to create your staging environment from your production environment, you need to:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},'Go inside your production environment and click on the "Clone" button.'),Object(r.b)("li",{parentName:"ol"},'Give a name to your staging environment (E.g "staging")'),Object(r.b)("li",{parentName:"ol"},'Set the mode to "Staging"'),Object(r.b)("li",{parentName:"ol"},'Set the cluster to "staging"'),Object(r.b)("li",{parentName:"ol"},'Click on "Create"'),Object(r.b)("li",{parentName:"ol"},"That's it!")),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Cloning your database does not copy the data (yet). To copy your data in Staging consider using ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.replibyte.com"}),"Replibyte")," in standalone. It will be integrated in Qovery soon.")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/614844644cc34211853de19dafe79343",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Your environment has been created, but it's not deployed yet. Before we will make some adjustment to change the branch of our applications."),Object(r.b)("h2",{id:"update-your-staging-applications"},"Update your Staging applications"),Object(r.b)("p",null,"Your Staging applications have the same branch as your Production applications. To update your Staging applications branch, you need to:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Go into the settings of each of your applications."),Object(r.b)("li",{parentName:"ol"},"Update the branch to your Staging branch."),Object(r.b)("li",{parentName:"ol"},'Click on "Save"')),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/2f4f2a22062a4840ae077285a891e573",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"We are almost done, now we need to smartly change our environment variables and secrets to not use the one used in production."),Object(r.b)("h2",{id:"override-your-environment-variables-and-secrets"},"Override your environment variables and secrets"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Qovery makes the distinction between ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Environment Variables")," and ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Secrets")," even if for your app both will be used as Environment Variables. Check out ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"this documentation")," to learn more about Environment Variables and Secrets.")),Object(r.b)("p",null,"Let's say you have a production environment with the following environment variables:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"NODE_ENV=production"),Object(r.b)("li",{parentName:"ul"},"STRIPE_API_KEY=a-secret-production-key")),Object(r.b)("p",null,"You might need to keep the same keys but change the values. That's exactly what Qovery makes you do with the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#override-environment-variable"}),"Environment Variable Override feature"),". You can keep the same keys but change the values."),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/3d5d37dd9a954500aa559afead5b3981",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"deploy-your-staging-environment"},"Deploy your Staging environment"),Object(r.b)("p",null,'Finally, your Staging environment has been created and set up correctly. To deploy your Staging environment, you just need to go to your Staging environment and click on the "Deploy" button.'),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/04709bb4039447c699477ce01a1aa19b",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(r.b)("p",null,"In this guide, we have covered everything you need to know to create a secure staging environment from your production. Now, you can take a look at ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/data-seeding-in-postgres/"}),"how to seed your Staging database")," (Guide for Postgres but applicable for most databases)."))}d.isMDXComponent=!0},424:function(e,t,n){"use strict";n(426);var a=n(0),o=n.n(a),r=n(423),i=n.n(r);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,r=e.icon,l=e.type,c=null;switch(l){case"danger":c="alert-triangle";break;case"success":c="check-circle";break;case"warning":c="alert-triangle";break;default:c="info"}return o.a.createElement("div",{className:i()(n,"alert","alert--"+l,{"alert--fill":a,"alert--icon":!1!==r}),role:"alert"},!1!==r&&o.a.createElement("i",{className:i()("feather","icon-"+(r||c))}),t)}},428:function(e,t,n){var a=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&a(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),o=n.n(a),r=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},437:function(e,t,n){"use strict";var a=n(1),o=(n(442),n(439),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(449),l=n(423),c=n.n(l),s=n(433),u=n.n(s),b=n(448),d=37,m=39;function p(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,o=e.className,i=e.handleKeydown,l=e.style,s=e.values,u=e.selectedValue,b=e.tabRefs;return r.a.createElement("div",{className:n?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:c()("tabs",o,{"tabs--block":t}),style:l},s.map((function(e){var t=e.value,n=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":u===t,className:c()("tab-item",{"tab-item--active":u===t}),key:t,ref:function(e){return b.push(e)},onKeyDown:function(e){return i(b,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function g(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,o=e.size,l=e.values,c=l;if(c[0].group){var s=_.groupBy(c,"group");c=Object.keys(s).map((function(e){return{label:e,options:s[e]}}))}return r.a.createElement(i.a,{className:"react-select-container react-select--"+o,classNamePrefix:"react-select",options:c,isClearable:n,placeholder:t,value:l.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,i=e.groupId,l=e.label,c=e.placeholder,s=e.select,v=e.size,h=(e.style,e.values),y=e.urlKey,f=Object(b.a)(),w=f.tabGroupChoices,O=f.setTabGroupChoices,j=Object(o.useState)(n),k=j[0],S=j[1];if(null!=i){var N=w[i];null!=N&&N!==k&&S(N)}var C=function(e){S(e),null!=i&&O(i,e)},E=[],T=function(e,t,n){switch(n.keyCode){case m:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case d:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(o.useEffect)((function(){if("undefined"!=typeof window&&window.location&&y){var e=u.a.parse(window.location.search);e[y]&&S(e[y])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(v||"md")},l&&r.a.createElement("div",{className:"margin-vert--sm"},l),h.length>1&&(s?r.a.createElement(g,Object(a.a)({changeSelectedValue:C,handleKeydown:T,placeholder:c,selectedValue:k,size:v,tabRefs:E},e)):r.a.createElement(p,Object(a.a)({changeSelectedValue:C,handleKeydown:T,selectedValue:k,tabRefs:E},e)))),o.Children.toArray(t).filter((function(e){return e.props.value===k}))[0])}}}]); \ No newline at end of file diff --git a/1aa86e56.eeb01a2a.js b/1aa86e56.3f6bf0d5.js similarity index 95% rename from 1aa86e56.eeb01a2a.js rename to 1aa86e56.3f6bf0d5.js index 485810c169..4aa755de7d 100644 --- a/1aa86e56.eeb01a2a.js +++ b/1aa86e56.3f6bf0d5.js @@ -1,2 +1,2 @@ -/*! For license information please see 1aa86e56.eeb01a2a.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[32],{181:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return c})),t.d(n,"metadata",(function(){return l})),t.d(n,"rightToc",(function(){return p})),t.d(n,"default",(function(){return m}));var o=t(1),r=t(9),a=(t(0),t(422)),i=t(421),c={last_modified_on:"2023-09-27",title:"Circle CI",description:"Learn how to connect Circle CI to Qovery"},l={id:"using-qovery/integration/continuous-integration/circle-ci",title:"Circle CI",description:"Learn how to connect Circle CI to Qovery",source:"@site/docs/using-qovery/integration/continuous-integration/circle-ci.md",permalink:"/docs/using-qovery/integration/continuous-integration/circle-ci",sidebar:"docs",previous:{title:"GitLab CI",permalink:"/docs/using-qovery/integration/continuous-integration/gitlab-ci"},next:{title:"Jenkins",permalink:"/docs/using-qovery/integration/continuous-integration/jenkins"}},p=[{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Jenkins Examples",id:"jenkins-examples",children:[]},{value:"Qovery CLI command examples",id:"qovery-cli-command-examples",children:[{value:"Deploy your application with a specific commit ID",id:"deploy-your-application-with-a-specific-commit-id",children:[]},{value:"Deploy your multiple applications with a different commit ID",id:"deploy-your-multiple-applications-with-a-different-commit-id",children:[]},{value:"Deploy your multiple applications with a specific commit ID (monorepo)",id:"deploy-your-multiple-applications-with-a-specific-commit-id-monorepo",children:[]},{value:"Create a Preview Environment for your Pull-Request",id:"create-a-preview-environment-for-your-pull-request",children:[]},{value:"Delete a Preview Environment",id:"delete-a-preview-environment",children:[]},{value:"Terraform",id:"terraform",children:[]},{value:"Any other examples?",id:"any-other-examples",children:[]}]}],u={rightToc:p};function m(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},u,t,{components:n,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Using Circle CI with Qovery is super powerful and gives you the ability to manage the way that you want to deploy your applications. As the possibility are endless, I will share with you a couple of examples that you can use. Feel free to adapt them to your need."),Object(a.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(a.b)("p",null,"Before using the examples below, you need to:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Install the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI"),"."),Object(a.b)("li",{parentName:"ol"},"Generate an API token via ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/#generate-api-token"}),"the CLI")," or the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/api-token/"}),"Console")," ."),Object(a.b)("li",{parentName:"ol"},"Set the environment variable ",Object(a.b)("inlineCode",{parentName:"li"},"Q_CLI_ACCESS_TOKEN")," or ",Object(a.b)("inlineCode",{parentName:"li"},"QOVERY_CLI_ACCESS_TOKEN")," (both are valid) with your API token. E.g. ",Object(a.b)("inlineCode",{parentName:"li"},"export QOVERY_CLI_ACCESS_TOKEN=your-api-token")),Object(a.b)("li",{parentName:"ol"},"You have turned off the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Qovery Auto Deployment")," for every service that you want to deploy manually.")),Object(a.b)("h2",{id:"jenkins-examples"},"Jenkins Examples"),Object(a.b)("p",null,"Since Circle CI also provides a .yaml file to configure your pipeline. Refers to ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/gitlab-ci/#gitlab-ci-examples"}),"GitLab CI")," and ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/#github-actions-examples"}),"GitHub Actions")," examples to learn how to configure your pipeline with Qovery."),Object(a.b)("h2",{id:"qovery-cli-command-examples"},"Qovery CLI command examples"),Object(a.b)("h3",{id:"deploy-your-application-with-a-specific-commit-id"},"Deploy your application with a specific commit ID"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"qovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n")),Object(a.b)(i.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,Object(a.b)("inlineCode",{parentName:"p"},"--watch")," is an optional parameter that will display the status of the deployment and return 0 if the deployment is successful or 1 if it fails.")),Object(a.b)("h3",{id:"deploy-your-multiple-applications-with-a-different-commit-id"},"Deploy your multiple applications with a different commit ID"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"# deploy the application 1 and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n\n# deploy the application 2 and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n")),Object(a.b)("p",null,"This is also applicable for the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery container deploy"),", ",Object(a.b)("inlineCode",{parentName:"p"},"qovery lifecycle deploy"),", and ",Object(a.b)("inlineCode",{parentName:"p"},"qovery cronjob deploy")," commands."),Object(a.b)("h3",{id:"deploy-your-multiple-applications-with-a-specific-commit-id-monorepo"},"Deploy your multiple applications with a specific commit ID (monorepo)"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),'# deploy the application 1, 2 and 3 with the same commit ID and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --applications ", , " \\\n --commit-id \\\n --watch\n')),Object(a.b)("p",null,"This is also applicable for the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery container deploy"),", ",Object(a.b)("inlineCode",{parentName:"p"},"qovery lifecycle deploy"),", and ",Object(a.b)("inlineCode",{parentName:"p"},"qovery cronjob deploy")," commands."),Object(a.b)("h3",{id:"create-a-preview-environment-for-your-pull-request"},"Create a Preview Environment for your Pull-Request"),Object(a.b)("p",null,"Qovery integrates automatically with GitHub, GitLab and Bitbucket to create a Preview Environment for each Pull-Request. But in case you want to control the creation of the Preview Environment manually, you can use the following commands:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"# Clone your base environment\nqovery environment clone \\\n --organization \\\n --project \\\n --environment \\\n --new-environment-name \n\n# Change your application branch to the Pull-Request branch\nqovery application update \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --branch \n\n# Deploy your new environment\nqovery environment deploy \\\n --organization \\\n --project \\\n --environment \\\n --watch\n")),Object(a.b)("h3",{id:"delete-a-preview-environment"},"Delete a Preview Environment"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"qovery environment delete \\\n --organization \\\n --project \\\n --environment \\\n --watch\n")),Object(a.b)("h3",{id:"terraform"},"Terraform"),Object(a.b)("p",null,"Do you want to include Terraform in your CI? Check out our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"Terraform documentation"),"."),Object(a.b)("h3",{id:"any-other-examples"},"Any other examples?"),Object(a.b)("p",null,"Feel free to share your examples with us, and we'll be happy to share them with the community. Contact us on ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum"),"."))}m.isMDXComponent=!0},420:function(e,n,t){var o;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var p=r.a.createContext({}),u=function(e){var n=r.a.useContext(p),t=n;return e&&(t="function"==typeof e?e(n):c({},n,{},e)),t},m=function(e){var n=u(e.components);return r.a.createElement(p.Provider,{value:n},e.children)},s={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},y=Object(o.forwardRef)((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),m=u(t),y=o,b=m["".concat(i,".").concat(y)]||m[y]||s[y]||a;return t?r.a.createElement(b,c({ref:n},p,{components:t})):r.a.createElement(b,c({ref:n},p))}));function b(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=y;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var p=2;p1?arguments[1]:void 0,t),l=i>2?arguments[2]:void 0,p=void 0===l?t:r(l,t);p>c;)n[c++]=e;return n}}}]); \ No newline at end of file +/*! For license information please see 1aa86e56.3f6bf0d5.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[33],{182:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return c})),t.d(n,"metadata",(function(){return l})),t.d(n,"rightToc",(function(){return p})),t.d(n,"default",(function(){return m}));var o=t(1),r=t(9),a=(t(0),t(425)),i=t(424),c={last_modified_on:"2023-09-27",title:"Circle CI",description:"Learn how to connect Circle CI to Qovery"},l={id:"using-qovery/integration/continuous-integration/circle-ci",title:"Circle CI",description:"Learn how to connect Circle CI to Qovery",source:"@site/docs/using-qovery/integration/continuous-integration/circle-ci.md",permalink:"/docs/using-qovery/integration/continuous-integration/circle-ci",sidebar:"docs",previous:{title:"GitLab CI",permalink:"/docs/using-qovery/integration/continuous-integration/gitlab-ci"},next:{title:"Jenkins",permalink:"/docs/using-qovery/integration/continuous-integration/jenkins"}},p=[{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Jenkins Examples",id:"jenkins-examples",children:[]},{value:"Qovery CLI command examples",id:"qovery-cli-command-examples",children:[{value:"Deploy your application with a specific commit ID",id:"deploy-your-application-with-a-specific-commit-id",children:[]},{value:"Deploy your multiple applications with a different commit ID",id:"deploy-your-multiple-applications-with-a-different-commit-id",children:[]},{value:"Deploy your multiple applications with a specific commit ID (monorepo)",id:"deploy-your-multiple-applications-with-a-specific-commit-id-monorepo",children:[]},{value:"Create a Preview Environment for your Pull-Request",id:"create-a-preview-environment-for-your-pull-request",children:[]},{value:"Delete a Preview Environment",id:"delete-a-preview-environment",children:[]},{value:"Terraform",id:"terraform",children:[]},{value:"Any other examples?",id:"any-other-examples",children:[]}]}],u={rightToc:p};function m(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},u,t,{components:n,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Using Circle CI with Qovery is super powerful and gives you the ability to manage the way that you want to deploy your applications. As the possibility are endless, I will share with you a couple of examples that you can use. Feel free to adapt them to your need."),Object(a.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(a.b)("p",null,"Before using the examples below, you need to:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Install the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI"),"."),Object(a.b)("li",{parentName:"ol"},"Generate an API token via ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/#generate-api-token"}),"the CLI")," or the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/api-token/"}),"Console")," ."),Object(a.b)("li",{parentName:"ol"},"Set the environment variable ",Object(a.b)("inlineCode",{parentName:"li"},"Q_CLI_ACCESS_TOKEN")," or ",Object(a.b)("inlineCode",{parentName:"li"},"QOVERY_CLI_ACCESS_TOKEN")," (both are valid) with your API token. E.g. ",Object(a.b)("inlineCode",{parentName:"li"},"export QOVERY_CLI_ACCESS_TOKEN=your-api-token")),Object(a.b)("li",{parentName:"ol"},"You have turned off the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Qovery Auto Deployment")," for every service that you want to deploy manually.")),Object(a.b)("h2",{id:"jenkins-examples"},"Jenkins Examples"),Object(a.b)("p",null,"Since Circle CI also provides a .yaml file to configure your pipeline. Refers to ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/gitlab-ci/#gitlab-ci-examples"}),"GitLab CI")," and ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/#github-actions-examples"}),"GitHub Actions")," examples to learn how to configure your pipeline with Qovery."),Object(a.b)("h2",{id:"qovery-cli-command-examples"},"Qovery CLI command examples"),Object(a.b)("h3",{id:"deploy-your-application-with-a-specific-commit-id"},"Deploy your application with a specific commit ID"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"qovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n")),Object(a.b)(i.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,Object(a.b)("inlineCode",{parentName:"p"},"--watch")," is an optional parameter that will display the status of the deployment and return 0 if the deployment is successful or 1 if it fails.")),Object(a.b)("h3",{id:"deploy-your-multiple-applications-with-a-different-commit-id"},"Deploy your multiple applications with a different commit ID"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"# deploy the application 1 and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n\n# deploy the application 2 and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n")),Object(a.b)("p",null,"This is also applicable for the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery container deploy"),", ",Object(a.b)("inlineCode",{parentName:"p"},"qovery lifecycle deploy"),", and ",Object(a.b)("inlineCode",{parentName:"p"},"qovery cronjob deploy")," commands."),Object(a.b)("h3",{id:"deploy-your-multiple-applications-with-a-specific-commit-id-monorepo"},"Deploy your multiple applications with a specific commit ID (monorepo)"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),'# deploy the application 1, 2 and 3 with the same commit ID and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --applications ", , " \\\n --commit-id \\\n --watch\n')),Object(a.b)("p",null,"This is also applicable for the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery container deploy"),", ",Object(a.b)("inlineCode",{parentName:"p"},"qovery lifecycle deploy"),", and ",Object(a.b)("inlineCode",{parentName:"p"},"qovery cronjob deploy")," commands."),Object(a.b)("h3",{id:"create-a-preview-environment-for-your-pull-request"},"Create a Preview Environment for your Pull-Request"),Object(a.b)("p",null,"Qovery integrates automatically with GitHub, GitLab and Bitbucket to create a Preview Environment for each Pull-Request. But in case you want to control the creation of the Preview Environment manually, you can use the following commands:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"# Clone your base environment\nqovery environment clone \\\n --organization \\\n --project \\\n --environment \\\n --new-environment-name \n\n# Change your application branch to the Pull-Request branch\nqovery application update \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --branch \n\n# Deploy your new environment\nqovery environment deploy \\\n --organization \\\n --project \\\n --environment \\\n --watch\n")),Object(a.b)("h3",{id:"delete-a-preview-environment"},"Delete a Preview Environment"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"qovery environment delete \\\n --organization \\\n --project \\\n --environment \\\n --watch\n")),Object(a.b)("h3",{id:"terraform"},"Terraform"),Object(a.b)("p",null,"Do you want to include Terraform in your CI? Check out our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"Terraform documentation"),"."),Object(a.b)("h3",{id:"any-other-examples"},"Any other examples?"),Object(a.b)("p",null,"Feel free to share your examples with us, and we'll be happy to share them with the community. Contact us on ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum"),"."))}m.isMDXComponent=!0},423:function(e,n,t){var o;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var p=r.a.createContext({}),u=function(e){var n=r.a.useContext(p),t=n;return e&&(t="function"==typeof e?e(n):c({},n,{},e)),t},m=function(e){var n=u(e.components);return r.a.createElement(p.Provider,{value:n},e.children)},s={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},y=Object(o.forwardRef)((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),m=u(t),y=o,b=m["".concat(i,".").concat(y)]||m[y]||s[y]||a;return t?r.a.createElement(b,c({ref:n},p,{components:t})):r.a.createElement(b,c({ref:n},p))}));function b(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=y;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var p=2;p1?arguments[1]:void 0,t),l=i>2?arguments[2]:void 0,p=void 0===l?t:r(l,t);p>c;)n[c++]=e;return n}}}]); \ No newline at end of file diff --git a/1b633bfd.d827d5b6.js.LICENSE.txt b/1aa86e56.3f6bf0d5.js.LICENSE.txt similarity index 100% rename from 1b633bfd.d827d5b6.js.LICENSE.txt rename to 1aa86e56.3f6bf0d5.js.LICENSE.txt diff --git a/06e8d299.1138c19d.js b/1b633bfd.bfb64824.js similarity index 82% rename from 06e8d299.1138c19d.js rename to 1b633bfd.bfb64824.js index dfa82b43ad..6a8e14b34e 100644 --- a/06e8d299.1138c19d.js +++ b/1b633bfd.bfb64824.js @@ -1,2 +1,2 @@ -/*! For license information please see 06e8d299.1138c19d.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{158:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var o=n(1),r=n(9),a=(n(0),n(422)),c=n(431),i=(n(421),n(426)),l=(n(429),{last_modified_on:"2023-10-12",$schema:"/.meta/.schemas/guides.json",title:"How to activate SSO to connect to your EKS cluster",description:"How to activate SSO to connect to your EKS cluster",author_github:"https://github.com/benjaminch",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to activate SSO to connect to your EKS cluster",description:"How to activate SSO to connect to your EKS cluster",permalink:"/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster",readingTime:"6 min read",source:"@site/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to activate SSO to connect to your EKS cluster",truncated:!1,prevItem:{title:"Helm Charts",permalink:"/guides/advanced/helm-chart"},nextItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1"}},u=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],b={rightToc:u};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Qovery makes it easy to create an EKS cluster on your AWS account and manage the deployment of applications on it. But you still might want to execute operations on it via ",Object(a.b)("inlineCode",{parentName:"p"},"kubectl")," like you would on any other Kubernetes cluster.\nYou have several ways to connect to your cluster:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Activate IAM group sync, more on that ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"here")),Object(a.b)("li",{parentName:"ul"},"Activate SSO support on your cluster allowing users to connect using AWS SSO.")),Object(a.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have AWS CLI installed"),Object(a.b)("li",{parentName:"ul"},"You have configured an ",Object(a.b)("inlineCode",{parentName:"li"},"Admins")," group (or any group used for admins) as described in the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/cloud-provider/guide-amazon-web-services/"}),"Qovery AWS setup")),Object(a.b)("li",{parentName:"ul"},"You have an existing EKS cluster managed by Qovery"),Object(a.b)("li",{parentName:"ul"},"You have followed ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"https://aws.amazon.com/fr/blogs/containers/a-quick-path-to-amazon-eks-single-sign-on-using-aws-sso/"}),"this AWS tutorial")," up to ",Object(a.b)("inlineCode",{parentName:"li"},"AWS SSO user configuration")," excluded."))),Object(a.b)("h2",{id:"goal"},"Goal"),Object(a.b)("p",null,"This tutorial will show you how to access a Qovery managed cluster using AWS SSO."),Object(a.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"install-and-configure-your-toolchain"},"Install and configure your toolchain"),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"kubectl")),Object(a.b)("p",null,"To interact with your cluster, you will need ",Object(a.b)("inlineCode",{parentName:"p"},"kubectl")," installed.\n",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://kubernetes.io/docs/tasks/tools/"}),"https://kubernetes.io/docs/tasks/tools/")),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"AWS CLI")),Object(a.b)("p",null,"The AWS CLI must be installed and configured on your machine.\n",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"}),"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"select-iam-user-group-you-configured-for-qovery-as-admin"},"Select IAM user group you configured for Qovery as admin"),Object(a.b)("p",null,"In AWS console, go to ",Object(a.b)("inlineCode",{parentName:"p"},"IAM > User Groups")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/0-go-to-iam-user-groups.png",alt:"AWS console - go to user groups"})),Object(a.b)("p",null,"then select the group you configured as admin group for Qovery (",Object(a.b)("inlineCode",{parentName:"p"},"Admins")," in the example below)."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/1-select-admins-iam-user-group.png",alt:"AWS console - select admin user group"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"create-a-new-policy-to-this-group-allowing-full-access-to-eks-resources"},"Create a new policy to this group allowing full access to EKS resources"),Object(a.b)("p",null,"In this admin group, go to ",Object(a.b)("inlineCode",{parentName:"p"},"permissions")," tab. Click on ",Object(a.b)("inlineCode",{parentName:"p"},"Add permissions > Create inline policy"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/2-create-new-inline-policy-to-admin-user-group.png",alt:"AWS console - create new inline policy"})),Object(a.b)("p",null,"Switch to JSON view."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/3-inline-policy-creation-json-view.png",alt:"AWS console - switch to inline policy creation json view"})),Object(a.b)("p",null,"Put this content to the ",Object(a.b)("inlineCode",{parentName:"p"},"Policy editor"),":"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Effect": "Allow",\n "Action": [\n "eks:*",\n "sts:AssumeRole"\n ],\n "Resource": "*"\n }\n ]\n}\n')),Object(a.b)("p",null,"Then click on ",Object(a.b)("inlineCode",{parentName:"p"},"Next"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/4-edit-inline-policy-content.png",alt:"AWS console - edit inline policy content"})),Object(a.b)("p",null,"Give a name to this new policy, for example ",Object(a.b)("inlineCode",{parentName:"p"},"SSO_EKSClusterAdminAccess"),". Then click on ",Object(a.b)("inlineCode",{parentName:"p"},"Create Policy"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/5-create-inline-policy.png",alt:"AWS console - create inline policy"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"set-up-cli-with-sso-access-to-eks"},"Set up CLI with SSO access to EKS"),Object(a.b)("p",null,"Create a named SSO profile using AWS CLI."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"aws configure sso\n")),Object(a.b)("p",null,"You will be prompted an SSO session name, put what you want, I used ",Object(a.b)("inlineCode",{parentName:"p"},"sso-benjamin"),"."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"SSO session name (Recommended): sso-benjamin\nAttempting to automatically open the SSO authorization page in your default browser.\nIf the browser does not open or you wish to use a different device to authorize this request, open the following URL:\n\nhttps://device.sso.us-east-2.amazonaws.com/\n\nThen enter the code:\n\nFHTG-****\n")),Object(a.b)("p",null,"You will be redirected to your browser, validate the form."),Object(a.b)("p",null,"Then you will be prompted to select your AWS account."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"There are 1 AWS account available to you.\n> qovery, q@qovery.com (283389****)\n")),Object(a.b)("p",null,"Then you will be prompted for default region (",Object(a.b)("inlineCode",{parentName:"p"},"eu-west-3")," in my case), output format (",Object(a.b)("inlineCode",{parentName:"p"},"json")," in my case) and profile name (",Object(a.b)("inlineCode",{parentName:"p"},"bchastanier_sso")," in my case, but feel free to pick whatever you want)."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),'Using the account ID 283389****\nThe only role available to you is: AdministratorAccess\nUsing the role name "AdministratorAccess"\nCLI default client Region [None]: eu-west-3\nCLI default output format [None]: json\nCLI profile name: bchastanier_sso\n'))),Object(a.b)("li",null,Object(a.b)("h4",{id:"get-sso-role-arn"},"Get SSO role ARN"),Object(a.b)("p",null,"Go to AWS console > IAM > Roles."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/6-iam-roles.png",alt:"AWS console - go to aws iam roles"})),Object(a.b)("p",null,"Look for a role named ",Object(a.b)("inlineCode",{parentName:"p"},"AWSReservedSSO_xx")," and select it (name can varies based on what you have configured / how you named your ",Object(a.b)("inlineCode",{parentName:"p"},"Admins")," user group, but it should start with ",Object(a.b)("inlineCode",{parentName:"p"},"AWSReservedSSO_"),")."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/7-iam-roles-look-for-sso-role.png",alt:"AWS console - look for SSO role"})),Object(a.b)("p",null,"Copy its ARN and keep it somewhere, you will need it in next step."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/8-iam-roles-copy-arn.png",alt:"AWS console - copy SSO role ARN"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"enable-sso-on-your-cluster"},"Enable SSO on your cluster"),Object(a.b)("p",null,"Go to your clusters in Qovery console and click on cluster you want to activate SSO on settings."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/9-qovery-go-to-cluster-settings.png",alt:"AWS console - go to qovery cluster settings"})),Object(a.b)("p",null,"Then go to advanced settings, and set:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("inlineCode",{parentName:"li"},"aws.iam.enable_sso")," to ",Object(a.b)("inlineCode",{parentName:"li"},"true")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("inlineCode",{parentName:"li"},"aws.iam.sso_role_arn")," to the SSO role ARN string you copy from previous step.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/10-qovery-cluster-advanced-settings-enable-sso.png",alt:"AWS console - set qovery cluster advanced settings to enable SSO"})),Object(a.b)("p",null,"Redeploy your cluster once advanced settings are saved.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"download-the-kubeconfig-file"},"Download the Kubeconfig file"),Object(a.b)("p",null,"To connect to your EKS cluster you will need to set a context to ",Object(a.b)("inlineCode",{parentName:"p"},"kubectl"),". This is done with a ",Object(a.b)("inlineCode",{parentName:"p"},"Kubeconfig")," file."),Object(a.b)("p",null,"When installing a new cluster, Qovery stores it in an S3 bucket on your account."),Object(a.b)("p",null,"Go to S3, find the Qovery bucket, and download the file. The bucket should be named something like ",Object(a.b)("inlineCode",{parentName:"p"},"qovery-kubeconfigs-.yaml"),"."),Object(a.b)("p",null,"Set the context for kubectl, run the following command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"export KUBECONFIG=\n")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/11-get-cluster-kubeconfig.png",alt:"AWS console - get Kubeconfig"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"connect-to-your-cluster"},"Connect to your cluster"),Object(a.b)("p",null,"Connect via the CLI running this command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"aws sso login --profile \n")),Object(a.b)("p",null,"This will open your browser and prompt you to connect, validate the form."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/12-validate-sso-connection-in-browser.png",alt:"AWS console - validate SSO connection in browser"})),Object(a.b)("p",null,"Now you should be able to access your cluster without anything else, let's try to get ",Object(a.b)("inlineCode",{parentName:"p"},"aws-auth")," configmap showing users and roles allowed to connect to the cluster:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"AWS_PROFILE= kubectl describe -n kube-system configmap/aws-auth\n")),Object(a.b)("p",null,"This should give you the config map content. If not, something is not properly configured.")))),Object(a.b)("h2",{id:"conclusion"},"Conclusion"),Object(a.b)("p",null,"You can access your Qovery clusters via your SSO directly."))}p.isMDXComponent=!0},420:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),m=o,d=b["".concat(c,".").concat(m)]||b[m]||p[m]||a;return n?r.a.createElement(d,i({ref:t},s,{components:n})):r.a.createElement(d,i({ref:t},s))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,c=new Array(a);c[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var s=2;s1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>i;)t[i++]=e;return t}},425:function(e,t,n){var o=n(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var o=n(0),r=n.n(o),a=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var o=n(1),r=n(0),a=n.n(r),c=n(39),i=n(430),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,b=Object(i.a)(u),p=Object(r.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&b&&window.docusaurus.prefetch(u),function(){m&&t&&t.disconnect()}}),[u,m,b]),u&&b?a.a.createElement(c.b,Object(o.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,o;m&&e&&b&&(n=e,o=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:u})):a.a.createElement("a",Object(o.a)({},e,{href:u}))}},428:function(e,t,n){"use strict";var o=n(432),r=n(51);function a(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(r),a,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[a(t,e),"[",o,"]"].join(""):[a(t,e),"[",a(o,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return a(o,t);if(Array.isArray(r)){var c=[];return r.slice().forEach((function(e){void 0!==e&&c.push(n(o,e,c.length))})),c.join("&")}return a(o,t)+"="+a(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=n(427),c=n(420),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,c=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,b=e.to,p=i()("jump-to","jump-to--"+s,n),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},o?r.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:b,target:u,className:p},m):r.a.createElement(a.a,{to:b,className:p},m)}},430:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},431:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(420),n(428)),c=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),u=Object(o.useState)(null),b=u[0],p=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 1b633bfd.bfb64824.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[34],{183:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var o=n(1),r=n(9),a=(n(0),n(425)),c=n(434),i=(n(424),n(429)),l=(n(431),{last_modified_on:"2023-10-12",$schema:"/.meta/.schemas/guides.json",title:"How to activate SSO to connect to your EKS cluster",description:"How to activate SSO to connect to your EKS cluster",author_github:"https://github.com/benjaminch",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to activate SSO to connect to your EKS cluster",description:"How to activate SSO to connect to your EKS cluster",permalink:"/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster",readingTime:"6 min read",source:"@site/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to activate SSO to connect to your EKS cluster",truncated:!1,prevItem:{title:"Helm Charts",permalink:"/guides/advanced/helm-chart"},nextItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1"}},u=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],b={rightToc:u};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Qovery makes it easy to create an EKS cluster on your AWS account and manage the deployment of applications on it. But you still might want to execute operations on it via ",Object(a.b)("inlineCode",{parentName:"p"},"kubectl")," like you would on any other Kubernetes cluster.\nYou have several ways to connect to your cluster:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Activate IAM group sync, more on that ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"here")),Object(a.b)("li",{parentName:"ul"},"Activate SSO support on your cluster allowing users to connect using AWS SSO.")),Object(a.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have AWS CLI installed"),Object(a.b)("li",{parentName:"ul"},"You have configured an ",Object(a.b)("inlineCode",{parentName:"li"},"Admins")," group (or any group used for admins) as described in the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/cloud-provider/guide-amazon-web-services/"}),"Qovery AWS setup")),Object(a.b)("li",{parentName:"ul"},"You have an existing EKS cluster managed by Qovery"),Object(a.b)("li",{parentName:"ul"},"You have followed ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"https://aws.amazon.com/fr/blogs/containers/a-quick-path-to-amazon-eks-single-sign-on-using-aws-sso/"}),"this AWS tutorial")," up to ",Object(a.b)("inlineCode",{parentName:"li"},"AWS SSO user configuration")," excluded."))),Object(a.b)("h2",{id:"goal"},"Goal"),Object(a.b)("p",null,"This tutorial will show you how to access a Qovery managed cluster using AWS SSO."),Object(a.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"install-and-configure-your-toolchain"},"Install and configure your toolchain"),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"kubectl")),Object(a.b)("p",null,"To interact with your cluster, you will need ",Object(a.b)("inlineCode",{parentName:"p"},"kubectl")," installed.\n",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://kubernetes.io/docs/tasks/tools/"}),"https://kubernetes.io/docs/tasks/tools/")),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"AWS CLI")),Object(a.b)("p",null,"The AWS CLI must be installed and configured on your machine.\n",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"}),"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"select-iam-user-group-you-configured-for-qovery-as-admin"},"Select IAM user group you configured for Qovery as admin"),Object(a.b)("p",null,"In AWS console, go to ",Object(a.b)("inlineCode",{parentName:"p"},"IAM > User Groups")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/0-go-to-iam-user-groups.png",alt:"AWS console - go to user groups"})),Object(a.b)("p",null,"then select the group you configured as admin group for Qovery (",Object(a.b)("inlineCode",{parentName:"p"},"Admins")," in the example below)."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/1-select-admins-iam-user-group.png",alt:"AWS console - select admin user group"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"create-a-new-policy-to-this-group-allowing-full-access-to-eks-resources"},"Create a new policy to this group allowing full access to EKS resources"),Object(a.b)("p",null,"In this admin group, go to ",Object(a.b)("inlineCode",{parentName:"p"},"permissions")," tab. Click on ",Object(a.b)("inlineCode",{parentName:"p"},"Add permissions > Create inline policy"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/2-create-new-inline-policy-to-admin-user-group.png",alt:"AWS console - create new inline policy"})),Object(a.b)("p",null,"Switch to JSON view."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/3-inline-policy-creation-json-view.png",alt:"AWS console - switch to inline policy creation json view"})),Object(a.b)("p",null,"Put this content to the ",Object(a.b)("inlineCode",{parentName:"p"},"Policy editor"),":"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Effect": "Allow",\n "Action": [\n "eks:*",\n "sts:AssumeRole"\n ],\n "Resource": "*"\n }\n ]\n}\n')),Object(a.b)("p",null,"Then click on ",Object(a.b)("inlineCode",{parentName:"p"},"Next"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/4-edit-inline-policy-content.png",alt:"AWS console - edit inline policy content"})),Object(a.b)("p",null,"Give a name to this new policy, for example ",Object(a.b)("inlineCode",{parentName:"p"},"SSO_EKSClusterAdminAccess"),". Then click on ",Object(a.b)("inlineCode",{parentName:"p"},"Create Policy"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/5-create-inline-policy.png",alt:"AWS console - create inline policy"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"set-up-cli-with-sso-access-to-eks"},"Set up CLI with SSO access to EKS"),Object(a.b)("p",null,"Create a named SSO profile using AWS CLI."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"aws configure sso\n")),Object(a.b)("p",null,"You will be prompted an SSO session name, put what you want, I used ",Object(a.b)("inlineCode",{parentName:"p"},"sso-benjamin"),"."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"SSO session name (Recommended): sso-benjamin\nAttempting to automatically open the SSO authorization page in your default browser.\nIf the browser does not open or you wish to use a different device to authorize this request, open the following URL:\n\nhttps://device.sso.us-east-2.amazonaws.com/\n\nThen enter the code:\n\nFHTG-****\n")),Object(a.b)("p",null,"You will be redirected to your browser, validate the form."),Object(a.b)("p",null,"Then you will be prompted to select your AWS account."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"There are 1 AWS account available to you.\n> qovery, q@qovery.com (283389****)\n")),Object(a.b)("p",null,"Then you will be prompted for default region (",Object(a.b)("inlineCode",{parentName:"p"},"eu-west-3")," in my case), output format (",Object(a.b)("inlineCode",{parentName:"p"},"json")," in my case) and profile name (",Object(a.b)("inlineCode",{parentName:"p"},"bchastanier_sso")," in my case, but feel free to pick whatever you want)."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),'Using the account ID 283389****\nThe only role available to you is: AdministratorAccess\nUsing the role name "AdministratorAccess"\nCLI default client Region [None]: eu-west-3\nCLI default output format [None]: json\nCLI profile name: bchastanier_sso\n'))),Object(a.b)("li",null,Object(a.b)("h4",{id:"get-sso-role-arn"},"Get SSO role ARN"),Object(a.b)("p",null,"Go to AWS console > IAM > Roles."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/6-iam-roles.png",alt:"AWS console - go to aws iam roles"})),Object(a.b)("p",null,"Look for a role named ",Object(a.b)("inlineCode",{parentName:"p"},"AWSReservedSSO_xx")," and select it (name can varies based on what you have configured / how you named your ",Object(a.b)("inlineCode",{parentName:"p"},"Admins")," user group, but it should start with ",Object(a.b)("inlineCode",{parentName:"p"},"AWSReservedSSO_"),")."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/7-iam-roles-look-for-sso-role.png",alt:"AWS console - look for SSO role"})),Object(a.b)("p",null,"Copy its ARN and keep it somewhere, you will need it in next step."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/8-iam-roles-copy-arn.png",alt:"AWS console - copy SSO role ARN"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"enable-sso-on-your-cluster"},"Enable SSO on your cluster"),Object(a.b)("p",null,"Go to your clusters in Qovery console and click on cluster you want to activate SSO on settings."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/9-qovery-go-to-cluster-settings.png",alt:"AWS console - go to qovery cluster settings"})),Object(a.b)("p",null,"Then go to advanced settings, and set:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("inlineCode",{parentName:"li"},"aws.iam.enable_sso")," to ",Object(a.b)("inlineCode",{parentName:"li"},"true")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("inlineCode",{parentName:"li"},"aws.iam.sso_role_arn")," to the SSO role ARN string you copy from previous step.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/10-qovery-cluster-advanced-settings-enable-sso.png",alt:"AWS console - set qovery cluster advanced settings to enable SSO"})),Object(a.b)("p",null,"Redeploy your cluster once advanced settings are saved.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"download-the-kubeconfig-file"},"Download the Kubeconfig file"),Object(a.b)("p",null,"To connect to your EKS cluster you will need to set a context to ",Object(a.b)("inlineCode",{parentName:"p"},"kubectl"),". This is done with a ",Object(a.b)("inlineCode",{parentName:"p"},"Kubeconfig")," file."),Object(a.b)("p",null,"When installing a new cluster, Qovery stores it in an S3 bucket on your account."),Object(a.b)("p",null,"Go to S3, find the Qovery bucket, and download the file. The bucket should be named something like ",Object(a.b)("inlineCode",{parentName:"p"},"qovery-kubeconfigs-.yaml"),"."),Object(a.b)("p",null,"Set the context for kubectl, run the following command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"export KUBECONFIG=\n")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/11-get-cluster-kubeconfig.png",alt:"AWS console - get Kubeconfig"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"connect-to-your-cluster"},"Connect to your cluster"),Object(a.b)("p",null,"Connect via the CLI running this command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"aws sso login --profile \n")),Object(a.b)("p",null,"This will open your browser and prompt you to connect, validate the form."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-activate-sso-to-connect-to-your-eks-cluster/12-validate-sso-connection-in-browser.png",alt:"AWS console - validate SSO connection in browser"})),Object(a.b)("p",null,"Now you should be able to access your cluster without anything else, let's try to get ",Object(a.b)("inlineCode",{parentName:"p"},"aws-auth")," configmap showing users and roles allowed to connect to the cluster:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"AWS_PROFILE= kubectl describe -n kube-system configmap/aws-auth\n")),Object(a.b)("p",null,"This should give you the config map content. If not, something is not properly configured.")))),Object(a.b)("h2",{id:"conclusion"},"Conclusion"),Object(a.b)("p",null,"You can access your Qovery clusters via your SSO directly."))}p.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),m=o,d=b["".concat(c,".").concat(m)]||b[m]||p[m]||a;return n?r.a.createElement(d,i({ref:t},s,{components:n})):r.a.createElement(d,i({ref:t},s))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,c=new Array(a);c[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var s=2;s1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>i;)t[i++]=e;return t}},428:function(e,t,n){var o=n(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var o=n(0),r=n.n(o),a=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var o=n(1),r=n(0),a=n.n(r),c=n(39),i=n(432),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,b=Object(i.a)(u),p=Object(r.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&b&&window.docusaurus.prefetch(u),function(){m&&t&&t.disconnect()}}),[u,m,b]),u&&b?a.a.createElement(c.b,Object(o.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,o;m&&e&&b&&(n=e,o=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:u})):a.a.createElement("a",Object(o.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=n(430),c=n(423),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,c=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,b=e.to,p=i()("jump-to","jump-to--"+s,n),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},o?r.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:b,target:u,className:p},m):r.a.createElement(a.a,{to:b,className:p},m)}},432:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},433:function(e,t,n){"use strict";var o=n(435),r=n(51);function a(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(r),a,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[a(t,e),"[",o,"]"].join(""):[a(t,e),"[",a(o,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return a(o,t);if(Array.isArray(r)){var c=[];return r.slice().forEach((function(e){void 0!==e&&c.push(n(o,e,c.length))})),c.join("&")}return a(o,t)+"="+a(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(423),n(433)),c=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),u=Object(o.useState)(null),b=u[0],p=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/1d187ae3.15baad28.js.LICENSE.txt b/1b633bfd.bfb64824.js.LICENSE.txt similarity index 100% rename from 1d187ae3.15baad28.js.LICENSE.txt rename to 1b633bfd.bfb64824.js.LICENSE.txt diff --git a/1be78505.35986b3f.js b/1be78505.9c8c9847.js similarity index 94% rename from 1be78505.35986b3f.js rename to 1be78505.9c8c9847.js index 63a9047b86..253dd930d3 100644 --- a/1be78505.35986b3f.js +++ b/1be78505.9c8c9847.js @@ -1,2 +1,2 @@ -/*! For license information please see 1be78505.35986b3f.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[34,267],{417:function(e,t,n){"use strict";n.r(t);n(29),n(22),n(21),n(52),n(436);var a=n(0),r=n.n(a),i=n(422),o=n(420),l=n.n(o),s=n(433),c=n(67),u=n(442),d=n(1),p=(n(78),n(443),n(444),n(427)),m=n(437),f=n.n(m);n(435);var b=n(449),g=n(450),h=n(183),y=n.n(h);n(184);function v(e){var t=e.item,n=e.level,i=e.onItemClick,o=e.collapsible,s=t.items,c=t.href,u=t.label,m=t.type,f=Object(a.useState)(t.collapsed),b=f[0],g=f[1],h=Object(a.useState)(null),y=h[0],k=h[1];switch(t.collapsed!==y&&(k(t.collapsed),g(t.collapsed)),m){case"category":if(0==s.length)return!1;if(1==n)return r.a.createElement("li",{className:l()("menu__list-item"),key:u},r.a.createElement("div",{className:"title"},u),r.a.createElement("ul",{className:"menu__list"},s.map((function(e){return r.a.createElement(v,{key:e.label,item:e,level:n+1,onItemClick:i,collapsible:o})}))));var w=s[0].href;return r.a.createElement("li",{className:l()("menu__list-item",{"menu__list-item--collapsed":b}),key:u},r.a.createElement(p.a,{activeClassName:"menu__link--active",className:l()("menu__link",{"menu__link--sublist":o}),to:w+"/",onClick:o&&"#!"==w?function(){return g(!b)}:void 0},u),r.a.createElement("ul",{className:"menu__list"},s.map((function(e){return r.a.createElement(v,{key:e.label,item:e,level:n+1,onItemClick:i,collapsible:o})}))));case"link":default:var E=[],_=u;if(u.includes("|")){var x=u.split("|",2);_=x[0],E=JSON.parse(x[1])}var O="hidden"==_;return r.a.createElement("li",{className:l()("menu__list-item",O&&"menu__list-item-hidden"),key:u},r.a.createElement(p.a,Object(d.a)({className:"menu__link",to:c+"/"},/^\/(?!\/)/.test(c)?{activeClassName:"menu__link--active",exact:!0,onClick:i}:{target:"_blank",rel:"noreferrer noopener"}),_,E.length>0&&r.a.createElement("span",{className:"badges"},E.includes("log")&&r.a.createElement("span",{className:"badge badge--secondary",title:"This component works with log events."},"L"),E.includes("metric")&&r.a.createElement("span",{className:"badge badge--secondary",title:"This component works with metric events."},"M"))))}}var k=function(e){var t=Object(a.useState)(!1),n=t[0],i=t[1],o=Object(s.a)(),c=o.siteConfig,u=(c=void 0===c?{}:c).themeConfig.navbar,m=(u=void 0===u?{}:u).title,h=o.isClient,k=Object(g.a)(),w=k.logoLink,E=k.logoLinkProps,_=k.logoImageUrl,x=k.logoAlt,O=e.docsSidebars,j=e.path,S=e.sidebar,N=e.sidebarCollapsible;if(Object(b.a)(n),!S)return null;var T=O[S];if(!T)throw new Error('Cannot find the sidebar "'+S+'" in the sidebar config!');return N&&T.forEach((function(e){return function e(t,n){var a=t.items,r=t.href;switch(t.type){case"category":var i=a.map((function(t){return e(t,n)})).filter((function(e){return e})).length>0;return t.collapsed=!i,i;case"link":default:return r===n}}(e,j)})),r.a.createElement("div",{className:l()("docs-sidebar",y.a.sidebar)},r.a.createElement(p.a,Object(d.a)({className:y.a.sidebarLogo,style:{maxWidth:"130px"},to:w},E),null!=_&&r.a.createElement(f.a,{key:h,src:_,alt:x}),null!=m&&r.a.createElement("strong",null,m)),r.a.createElement("div",{className:l()("menu","menu--responsive",y.a.menu,{"menu--show":n})},r.a.createElement("button",{"aria-label":n?"Close Menu":"Open Menu",className:"button button--secondary button--sm menu__button",type:"button",onClick:function(){i(!n)}},n?r.a.createElement("span",{className:l()(y.a.sidebarMenuIcon,y.a.sidebarMenuCloseIcon)},"\xd7"):r.a.createElement("svg",{className:y.a.sidebarMenuIcon,xmlns:"http://www.w3.org/2000/svg",height:24,width:24,viewBox:"0 0 32 32",role:"img",focusable:"false"},r.a.createElement("title",null,"Menu"),r.a.createElement("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"}))),r.a.createElement("ul",{className:"menu__list"},T.map((function(e){return e.items.length>0&&r.a.createElement(v,{key:e.label,item:e,level:1,onItemClick:function(){i(!1)},collapsible:N})})))))},w=n(526),E=n(561),_=n(469),x=n(185),O=n.n(x);t.default=function(e){var t=e.route,n=e.docsMetadata,a=e.location,o=t.routes.find((function(e){return Object(_.b)(a.pathname,e)}))||{},d=n.permalinkToSidebar,p=n.docsSidebars,m=n.version,f=d[o.path],b=Object(s.a)(),g=b.siteConfig,h=(g=void 0===g?{}:g).themeConfig,y=void 0===h?{}:h,v=b.isClient,x=y.sidebarCollapsible,j=void 0===x||x;return 0===Object.keys(o).length?r.a.createElement(E.default,e):r.a.createElement(u.a,{version:m,key:v},r.a.createElement("div",{className:l()(O.a.container,"container","container--l")},f&&r.a.createElement("div",{className:l()(O.a.sidebar)},r.a.createElement(k,{docsSidebars:p,path:o.path,sidebar:f,sidebarCollapsible:j})),r.a.createElement("main",{className:O.a.main},r.a.createElement(i.a,{components:w.a},Object(c.a)(t.routes)))))}},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=r.a.createContext({}),u=function(e){var t=r.a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},d=function(e){var t=u(e.components);return r.a.createElement(c.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,o=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=u(n),m=a,f=d["".concat(o,".").concat(m)]||d[m]||p[m]||i;return n?r.a.createElement(f,l({ref:t},c,{components:n})):r.a.createElement(f,l({ref:t},c))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var c=2;c1?arguments[1]:void 0)}}),n(74)("find")},442:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),i=n(455),o=n(440),l=n(1),s=(n(443),n(444),n(456),n(427)),c=n(457),u=n(437),d=n.n(u),p=n(458),m=n.n(p),f=n(433),b=n(420),g=n.n(b),h=n(135),y=n.n(h),v=function(){return r.a.createElement("span",{className:g()(y.a.toggle,y.a.moon)})},k=function(){return r.a.createElement("span",{className:g()(y.a.toggle,y.a.sun)})},w=function(e){var t=Object(f.a)().isClient;return r.a.createElement(m.a,Object(l.a)({disabled:!t,icons:{checked:r.a.createElement(v,null),unchecked:r.a.createElement(k,null)}},e))};function E(){var e=Object(f.a)().siteConfig,t=(void 0===e?{}:e).customFields.metadata.latest_post,n=Date.parse(t.date),a=new Date,r=Math.abs(a-n),i=Math.ceil(r/864e5),o=null;return"undefined"!=typeof window&&(o=new Date(parseInt(window.localStorage.getItem("blogViewedAt")||"0"))),i<30&&(!o||o0&&r.a.createElement("div",{className:"row footer__links"},r.a.createElement("div",{className:"col col--5 footer__col"},r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement(d.a,{className:"navbar__logo",src:m,alt:"Qovery",width:"150",height:"auto"})),r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),r.a.createElement("div",null,r.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},r.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},r.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},r.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},r.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),s.map((function(e,t){return r.a.createElement("div",{key:t,className:"col footer__col"},null!=e.title?r.a.createElement("h4",{className:"footer__title"},e.title):null,null!=e.items&&Array.isArray(e.items)&&e.items.length>0?r.a.createElement("ul",{className:"footer__items"},e.items.map((function(e,t){return e.html?r.a.createElement("li",{key:t,className:"footer__item",dangerouslySetInnerHTML:{__html:e.html}}):r.a.createElement("li",{key:e.href||e.to,className:"footer__item"},r.a.createElement(R,e))}))):null)}))),(u||o)&&r.a.createElement("div",{className:"text--center"},u&&u.src&&r.a.createElement("div",{className:"margin-bottom--sm"},u.href?r.a.createElement("a",{href:u.href,target:"_blank",rel:"noopener noreferrer",className:I.a.footerLogoLink},r.a.createElement(D,{alt:u.alt,url:p})):r.a.createElement(D,{alt:u.alt,url:p})),r.a.createElement("small",null,o),r.a.createElement("br",null))))},M=n(459),F=n(460),q=n(3);n(138);t.a=function(e){var t=Object(f.a)().siteConfig,n=void 0===t?{}:t,a=n.favicon,l=(n.tagline,n.title),s=n.themeConfig.image,c=n.url,u=e.children,d=e.title,p=e.noFooter,m=e.description,b=e.image,g=e.keywords,h=(e.permalink,e.version),y=d?d+" | "+l:l,v=b||s,k=c+Object(x.a)(v),w=Object(x.a)(a),E=Object(q.h)(),_=E?"https://docs.qovery.com"+(E.pathname.endsWith("/")?E.pathname:E.pathname+"/"):null;return r.a.createElement(F.a,null,r.a.createElement(M.a,null,r.a.createElement(o.a,null,r.a.createElement("html",{lang:"en"}),r.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),y&&r.a.createElement("title",null,y),y&&r.a.createElement("meta",{property:"og:title",content:y}),a&&r.a.createElement("link",{rel:"shortcut icon",href:w}),m&&r.a.createElement("meta",{name:"description",content:m}),m&&r.a.createElement("meta",{property:"og:description",content:m}),h&&r.a.createElement("meta",{name:"docsearch:version",content:h}),g&&g.length&&r.a.createElement("meta",{name:"keywords",content:g.join(",")}),v&&r.a.createElement("meta",{property:"og:image",content:k}),v&&r.a.createElement("meta",{property:"twitter:image",content:k}),v&&r.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+y}),_&&r.a.createElement("meta",{property:"og:url",content:_}),r.a.createElement("meta",{name:"twitter:card",content:"summary"}),_&&r.a.createElement("link",{rel:"canonical",href:_})),r.a.createElement(i.a,null),r.a.createElement(A,null),r.a.createElement("div",{className:"main-wrapper"},u),!p&&r.a.createElement($,null)))}},447:function(e,t,n){"use strict";var a=n(9),r=n(0),i=n.n(r),o=n(420),l=n.n(o),s=n(433),c=(n(139),n(140)),u=n.n(c);t.a=function(e){return function(t){var n,r=t.id,o=Object(a.a)(t,["id"]),c=Object(s.a)().siteConfig,d=(c=void 0===c?{}:c).themeConfig,p=(d=void 0===d?{}:d).navbar,m=(p=void 0===p?{}:p).hideOnScroll,f=void 0!==m&&m;return r?i.a.createElement(e,o,i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:l()("anchor",(n={},n[u.a.enhancedAnchor]=!f,n)),id:r}),i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+r,title:"Direct link to heading"},"#"),o.children):i.a.createElement(e,o)}}},451:function(e,t,n){"use strict";var a=n(0),r=Object(a.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=r},462:function(e,t,n){var a=n(30),r=n(54),i=n(27),o=n(26),l=n(463);e.exports=function(e,t){var n=1==e,s=2==e,c=3==e,u=4==e,d=6==e,p=5==e||d,m=t||l;return function(t,l,f){for(var b,g,h=i(t),y=r(h),v=a(l,f,3),k=o(y.length),w=0,E=n?m(t,k):s?m(t,0):void 0;k>w;w++)if((p||w in y)&&(g=v(b=y[w],w,h),e))if(n)E[w]=g;else if(g)switch(e){case 3:return!0;case 5:return b;case 6:return w;case 2:E.push(b)}else if(u)return!1;return d?-1:c||u?u:E}}},463:function(e,t,n){var a=n(464);e.exports=function(e,t){return new(a(e))(t)}},464:function(e,t,n){var a=n(13),r=n(465),i=n(2)("species");e.exports=function(e){var t;return r(e)&&("function"!=typeof(t=e.constructor)||t!==Array&&!r(t.prototype)||(t=void 0),a(t)&&null===(t=t[i])&&(t=void 0)),void 0===t?Array:t}},465:function(e,t,n){var a=n(23);e.exports=Array.isArray||function(e){return"Array"==a(e)}},484:function(e,t,n){"use strict";(function(e){var a=n(1),r=(n(443),n(444),n(78),n(77),n(527),n(0)),i=n.n(r),o=n(528),l=n.n(o),s=n(560),c=n(53),u=n(420),d=n.n(u),p=n(540),m=n.n(p),f=n(529),b=n.n(f),g=n(433),h=n(438),y=n(148),v=n.n(y);(void 0!==e?e:window).Prism=c.a,n(530),n(531),n(532),n(533),n(90),n(534),n(535),n(536),n(537),n(538),n(539);var k=/{([\d,-]+)}/,w=/title=".*"/;t.a=function(e){var t=e.children,n=e.className,o=e.metastring,c=Object(g.a)().siteConfig.themeConfig.prism,u=void 0===c?{}:c,p=Object(r.useState)(!1),f=p[0],y=p[1],E=Object(r.useState)(!1),_=E[0],x=E[1];Object(r.useEffect)((function(){x(!0)}),[]);var O=Object(r.useRef)(null),j=Object(r.useRef)(null),S=[],N="",T=Object(h.a)().isDarkTheme,C=u.theme||m.a,P=u.darkTheme||C,A=T?P:C;if(o&&k.test(o)){var z=o.match(k)[1];S=b.a.parse(z).filter((function(e){return e>0}))}o&&w.test(o)&&(N=o.match(w)[0].split("title=")[1].replace(/"+/g,"")),Object(r.useEffect)((function(){var e;return j.current&&(e=new l.a(j.current,{target:function(){return O.current}})),function(){e&&e.destroy()}}),[j.current,O.current]);var L=n&&n.replace(/language-/,"");!L&&u.defaultLanguage&&(L=u.defaultLanguage);var I=function(){window.getSelection().empty(),y(!0),setTimeout((function(){return y(!1)}),2e3)};return i.a.createElement(s.a,Object(a.a)({},s.b,{key:_,theme:A,code:t.trim(),language:L}),(function(e){var t,n,r=e.className,o=e.style,l=e.tokens,s=e.getLineProps,c=e.getTokenProps;return i.a.createElement(i.a.Fragment,null,N&&i.a.createElement("div",{style:o,className:v.a.codeBlockTitle},N),i.a.createElement("div",{className:v.a.codeBlockContent},i.a.createElement("button",{ref:j,type:"button","aria-label":"Copy code to clipboard",className:d()(v.a.copyButton,(t={},t[v.a.copyButtonWithTitle]=N,t)),onClick:I},f?"Copied":"Copy"),i.a.createElement("pre",{className:d()(r,v.a.codeBlock,(n={},n[v.a.codeBlockWithTitle]=N,n))},i.a.createElement("div",{ref:O,className:v.a.codeBlockLines,style:o},l.map((function(e,t){1===e.length&&""===e[0].content&&(e[0].content="\n");var n=s({line:e,key:t});return S.includes(t+1)&&(n.className=n.className+" docusaurus-highlight-code-line"),i.a.createElement("div",Object(a.a)({key:t},n),e.map((function(e,t){return i.a.createElement("span",Object(a.a)({key:t},c({token:e,key:t})))})))}))))))}))}}).call(this,n(76))},526:function(e,t,n){"use strict";var a=n(1),r=n(0),i=n.n(r),o=n(427),l=n(484),s=n(447),c=n(149),u=n.n(c);t.a={code:function(e){var t=e.children;return"string"==typeof t?i.a.createElement(l.a,e):t},a:function(e){return/\.[^./]+$/.test(e.href)?i.a.createElement("a",e):i.a.createElement(o.a,e)},pre:function(e){return i.a.createElement("div",Object(a.a)({className:u.a.mdxCodeBlock},e))},h1:Object(s.a)("h1"),h2:Object(s.a)("h2"),h3:Object(s.a)("h3"),h4:Object(s.a)("h4"),h5:Object(s.a)("h5"),h6:Object(s.a)("h6")}},527:function(e,t,n){"use strict";var a=n(8),r=n(26),i=n(60),o=n(55);n(56)("match",1,(function(e,t,n,l){return[function(n){var a=e(this),r=null==n?void 0:n[t];return void 0!==r?r.call(n,a):new RegExp(n)[t](String(a))},function(e){var t=l(n,e,this);if(t.done)return t.value;var s=a(e),c=String(this);if(!s.global)return o(s,c);var u=s.unicode;s.lastIndex=0;for(var d,p=[],m=0;null!==(d=o(s,c));){var f=String(d[0]);p[m]=f,""===f&&(s.lastIndex=i(c,r(s.lastIndex),u)),m++}return 0===m?null:p}]}))},528:function(e,t,n){var a;a=function(){return function(e){var t={};function n(a){if(t[a])return t[a].exports;var r=t[a]={i:a,l:!1,exports:{}};return e[a].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=e,n.c=t,n.d=function(e,t,a){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:a})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var a=Object.create(null);if(n.r(a),Object.defineProperty(a,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(a,r,function(t){return e[t]}.bind(null,r));return a},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=6)}([function(e,t){e.exports=function(e){var t;if("SELECT"===e.nodeName)e.focus(),t=e.value;else if("INPUT"===e.nodeName||"TEXTAREA"===e.nodeName){var n=e.hasAttribute("readonly");n||e.setAttribute("readonly",""),e.select(),e.setSelectionRange(0,e.value.length),n||e.removeAttribute("readonly"),t=e.value}else{e.hasAttribute("contenteditable")&&e.focus();var a=window.getSelection(),r=document.createRange();r.selectNodeContents(e),a.removeAllRanges(),a.addRange(r),t=a.toString()}return t}},function(e,t){function n(){}n.prototype={on:function(e,t,n){var a=this.e||(this.e={});return(a[e]||(a[e]=[])).push({fn:t,ctx:n}),this},once:function(e,t,n){var a=this;function r(){a.off(e,r),t.apply(n,arguments)}return r._=t,this.on(e,r,n)},emit:function(e){for(var t=[].slice.call(arguments,1),n=((this.e||(this.e={}))[e]||[]).slice(),a=0,r=n.length;a0&&void 0!==arguments[0]?arguments[0]:{};this.action=e.action,this.container=e.container,this.emitter=e.emitter,this.target=e.target,this.text=e.text,this.trigger=e.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function(){var e=this,t="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return e.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[t?"right":"left"]="-9999px";var n=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.style.top=n+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.container.appendChild(this.fakeElem),this.selectedText=r()(this.fakeElem),this.copyText()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=r()(this.target),this.copyText()}},{key:"copyText",value:function(){var e=void 0;try{e=document.execCommand(this.action)}catch(t){e=!1}this.handleResult(e)}},{key:"handleResult",value:function(e){this.emitter.emit(e?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),document.activeElement.blur(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=e,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(e){if(void 0!==e){if(!e||"object"!==(void 0===e?"undefined":i(e))||1!==e.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&e.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(e.hasAttribute("readonly")||e.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=e}},get:function(){return this._target}}]),e}(),s=n(1),c=n.n(s),u=n(2),d=n.n(u),p="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},m=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof e.action?e.action:this.defaultAction,this.target="function"==typeof e.target?e.target:this.defaultTarget,this.text="function"==typeof e.text?e.text:this.defaultText,this.container="object"===p(e.container)?e.container:document.body}},{key:"listenClick",value:function(e){var t=this;this.listener=d()(e,"click",(function(e){return t.onClick(e)}))}},{key:"onClick",value:function(e){var t=e.delegateTarget||e.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new l({action:this.action(t),target:this.target(t),text:this.text(t),container:this.container,trigger:t,emitter:this})}},{key:"defaultAction",value:function(e){return b("action",e)}},{key:"defaultTarget",value:function(e){var t=b("target",e);if(t)return document.querySelector(t)}},{key:"defaultText",value:function(e){return b("text",e)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["copy","cut"],t="string"==typeof e?[e]:e,n=!!document.queryCommandSupported;return t.forEach((function(e){n=n&&!!document.queryCommandSupported(e)})),n}}]),t}(c.a);function b(e,t){var n="data-clipboard-"+e;if(t.hasAttribute(n))return t.getAttribute(n)}t.default=f}]).default},e.exports=a()},529:function(e,t){e.exports.parse=function(e){var t=e.split(",").map((function(e){return function(e){if(/^-?\d+$/.test(e))return parseInt(e,10);var t;if(t=e.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){var n=t[1],a=t[2],r=t[3];if(n&&r){var i=[],o=(n=parseInt(n))<(r=parseInt(r))?1:-1;"-"!=a&&".."!=a&&"\u2025"!=a||(r+=o);for(var l=n;l!=r;l+=o)i.push(l);return i}}return[]}(e)}));return 0===t.length?[]:1===t.length?Array.isArray(t[0])?t[0]:t:t.reduce((function(e,t){return Array.isArray(e)||(e=[e]),Array.isArray(t)||(t=[t]),e.concat(t)}))}},530:function(e,t){!function(e){function t(e){return RegExp("(^(?:"+e+"):[ \t]*(?![ \t]))[^]+","i")}e.languages.http={"request-line":{pattern:/^(?:CONNECT|DELETE|GET|HEAD|OPTIONS|PATCH|POST|PRI|PUT|SEARCH|TRACE)\s(?:https?:\/\/|\/)\S*\sHTTP\/[\d.]+/m,inside:{method:{pattern:/^[A-Z]+\b/,alias:"property"},"request-target":{pattern:/^(\s)(?:https?:\/\/|\/)\S*(?=\s)/,lookbehind:!0,alias:"url",inside:e.languages.uri},"http-version":{pattern:/^(\s)HTTP\/[\d.]+/,lookbehind:!0,alias:"property"}}},"response-status":{pattern:/^HTTP\/[\d.]+ \d+ .+/m,inside:{"http-version":{pattern:/^HTTP\/[\d.]+/,alias:"property"},"status-code":{pattern:/^(\s)\d+(?=\s)/,lookbehind:!0,alias:"number"},"reason-phrase":{pattern:/^(\s).+/,lookbehind:!0,alias:"string"}}},header:{pattern:/^[\w-]+:.+(?:(?:\r\n?|\n)[ \t].+)*/m,inside:{"header-value":[{pattern:t(/Content-Security-Policy/.source),lookbehind:!0,alias:["csp","languages-csp"],inside:e.languages.csp},{pattern:t(/Public-Key-Pins(?:-Report-Only)?/.source),lookbehind:!0,alias:["hpkp","languages-hpkp"],inside:e.languages.hpkp},{pattern:t(/Strict-Transport-Security/.source),lookbehind:!0,alias:["hsts","languages-hsts"],inside:e.languages.hsts},{pattern:t(/[^:]+/.source),lookbehind:!0}],"header-name":{pattern:/^[^:]+/,alias:"keyword"},punctuation:/^:/}}};var n,a=e.languages,r={"application/javascript":a.javascript,"application/json":a.json||a.javascript,"application/xml":a.xml,"text/xml":a.xml,"text/html":a.html,"text/css":a.css,"text/plain":a.plain},i={"application/json":!0,"application/xml":!0};function o(e){var t=e.replace(/^[a-z]+\//,"");return"(?:"+e+"|"+("\\w+/(?:[\\w.-]+\\+)+"+t+"(?![+\\w.-])")+")"}for(var l in r)if(r[l]){n=n||{};var s=i[l]?o(l):l;n[l.replace(/\//g,"-")]={pattern:RegExp("("+/content-type:\s*/.source+s+/(?:(?:\r\n?|\n)[\w-].*)*(?:\r(?:\n|(?!\n))|\n)/.source+")"+/[^ \t\w-][\s\S]*/.source,"i"),lookbehind:!0,inside:r[l]}}n&&e.languages.insertBefore("http","header",n)}(Prism)},531:function(e,t){Prism.languages.lua={comment:/^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,string:{pattern:/(["'])(?:(?!\1)[^\\\r\n]|\\z(?:\r\n|\s)|\\(?:\r\n|[^z]))*\1|\[(=*)\[[\s\S]*?\]\2\]/,greedy:!0},number:/\b0x[a-f\d]+(?:\.[a-f\d]*)?(?:p[+-]?\d+)?\b|\b\d+(?:\.\B|(?:\.\d*)?(?:e[+-]?\d+)?\b)|\B\.\d+(?:e[+-]?\d+)?\b/i,keyword:/\b(?:and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,function:/(?!\d)\w+(?=\s*(?:[({]))/,operator:[/[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,{pattern:/(^|[^.])\.\.(?!\.)/,lookbehind:!0}],punctuation:/[\[\](){},;]|\.+|:+/}},532:function(e,t){!function(e){var t=e.languages.powershell={comment:[{pattern:/(^|[^`])<#[\s\S]*?#>/,lookbehind:!0},{pattern:/(^|[^`])#.*/,lookbehind:!0}],string:[{pattern:/"(?:`[\s\S]|[^`"])*"/,greedy:!0,inside:null},{pattern:/'(?:[^']|'')*'/,greedy:!0}],namespace:/\[[a-z](?:\[(?:\[[^\]]*\]|[^\[\]])*\]|[^\[\]])*\]/i,boolean:/\$(?:false|true)\b/i,variable:/\$\w+\b/,function:[/\b(?:Add|Approve|Assert|Backup|Block|Checkpoint|Clear|Close|Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom|ConvertTo|Copy|Debug|Deny|Disable|Disconnect|Dismount|Edit|Enable|Enter|Exit|Expand|Export|Find|ForEach|Format|Get|Grant|Group|Hide|Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push|Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset|Resize|Resolve|Restart|Restore|Resume|Revoke|Save|Search|Select|Send|Set|Show|Skip|Sort|Split|Start|Step|Stop|Submit|Suspend|Switch|Sync|Tee|Test|Trace|Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish|Unregister|Update|Use|Wait|Watch|Where|Write)-[a-z]+\b/i,/\b(?:ac|cat|chdir|clc|cli|clp|clv|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|ebp|echo|epal|epcsv|epsn|erase|fc|fl|ft|fw|gal|gbp|gc|gci|gcs|gdr|gi|gl|gm|gp|gps|group|gsv|gu|gv|gwmi|iex|ii|ipal|ipcsv|ipsn|irm|iwmi|iwr|kill|lp|ls|measure|mi|mount|move|mp|mv|nal|ndr|ni|nv|ogv|popd|ps|pushd|pwd|rbp|rd|rdr|ren|ri|rm|rmdir|rni|rnp|rp|rv|rvpa|rwmi|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spps|spsv|start|sv|swmi|tee|trcm|type|write)\b/i],keyword:/\b(?:Begin|Break|Catch|Class|Continue|Data|Define|Do|DynamicParam|Else|ElseIf|End|Exit|Filter|Finally|For|ForEach|From|Function|If|InlineScript|Parallel|Param|Process|Return|Sequence|Switch|Throw|Trap|Try|Until|Using|Var|While|Workflow)\b/i,operator:{pattern:/(^|\W)(?:!|-(?:b?(?:and|x?or)|as|(?:Not)?(?:Contains|In|Like|Match)|eq|ge|gt|is(?:Not)?|Join|le|lt|ne|not|Replace|sh[lr])\b|-[-=]?|\+[+=]?|[*\/%]=?)/i,lookbehind:!0},punctuation:/[|{}[\];(),.]/};t.string[0].inside={function:{pattern:/(^|[^`])\$\((?:\$\([^\r\n()]*\)|(?!\$\()[^\r\n)])*\)/,lookbehind:!0,inside:t},boolean:t.boolean,variable:t.variable}}(Prism)},533:function(e,t){!function(e){var t=/\b(?:bool|bytes|double|s?fixed(?:32|64)|float|[su]?int(?:32|64)|string)\b/;e.languages.protobuf=e.languages.extend("clike",{"class-name":[{pattern:/(\b(?:enum|extend|message|service)\s+)[A-Za-z_]\w*(?=\s*\{)/,lookbehind:!0},{pattern:/(\b(?:rpc\s+\w+|returns)\s*\(\s*(?:stream\s+)?)\.?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*(?=\s*\))/,lookbehind:!0}],keyword:/\b(?:enum|extend|extensions|import|message|oneof|option|optional|package|public|repeated|required|reserved|returns|rpc(?=\s+\w)|service|stream|syntax|to)\b(?!\s*=\s*\d)/,function:/\b[a-z_]\w*(?=\s*\()/i}),e.languages.insertBefore("protobuf","operator",{map:{pattern:/\bmap<\s*[\w.]+\s*,\s*[\w.]+\s*>(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/[<>.,]/,builtin:t}},builtin:t,"positional-class-name":{pattern:/(?:\b|\B\.)[a-z_]\w*(?:\.[a-z_]\w*)*(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/\./}},annotation:{pattern:/(\[\s*)[a-z_]\w*(?=\s*=)/i,lookbehind:!0}})}(Prism)},534:function(e,t){!function(e){var t=/(?:[\w-]+|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*")/.source;function n(e){return e.replace(/__/g,(function(){return t}))}e.languages.toml={comment:{pattern:/#.*/,greedy:!0},table:{pattern:RegExp(n(/(^[\t ]*\[\s*(?:\[\s*)?)__(?:\s*\.\s*__)*(?=\s*\])/.source),"m"),lookbehind:!0,greedy:!0,alias:"class-name"},key:{pattern:RegExp(n(/(^[\t ]*|[{,]\s*)__(?:\s*\.\s*__)*(?=\s*=)/.source),"m"),lookbehind:!0,greedy:!0,alias:"property"},string:{pattern:/"""(?:\\[\s\S]|[^\\])*?"""|'''[\s\S]*?'''|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},date:[{pattern:/\b\d{4}-\d{2}-\d{2}(?:[T\s]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?\b/i,alias:"number"},{pattern:/\b\d{2}:\d{2}:\d{2}(?:\.\d+)?\b/,alias:"number"}],number:/(?:\b0(?:x[\da-zA-Z]+(?:_[\da-zA-Z]+)*|o[0-7]+(?:_[0-7]+)*|b[10]+(?:_[10]+)*))\b|[-+]?\b\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?\b|[-+]?\b(?:inf|nan)\b/,boolean:/\b(?:false|true)\b/,punctuation:/[.,=[\]{}]/}}(Prism)},535:function(e,t){!function(e){e.languages.kotlin=e.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,lookbehind:!0},function:[{pattern:/(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/,greedy:!0},{pattern:/(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/,lookbehind:!0,greedy:!0}],number:/\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete e.languages.kotlin["class-name"];var t={"interpolation-punctuation":{pattern:/^\$\{?|\}$/,alias:"punctuation"},expression:{pattern:/[\s\S]+/,inside:e.languages.kotlin}};e.languages.insertBefore("kotlin","string",{"string-literal":[{pattern:/"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/,alias:"multiline",inside:{interpolation:{pattern:/\$(?:[a-z_]\w*|\{[^{}]*\})/i,inside:t},string:/[\s\S]+/}},{pattern:/"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/,alias:"singleline",inside:{interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i,lookbehind:!0,inside:t},string:/[\s\S]+/}}],char:{pattern:/'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/,greedy:!0}}),delete e.languages.kotlin.string,e.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),e.languages.insertBefore("kotlin","function",{label:{pattern:/\b\w+@|@\w+\b/,alias:"symbol"}}),e.languages.kt=e.languages.kotlin,e.languages.kts=e.languages.kotlin}(Prism)},536:function(e,t){!function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,n=/(^|[^\w.])(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source,a={pattern:RegExp(n+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}};e.languages.java=e.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,lookbehind:!0,greedy:!0},"class-name":[a,{pattern:RegExp(n+/[A-Z]\w*(?=\s+\w+\s*[;,=()])/.source),lookbehind:!0,inside:a.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"},char:{pattern:/'(?:\\.|[^'\\\r\n]){1,6}'/,greedy:!0}}),e.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":a,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},namespace:{pattern:RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(//g,(function(){return t.source}))),lookbehind:!0,inside:{punctuation:/\./}}})}(Prism)},537:function(e,t){Prism.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},Prism.languages.python["string-interpolation"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python},538:function(e,t){!function(e){var t=/\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/,n=[{pattern:/\b(?:false|true)\b/i,alias:"boolean"},{pattern:/(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,greedy:!0,lookbehind:!0},{pattern:/(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,greedy:!0,lookbehind:!0},/\b(?:null)\b/i,/\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/],a=/\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i,r=/|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,i=/[{}\[\](),:;]/;e.languages.php={delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"},comment:t,variable:/\$+(?:\w+\b|(?=\{))/,package:{pattern:/(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,lookbehind:!0,inside:{punctuation:/\\/}},"class-name-definition":{pattern:/(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,lookbehind:!0,alias:"class-name"},"function-definition":{pattern:/(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,lookbehind:!0,alias:"function"},keyword:[{pattern:/(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i,alias:"type-casting",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string|void)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i,alias:"type-declaration",greedy:!0},{pattern:/(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i,alias:"type-declaration",greedy:!0,lookbehind:!0},{pattern:/\b(?:parent|self|static)(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(\byield\s+)from\b/i,lookbehind:!0},/\bclass\b/i,{pattern:/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|new|or|parent|print|private|protected|public|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i,lookbehind:!0}],"argument-name":{pattern:/([(,]\s+)\b[a-z_]\w*(?=\s*:(?!:))/i,lookbehind:!0},"class-name":[{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/(\|\s*)\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,greedy:!0},{pattern:/(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,alias:"class-name-fully-qualified",greedy:!0,inside:{punctuation:/\\/}},{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*\$)/i,alias:"type-declaration",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-declaration"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,alias:["class-name-fully-qualified","static-context"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-hint"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:["class-name-fully-qualified","return-type"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,function:{pattern:/(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,lookbehind:!0,inside:{punctuation:/\\/}},property:{pattern:/(->\s*)\w+/,lookbehind:!0},number:a,operator:r,punctuation:i};var o={pattern:/\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,lookbehind:!0,inside:e.languages.php},l=[{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,alias:"nowdoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:o}},{pattern:/`(?:\\[\s\S]|[^\\`])*`/,alias:"backtick-quoted-string",greedy:!0},{pattern:/'(?:\\[\s\S]|[^\\'])*'/,alias:"single-quoted-string",greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,alias:"double-quoted-string",greedy:!0,inside:{interpolation:o}}];e.languages.insertBefore("php","variable",{string:l,attribute:{pattern:/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,greedy:!0,inside:{"attribute-content":{pattern:/^(#\[)[\s\S]+(?=\]$)/,lookbehind:!0,inside:{comment:t,string:l,"attribute-class-name":[{pattern:/([^:]|^)\b[a-z_]\w*(?!\\)\b/i,alias:"class-name",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\?\b[a-z_]\w*)+/i,alias:["class-name","class-name-fully-qualified"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,number:a,operator:r,punctuation:i}},delimiter:{pattern:/^#\[|\]$/,alias:"punctuation"}}}}),e.hooks.add("before-tokenize",(function(t){if(/<\?/.test(t.code)){e.languages["markup-templating"].buildPlaceholders(t,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g)}})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"php")}))}(Prism)},539:function(e,t){!function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,a="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",r=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*/.source.replace(//g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),i=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function o(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<>/g,(function(){return a})).replace(/<>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<>/g,(function(){return a}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)<>(?=\s*:\s)/.source.replace(/<>/g,(function(){return a})).replace(/<>/g,(function(){return"(?:"+r+"|"+i+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:o(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:o(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:o(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:o(i),lookbehind:!0,greedy:!0},number:{pattern:o(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(Prism)},540:function(e,t){e.exports={plain:{color:"#bfc7d5",backgroundColor:"#292d3e"},styles:[{types:["comment"],style:{color:"rgb(105, 112, 152)",fontStyle:"italic"}},{types:["string"],style:{color:"rgb(195, 232, 141)"}},{types:["number"],style:{color:"rgb(247, 140, 108)"}},{types:["builtin","char","constant","function"],style:{color:"rgb(130, 170, 255)"}},{types:["punctuation","selector"],style:{color:"rgb(199, 146, 234)"}},{types:["variable"],style:{color:"rgb(191, 199, 213)"}},{types:["class-name","attr-name"],style:{color:"rgb(255, 203, 107)"}},{types:["tag"],style:{color:"rgb(255, 85, 114)"}},{types:["operator"],style:{color:"rgb(137, 221, 255)"}},{types:["boolean"],style:{color:"rgb(255, 88, 116)"}},{types:["keyword"],style:{fontStyle:"italic"}},{types:["doctype"],style:{color:"rgb(199, 146, 234)",fontStyle:"italic"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)"}},{types:["url"],style:{color:"rgb(221, 221, 221)"}}]}},560:function(e,t,n){"use strict";n.d(t,"b",(function(){return o}));var a=n(53),r={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","at-rule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]},i=n(0),o={Prism:a.a,theme:r};function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(){return(s=Object.assign||function(e){for(var t=1;t0&&e[n-1]===t?e:e.concat(t)},p=function(e,t){var n=e.plain,a=Object.create(null),r=e.styles.reduce((function(e,n){var a=n.languages,r=n.style;return a&&!a.includes(t)||n.types.forEach((function(t){var n=s({},e[t],r);e[t]=n})),e}),a);return r.root=n,r.plain=s({},n,{backgroundColor:null}),r};function m(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&-1===t.indexOf(a)&&(n[a]=e[a]);return n}var f=function(e){function t(){for(var t=this,n=[],a=arguments.length;a--;)n[a]=arguments[a];e.apply(this,n),l(this,"getThemeDict",(function(e){if(void 0!==t.themeDict&&e.theme===t.prevTheme&&e.language===t.prevLanguage)return t.themeDict;t.prevTheme=e.theme,t.prevLanguage=e.language;var n=e.theme?p(e.theme,e.language):void 0;return t.themeDict=n})),l(this,"getLineProps",(function(e){var n=e.key,a=e.className,r=e.style,i=s({},m(e,["key","className","style","line"]),{className:"token-line",style:void 0,key:void 0}),o=t.getThemeDict(t.props);return void 0!==o&&(i.style=o.plain),void 0!==r&&(i.style=void 0!==i.style?s({},i.style,r):r),void 0!==n&&(i.key=n),a&&(i.className+=" "+a),i})),l(this,"getStyleForToken",(function(e){var n=e.types,a=e.empty,r=n.length,i=t.getThemeDict(t.props);if(void 0!==i){if(1===r&&"plain"===n[0])return a?{display:"inline-block"}:void 0;if(1===r&&!a)return i[n[0]];var o=a?{display:"inline-block"}:{},l=n.map((function(e){return i[e]}));return Object.assign.apply(Object,[o].concat(l))}})),l(this,"getTokenProps",(function(e){var n=e.key,a=e.className,r=e.style,i=e.token,o=s({},m(e,["key","className","style","token"]),{className:"token "+i.types.join(" "),children:i.content,style:t.getStyleForToken(i),key:void 0});return void 0!==r&&(o.style=void 0!==o.style?s({},o.style,r):r),void 0!==n&&(o.key=n),a&&(o.className+=" "+a),o}))}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.render=function(){var e=this.props,t=e.Prism,n=e.language,a=e.code,r=e.children,i=this.getThemeDict(this.props),o=t.languages[n];return r({tokens:function(e){for(var t=[[]],n=[e],a=[0],r=[e.length],i=0,o=0,l=[],s=[l];o>-1;){for(;(i=a[o]++)0?m:["plain"],p=f):(m=d(m,f.type),f.alias&&(m=d(m,f.alias)),p=f.content),"string"==typeof p){var b=p.split(c),g=b.length;l.push({types:m,content:b[0]});for(var h=1;h0&&r.a.createElement("span",{className:"badges"},E.includes("log")&&r.a.createElement("span",{className:"badge badge--secondary",title:"This component works with log events."},"L"),E.includes("metric")&&r.a.createElement("span",{className:"badge badge--secondary",title:"This component works with metric events."},"M"))))}}var k=function(e){var t=Object(a.useState)(!1),n=t[0],i=t[1],o=Object(s.a)(),c=o.siteConfig,u=(c=void 0===c?{}:c).themeConfig.navbar,m=(u=void 0===u?{}:u).title,h=o.isClient,k=Object(g.a)(),w=k.logoLink,E=k.logoLinkProps,_=k.logoImageUrl,x=k.logoAlt,O=e.docsSidebars,j=e.path,S=e.sidebar,N=e.sidebarCollapsible;if(Object(b.a)(n),!S)return null;var T=O[S];if(!T)throw new Error('Cannot find the sidebar "'+S+'" in the sidebar config!');return N&&T.forEach((function(e){return function e(t,n){var a=t.items,r=t.href;switch(t.type){case"category":var i=a.map((function(t){return e(t,n)})).filter((function(e){return e})).length>0;return t.collapsed=!i,i;case"link":default:return r===n}}(e,j)})),r.a.createElement("div",{className:l()("docs-sidebar",y.a.sidebar)},r.a.createElement(p.a,Object(d.a)({className:y.a.sidebarLogo,style:{maxWidth:"130px"},to:w},E),null!=_&&r.a.createElement(f.a,{key:h,src:_,alt:x}),null!=m&&r.a.createElement("strong",null,m)),r.a.createElement("div",{className:l()("menu","menu--responsive",y.a.menu,{"menu--show":n})},r.a.createElement("button",{"aria-label":n?"Close Menu":"Open Menu",className:"button button--secondary button--sm menu__button",type:"button",onClick:function(){i(!n)}},n?r.a.createElement("span",{className:l()(y.a.sidebarMenuIcon,y.a.sidebarMenuCloseIcon)},"\xd7"):r.a.createElement("svg",{className:y.a.sidebarMenuIcon,xmlns:"http://www.w3.org/2000/svg",height:24,width:24,viewBox:"0 0 32 32",role:"img",focusable:"false"},r.a.createElement("title",null,"Menu"),r.a.createElement("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"}))),r.a.createElement("ul",{className:"menu__list"},T.map((function(e){return e.items.length>0&&r.a.createElement(v,{key:e.label,item:e,level:1,onItemClick:function(){i(!1)},collapsible:N})})))))},w=n(529),E=n(564),_=n(472),x=n(186),O=n.n(x);t.default=function(e){var t=e.route,n=e.docsMetadata,a=e.location,o=t.routes.find((function(e){return Object(_.b)(a.pathname,e)}))||{},d=n.permalinkToSidebar,p=n.docsSidebars,m=n.version,f=d[o.path],b=Object(s.a)(),g=b.siteConfig,h=(g=void 0===g?{}:g).themeConfig,y=void 0===h?{}:h,v=b.isClient,x=y.sidebarCollapsible,j=void 0===x||x;return 0===Object.keys(o).length?r.a.createElement(E.default,e):r.a.createElement(u.a,{version:m,key:v},r.a.createElement("div",{className:l()(O.a.container,"container","container--l")},f&&r.a.createElement("div",{className:l()(O.a.sidebar)},r.a.createElement(k,{docsSidebars:p,path:o.path,sidebar:f,sidebarCollapsible:j})),r.a.createElement("main",{className:O.a.main},r.a.createElement(i.a,{components:w.a},Object(c.a)(t.routes)))))}},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=r.a.createContext({}),u=function(e){var t=r.a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},d=function(e){var t=u(e.components);return r.a.createElement(c.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,o=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=u(n),m=a,f=d["".concat(o,".").concat(m)]||d[m]||p[m]||i;return n?r.a.createElement(f,l({ref:t},c,{components:n})):r.a.createElement(f,l({ref:t},c))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var c=2;c1?arguments[1]:void 0)}}),n(74)("find")},445:function(e,t,n){"use strict";n(457);var a=n(0),r=n.n(a),i=n(458),o=n(443),l=n(1),s=(n(446),n(447),n(459),n(430)),c=n(460),u=n(440),d=n.n(u),p=n(461),m=n.n(p),f=n(436),b=n(423),g=n.n(b),h=n(135),y=n.n(h),v=function(){return r.a.createElement("span",{className:g()(y.a.toggle,y.a.moon)})},k=function(){return r.a.createElement("span",{className:g()(y.a.toggle,y.a.sun)})},w=function(e){var t=Object(f.a)().isClient;return r.a.createElement(m.a,Object(l.a)({disabled:!t,icons:{checked:r.a.createElement(v,null),unchecked:r.a.createElement(k,null)}},e))};function E(){var e=Object(f.a)().siteConfig,t=(void 0===e?{}:e).customFields.metadata.latest_post,n=Date.parse(t.date),a=new Date,r=Math.abs(a-n),i=Math.ceil(r/864e5),o=null;return"undefined"!=typeof window&&(o=new Date(parseInt(window.localStorage.getItem("blogViewedAt")||"0"))),i<30&&(!o||o0&&r.a.createElement("div",{className:"row footer__links"},r.a.createElement("div",{className:"col col--5 footer__col"},r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement(d.a,{className:"navbar__logo",src:m,alt:"Qovery",width:"150",height:"auto"})),r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),r.a.createElement("div",null,r.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},r.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},r.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},r.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},r.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),s.map((function(e,t){return r.a.createElement("div",{key:t,className:"col footer__col"},null!=e.title?r.a.createElement("h4",{className:"footer__title"},e.title):null,null!=e.items&&Array.isArray(e.items)&&e.items.length>0?r.a.createElement("ul",{className:"footer__items"},e.items.map((function(e,t){return e.html?r.a.createElement("li",{key:t,className:"footer__item",dangerouslySetInnerHTML:{__html:e.html}}):r.a.createElement("li",{key:e.href||e.to,className:"footer__item"},r.a.createElement(R,e))}))):null)}))),(u||o)&&r.a.createElement("div",{className:"text--center"},u&&u.src&&r.a.createElement("div",{className:"margin-bottom--sm"},u.href?r.a.createElement("a",{href:u.href,target:"_blank",rel:"noopener noreferrer",className:I.a.footerLogoLink},r.a.createElement(D,{alt:u.alt,url:p})):r.a.createElement(D,{alt:u.alt,url:p})),r.a.createElement("small",null,o),r.a.createElement("br",null))))},M=n(462),F=n(463),q=n(3);n(138);t.a=function(e){var t=Object(f.a)().siteConfig,n=void 0===t?{}:t,a=n.favicon,l=(n.tagline,n.title),s=n.themeConfig.image,c=n.url,u=e.children,d=e.title,p=e.noFooter,m=e.description,b=e.image,g=e.keywords,h=(e.permalink,e.version),y=d?d+" | "+l:l,v=b||s,k=c+Object(x.a)(v),w=Object(x.a)(a),E=Object(q.h)(),_=E?"https://docs.qovery.com"+(E.pathname.endsWith("/")?E.pathname:E.pathname+"/"):null;return r.a.createElement(F.a,null,r.a.createElement(M.a,null,r.a.createElement(o.a,null,r.a.createElement("html",{lang:"en"}),r.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),y&&r.a.createElement("title",null,y),y&&r.a.createElement("meta",{property:"og:title",content:y}),a&&r.a.createElement("link",{rel:"shortcut icon",href:w}),m&&r.a.createElement("meta",{name:"description",content:m}),m&&r.a.createElement("meta",{property:"og:description",content:m}),h&&r.a.createElement("meta",{name:"docsearch:version",content:h}),g&&g.length&&r.a.createElement("meta",{name:"keywords",content:g.join(",")}),v&&r.a.createElement("meta",{property:"og:image",content:k}),v&&r.a.createElement("meta",{property:"twitter:image",content:k}),v&&r.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+y}),_&&r.a.createElement("meta",{property:"og:url",content:_}),r.a.createElement("meta",{name:"twitter:card",content:"summary"}),_&&r.a.createElement("link",{rel:"canonical",href:_})),r.a.createElement(i.a,null),r.a.createElement(A,null),r.a.createElement("div",{className:"main-wrapper"},u),!p&&r.a.createElement($,null)))}},450:function(e,t,n){"use strict";var a=n(9),r=n(0),i=n.n(r),o=n(423),l=n.n(o),s=n(436),c=(n(139),n(140)),u=n.n(c);t.a=function(e){return function(t){var n,r=t.id,o=Object(a.a)(t,["id"]),c=Object(s.a)().siteConfig,d=(c=void 0===c?{}:c).themeConfig,p=(d=void 0===d?{}:d).navbar,m=(p=void 0===p?{}:p).hideOnScroll,f=void 0!==m&&m;return r?i.a.createElement(e,o,i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:l()("anchor",(n={},n[u.a.enhancedAnchor]=!f,n)),id:r}),i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+r,title:"Direct link to heading"},"#"),o.children):i.a.createElement(e,o)}}},454:function(e,t,n){"use strict";var a=n(0),r=Object(a.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=r},465:function(e,t,n){var a=n(30),r=n(54),i=n(27),o=n(26),l=n(466);e.exports=function(e,t){var n=1==e,s=2==e,c=3==e,u=4==e,d=6==e,p=5==e||d,m=t||l;return function(t,l,f){for(var b,g,h=i(t),y=r(h),v=a(l,f,3),k=o(y.length),w=0,E=n?m(t,k):s?m(t,0):void 0;k>w;w++)if((p||w in y)&&(g=v(b=y[w],w,h),e))if(n)E[w]=g;else if(g)switch(e){case 3:return!0;case 5:return b;case 6:return w;case 2:E.push(b)}else if(u)return!1;return d?-1:c||u?u:E}}},466:function(e,t,n){var a=n(467);e.exports=function(e,t){return new(a(e))(t)}},467:function(e,t,n){var a=n(13),r=n(468),i=n(2)("species");e.exports=function(e){var t;return r(e)&&("function"!=typeof(t=e.constructor)||t!==Array&&!r(t.prototype)||(t=void 0),a(t)&&null===(t=t[i])&&(t=void 0)),void 0===t?Array:t}},468:function(e,t,n){var a=n(23);e.exports=Array.isArray||function(e){return"Array"==a(e)}},487:function(e,t,n){"use strict";(function(e){var a=n(1),r=(n(446),n(447),n(78),n(77),n(530),n(0)),i=n.n(r),o=n(531),l=n.n(o),s=n(563),c=n(53),u=n(423),d=n.n(u),p=n(543),m=n.n(p),f=n(532),b=n.n(f),g=n(436),h=n(441),y=n(148),v=n.n(y);(void 0!==e?e:window).Prism=c.a,n(533),n(534),n(535),n(536),n(90),n(537),n(538),n(539),n(540),n(541),n(542);var k=/{([\d,-]+)}/,w=/title=".*"/;t.a=function(e){var t=e.children,n=e.className,o=e.metastring,c=Object(g.a)().siteConfig.themeConfig.prism,u=void 0===c?{}:c,p=Object(r.useState)(!1),f=p[0],y=p[1],E=Object(r.useState)(!1),_=E[0],x=E[1];Object(r.useEffect)((function(){x(!0)}),[]);var O=Object(r.useRef)(null),j=Object(r.useRef)(null),S=[],N="",T=Object(h.a)().isDarkTheme,C=u.theme||m.a,P=u.darkTheme||C,A=T?P:C;if(o&&k.test(o)){var z=o.match(k)[1];S=b.a.parse(z).filter((function(e){return e>0}))}o&&w.test(o)&&(N=o.match(w)[0].split("title=")[1].replace(/"+/g,"")),Object(r.useEffect)((function(){var e;return j.current&&(e=new l.a(j.current,{target:function(){return O.current}})),function(){e&&e.destroy()}}),[j.current,O.current]);var L=n&&n.replace(/language-/,"");!L&&u.defaultLanguage&&(L=u.defaultLanguage);var I=function(){window.getSelection().empty(),y(!0),setTimeout((function(){return y(!1)}),2e3)};return i.a.createElement(s.a,Object(a.a)({},s.b,{key:_,theme:A,code:t.trim(),language:L}),(function(e){var t,n,r=e.className,o=e.style,l=e.tokens,s=e.getLineProps,c=e.getTokenProps;return i.a.createElement(i.a.Fragment,null,N&&i.a.createElement("div",{style:o,className:v.a.codeBlockTitle},N),i.a.createElement("div",{className:v.a.codeBlockContent},i.a.createElement("button",{ref:j,type:"button","aria-label":"Copy code to clipboard",className:d()(v.a.copyButton,(t={},t[v.a.copyButtonWithTitle]=N,t)),onClick:I},f?"Copied":"Copy"),i.a.createElement("pre",{className:d()(r,v.a.codeBlock,(n={},n[v.a.codeBlockWithTitle]=N,n))},i.a.createElement("div",{ref:O,className:v.a.codeBlockLines,style:o},l.map((function(e,t){1===e.length&&""===e[0].content&&(e[0].content="\n");var n=s({line:e,key:t});return S.includes(t+1)&&(n.className=n.className+" docusaurus-highlight-code-line"),i.a.createElement("div",Object(a.a)({key:t},n),e.map((function(e,t){return i.a.createElement("span",Object(a.a)({key:t},c({token:e,key:t})))})))}))))))}))}}).call(this,n(76))},529:function(e,t,n){"use strict";var a=n(1),r=n(0),i=n.n(r),o=n(430),l=n(487),s=n(450),c=n(149),u=n.n(c);t.a={code:function(e){var t=e.children;return"string"==typeof t?i.a.createElement(l.a,e):t},a:function(e){return/\.[^./]+$/.test(e.href)?i.a.createElement("a",e):i.a.createElement(o.a,e)},pre:function(e){return i.a.createElement("div",Object(a.a)({className:u.a.mdxCodeBlock},e))},h1:Object(s.a)("h1"),h2:Object(s.a)("h2"),h3:Object(s.a)("h3"),h4:Object(s.a)("h4"),h5:Object(s.a)("h5"),h6:Object(s.a)("h6")}},530:function(e,t,n){"use strict";var a=n(8),r=n(26),i=n(60),o=n(55);n(56)("match",1,(function(e,t,n,l){return[function(n){var a=e(this),r=null==n?void 0:n[t];return void 0!==r?r.call(n,a):new RegExp(n)[t](String(a))},function(e){var t=l(n,e,this);if(t.done)return t.value;var s=a(e),c=String(this);if(!s.global)return o(s,c);var u=s.unicode;s.lastIndex=0;for(var d,p=[],m=0;null!==(d=o(s,c));){var f=String(d[0]);p[m]=f,""===f&&(s.lastIndex=i(c,r(s.lastIndex),u)),m++}return 0===m?null:p}]}))},531:function(e,t,n){var a;a=function(){return function(e){var t={};function n(a){if(t[a])return t[a].exports;var r=t[a]={i:a,l:!1,exports:{}};return e[a].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=e,n.c=t,n.d=function(e,t,a){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:a})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var a=Object.create(null);if(n.r(a),Object.defineProperty(a,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(a,r,function(t){return e[t]}.bind(null,r));return a},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=6)}([function(e,t){e.exports=function(e){var t;if("SELECT"===e.nodeName)e.focus(),t=e.value;else if("INPUT"===e.nodeName||"TEXTAREA"===e.nodeName){var n=e.hasAttribute("readonly");n||e.setAttribute("readonly",""),e.select(),e.setSelectionRange(0,e.value.length),n||e.removeAttribute("readonly"),t=e.value}else{e.hasAttribute("contenteditable")&&e.focus();var a=window.getSelection(),r=document.createRange();r.selectNodeContents(e),a.removeAllRanges(),a.addRange(r),t=a.toString()}return t}},function(e,t){function n(){}n.prototype={on:function(e,t,n){var a=this.e||(this.e={});return(a[e]||(a[e]=[])).push({fn:t,ctx:n}),this},once:function(e,t,n){var a=this;function r(){a.off(e,r),t.apply(n,arguments)}return r._=t,this.on(e,r,n)},emit:function(e){for(var t=[].slice.call(arguments,1),n=((this.e||(this.e={}))[e]||[]).slice(),a=0,r=n.length;a0&&void 0!==arguments[0]?arguments[0]:{};this.action=e.action,this.container=e.container,this.emitter=e.emitter,this.target=e.target,this.text=e.text,this.trigger=e.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function(){var e=this,t="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return e.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[t?"right":"left"]="-9999px";var n=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.style.top=n+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.container.appendChild(this.fakeElem),this.selectedText=r()(this.fakeElem),this.copyText()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=r()(this.target),this.copyText()}},{key:"copyText",value:function(){var e=void 0;try{e=document.execCommand(this.action)}catch(t){e=!1}this.handleResult(e)}},{key:"handleResult",value:function(e){this.emitter.emit(e?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),document.activeElement.blur(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=e,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(e){if(void 0!==e){if(!e||"object"!==(void 0===e?"undefined":i(e))||1!==e.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&e.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(e.hasAttribute("readonly")||e.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=e}},get:function(){return this._target}}]),e}(),s=n(1),c=n.n(s),u=n(2),d=n.n(u),p="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},m=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof e.action?e.action:this.defaultAction,this.target="function"==typeof e.target?e.target:this.defaultTarget,this.text="function"==typeof e.text?e.text:this.defaultText,this.container="object"===p(e.container)?e.container:document.body}},{key:"listenClick",value:function(e){var t=this;this.listener=d()(e,"click",(function(e){return t.onClick(e)}))}},{key:"onClick",value:function(e){var t=e.delegateTarget||e.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new l({action:this.action(t),target:this.target(t),text:this.text(t),container:this.container,trigger:t,emitter:this})}},{key:"defaultAction",value:function(e){return b("action",e)}},{key:"defaultTarget",value:function(e){var t=b("target",e);if(t)return document.querySelector(t)}},{key:"defaultText",value:function(e){return b("text",e)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["copy","cut"],t="string"==typeof e?[e]:e,n=!!document.queryCommandSupported;return t.forEach((function(e){n=n&&!!document.queryCommandSupported(e)})),n}}]),t}(c.a);function b(e,t){var n="data-clipboard-"+e;if(t.hasAttribute(n))return t.getAttribute(n)}t.default=f}]).default},e.exports=a()},532:function(e,t){e.exports.parse=function(e){var t=e.split(",").map((function(e){return function(e){if(/^-?\d+$/.test(e))return parseInt(e,10);var t;if(t=e.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){var n=t[1],a=t[2],r=t[3];if(n&&r){var i=[],o=(n=parseInt(n))<(r=parseInt(r))?1:-1;"-"!=a&&".."!=a&&"\u2025"!=a||(r+=o);for(var l=n;l!=r;l+=o)i.push(l);return i}}return[]}(e)}));return 0===t.length?[]:1===t.length?Array.isArray(t[0])?t[0]:t:t.reduce((function(e,t){return Array.isArray(e)||(e=[e]),Array.isArray(t)||(t=[t]),e.concat(t)}))}},533:function(e,t){!function(e){function t(e){return RegExp("(^(?:"+e+"):[ \t]*(?![ \t]))[^]+","i")}e.languages.http={"request-line":{pattern:/^(?:CONNECT|DELETE|GET|HEAD|OPTIONS|PATCH|POST|PRI|PUT|SEARCH|TRACE)\s(?:https?:\/\/|\/)\S*\sHTTP\/[\d.]+/m,inside:{method:{pattern:/^[A-Z]+\b/,alias:"property"},"request-target":{pattern:/^(\s)(?:https?:\/\/|\/)\S*(?=\s)/,lookbehind:!0,alias:"url",inside:e.languages.uri},"http-version":{pattern:/^(\s)HTTP\/[\d.]+/,lookbehind:!0,alias:"property"}}},"response-status":{pattern:/^HTTP\/[\d.]+ \d+ .+/m,inside:{"http-version":{pattern:/^HTTP\/[\d.]+/,alias:"property"},"status-code":{pattern:/^(\s)\d+(?=\s)/,lookbehind:!0,alias:"number"},"reason-phrase":{pattern:/^(\s).+/,lookbehind:!0,alias:"string"}}},header:{pattern:/^[\w-]+:.+(?:(?:\r\n?|\n)[ \t].+)*/m,inside:{"header-value":[{pattern:t(/Content-Security-Policy/.source),lookbehind:!0,alias:["csp","languages-csp"],inside:e.languages.csp},{pattern:t(/Public-Key-Pins(?:-Report-Only)?/.source),lookbehind:!0,alias:["hpkp","languages-hpkp"],inside:e.languages.hpkp},{pattern:t(/Strict-Transport-Security/.source),lookbehind:!0,alias:["hsts","languages-hsts"],inside:e.languages.hsts},{pattern:t(/[^:]+/.source),lookbehind:!0}],"header-name":{pattern:/^[^:]+/,alias:"keyword"},punctuation:/^:/}}};var n,a=e.languages,r={"application/javascript":a.javascript,"application/json":a.json||a.javascript,"application/xml":a.xml,"text/xml":a.xml,"text/html":a.html,"text/css":a.css,"text/plain":a.plain},i={"application/json":!0,"application/xml":!0};function o(e){var t=e.replace(/^[a-z]+\//,"");return"(?:"+e+"|"+("\\w+/(?:[\\w.-]+\\+)+"+t+"(?![+\\w.-])")+")"}for(var l in r)if(r[l]){n=n||{};var s=i[l]?o(l):l;n[l.replace(/\//g,"-")]={pattern:RegExp("("+/content-type:\s*/.source+s+/(?:(?:\r\n?|\n)[\w-].*)*(?:\r(?:\n|(?!\n))|\n)/.source+")"+/[^ \t\w-][\s\S]*/.source,"i"),lookbehind:!0,inside:r[l]}}n&&e.languages.insertBefore("http","header",n)}(Prism)},534:function(e,t){Prism.languages.lua={comment:/^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,string:{pattern:/(["'])(?:(?!\1)[^\\\r\n]|\\z(?:\r\n|\s)|\\(?:\r\n|[^z]))*\1|\[(=*)\[[\s\S]*?\]\2\]/,greedy:!0},number:/\b0x[a-f\d]+(?:\.[a-f\d]*)?(?:p[+-]?\d+)?\b|\b\d+(?:\.\B|(?:\.\d*)?(?:e[+-]?\d+)?\b)|\B\.\d+(?:e[+-]?\d+)?\b/i,keyword:/\b(?:and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,function:/(?!\d)\w+(?=\s*(?:[({]))/,operator:[/[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,{pattern:/(^|[^.])\.\.(?!\.)/,lookbehind:!0}],punctuation:/[\[\](){},;]|\.+|:+/}},535:function(e,t){!function(e){var t=e.languages.powershell={comment:[{pattern:/(^|[^`])<#[\s\S]*?#>/,lookbehind:!0},{pattern:/(^|[^`])#.*/,lookbehind:!0}],string:[{pattern:/"(?:`[\s\S]|[^`"])*"/,greedy:!0,inside:null},{pattern:/'(?:[^']|'')*'/,greedy:!0}],namespace:/\[[a-z](?:\[(?:\[[^\]]*\]|[^\[\]])*\]|[^\[\]])*\]/i,boolean:/\$(?:false|true)\b/i,variable:/\$\w+\b/,function:[/\b(?:Add|Approve|Assert|Backup|Block|Checkpoint|Clear|Close|Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom|ConvertTo|Copy|Debug|Deny|Disable|Disconnect|Dismount|Edit|Enable|Enter|Exit|Expand|Export|Find|ForEach|Format|Get|Grant|Group|Hide|Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push|Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset|Resize|Resolve|Restart|Restore|Resume|Revoke|Save|Search|Select|Send|Set|Show|Skip|Sort|Split|Start|Step|Stop|Submit|Suspend|Switch|Sync|Tee|Test|Trace|Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish|Unregister|Update|Use|Wait|Watch|Where|Write)-[a-z]+\b/i,/\b(?:ac|cat|chdir|clc|cli|clp|clv|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|ebp|echo|epal|epcsv|epsn|erase|fc|fl|ft|fw|gal|gbp|gc|gci|gcs|gdr|gi|gl|gm|gp|gps|group|gsv|gu|gv|gwmi|iex|ii|ipal|ipcsv|ipsn|irm|iwmi|iwr|kill|lp|ls|measure|mi|mount|move|mp|mv|nal|ndr|ni|nv|ogv|popd|ps|pushd|pwd|rbp|rd|rdr|ren|ri|rm|rmdir|rni|rnp|rp|rv|rvpa|rwmi|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spps|spsv|start|sv|swmi|tee|trcm|type|write)\b/i],keyword:/\b(?:Begin|Break|Catch|Class|Continue|Data|Define|Do|DynamicParam|Else|ElseIf|End|Exit|Filter|Finally|For|ForEach|From|Function|If|InlineScript|Parallel|Param|Process|Return|Sequence|Switch|Throw|Trap|Try|Until|Using|Var|While|Workflow)\b/i,operator:{pattern:/(^|\W)(?:!|-(?:b?(?:and|x?or)|as|(?:Not)?(?:Contains|In|Like|Match)|eq|ge|gt|is(?:Not)?|Join|le|lt|ne|not|Replace|sh[lr])\b|-[-=]?|\+[+=]?|[*\/%]=?)/i,lookbehind:!0},punctuation:/[|{}[\];(),.]/};t.string[0].inside={function:{pattern:/(^|[^`])\$\((?:\$\([^\r\n()]*\)|(?!\$\()[^\r\n)])*\)/,lookbehind:!0,inside:t},boolean:t.boolean,variable:t.variable}}(Prism)},536:function(e,t){!function(e){var t=/\b(?:bool|bytes|double|s?fixed(?:32|64)|float|[su]?int(?:32|64)|string)\b/;e.languages.protobuf=e.languages.extend("clike",{"class-name":[{pattern:/(\b(?:enum|extend|message|service)\s+)[A-Za-z_]\w*(?=\s*\{)/,lookbehind:!0},{pattern:/(\b(?:rpc\s+\w+|returns)\s*\(\s*(?:stream\s+)?)\.?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*(?=\s*\))/,lookbehind:!0}],keyword:/\b(?:enum|extend|extensions|import|message|oneof|option|optional|package|public|repeated|required|reserved|returns|rpc(?=\s+\w)|service|stream|syntax|to)\b(?!\s*=\s*\d)/,function:/\b[a-z_]\w*(?=\s*\()/i}),e.languages.insertBefore("protobuf","operator",{map:{pattern:/\bmap<\s*[\w.]+\s*,\s*[\w.]+\s*>(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/[<>.,]/,builtin:t}},builtin:t,"positional-class-name":{pattern:/(?:\b|\B\.)[a-z_]\w*(?:\.[a-z_]\w*)*(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/\./}},annotation:{pattern:/(\[\s*)[a-z_]\w*(?=\s*=)/i,lookbehind:!0}})}(Prism)},537:function(e,t){!function(e){var t=/(?:[\w-]+|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*")/.source;function n(e){return e.replace(/__/g,(function(){return t}))}e.languages.toml={comment:{pattern:/#.*/,greedy:!0},table:{pattern:RegExp(n(/(^[\t ]*\[\s*(?:\[\s*)?)__(?:\s*\.\s*__)*(?=\s*\])/.source),"m"),lookbehind:!0,greedy:!0,alias:"class-name"},key:{pattern:RegExp(n(/(^[\t ]*|[{,]\s*)__(?:\s*\.\s*__)*(?=\s*=)/.source),"m"),lookbehind:!0,greedy:!0,alias:"property"},string:{pattern:/"""(?:\\[\s\S]|[^\\])*?"""|'''[\s\S]*?'''|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},date:[{pattern:/\b\d{4}-\d{2}-\d{2}(?:[T\s]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?\b/i,alias:"number"},{pattern:/\b\d{2}:\d{2}:\d{2}(?:\.\d+)?\b/,alias:"number"}],number:/(?:\b0(?:x[\da-zA-Z]+(?:_[\da-zA-Z]+)*|o[0-7]+(?:_[0-7]+)*|b[10]+(?:_[10]+)*))\b|[-+]?\b\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?\b|[-+]?\b(?:inf|nan)\b/,boolean:/\b(?:false|true)\b/,punctuation:/[.,=[\]{}]/}}(Prism)},538:function(e,t){!function(e){e.languages.kotlin=e.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,lookbehind:!0},function:[{pattern:/(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/,greedy:!0},{pattern:/(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/,lookbehind:!0,greedy:!0}],number:/\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete e.languages.kotlin["class-name"];var t={"interpolation-punctuation":{pattern:/^\$\{?|\}$/,alias:"punctuation"},expression:{pattern:/[\s\S]+/,inside:e.languages.kotlin}};e.languages.insertBefore("kotlin","string",{"string-literal":[{pattern:/"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/,alias:"multiline",inside:{interpolation:{pattern:/\$(?:[a-z_]\w*|\{[^{}]*\})/i,inside:t},string:/[\s\S]+/}},{pattern:/"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/,alias:"singleline",inside:{interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i,lookbehind:!0,inside:t},string:/[\s\S]+/}}],char:{pattern:/'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/,greedy:!0}}),delete e.languages.kotlin.string,e.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),e.languages.insertBefore("kotlin","function",{label:{pattern:/\b\w+@|@\w+\b/,alias:"symbol"}}),e.languages.kt=e.languages.kotlin,e.languages.kts=e.languages.kotlin}(Prism)},539:function(e,t){!function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,n=/(^|[^\w.])(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source,a={pattern:RegExp(n+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}};e.languages.java=e.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,lookbehind:!0,greedy:!0},"class-name":[a,{pattern:RegExp(n+/[A-Z]\w*(?=\s+\w+\s*[;,=()])/.source),lookbehind:!0,inside:a.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"},char:{pattern:/'(?:\\.|[^'\\\r\n]){1,6}'/,greedy:!0}}),e.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":a,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},namespace:{pattern:RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(//g,(function(){return t.source}))),lookbehind:!0,inside:{punctuation:/\./}}})}(Prism)},540:function(e,t){Prism.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},Prism.languages.python["string-interpolation"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python},541:function(e,t){!function(e){var t=/\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/,n=[{pattern:/\b(?:false|true)\b/i,alias:"boolean"},{pattern:/(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,greedy:!0,lookbehind:!0},{pattern:/(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,greedy:!0,lookbehind:!0},/\b(?:null)\b/i,/\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/],a=/\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i,r=/|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,i=/[{}\[\](),:;]/;e.languages.php={delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"},comment:t,variable:/\$+(?:\w+\b|(?=\{))/,package:{pattern:/(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,lookbehind:!0,inside:{punctuation:/\\/}},"class-name-definition":{pattern:/(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,lookbehind:!0,alias:"class-name"},"function-definition":{pattern:/(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,lookbehind:!0,alias:"function"},keyword:[{pattern:/(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i,alias:"type-casting",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string|void)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i,alias:"type-declaration",greedy:!0},{pattern:/(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i,alias:"type-declaration",greedy:!0,lookbehind:!0},{pattern:/\b(?:parent|self|static)(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(\byield\s+)from\b/i,lookbehind:!0},/\bclass\b/i,{pattern:/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|new|or|parent|print|private|protected|public|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i,lookbehind:!0}],"argument-name":{pattern:/([(,]\s+)\b[a-z_]\w*(?=\s*:(?!:))/i,lookbehind:!0},"class-name":[{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/(\|\s*)\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,greedy:!0},{pattern:/(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,alias:"class-name-fully-qualified",greedy:!0,inside:{punctuation:/\\/}},{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*\$)/i,alias:"type-declaration",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-declaration"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,alias:["class-name-fully-qualified","static-context"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-hint"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:["class-name-fully-qualified","return-type"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,function:{pattern:/(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,lookbehind:!0,inside:{punctuation:/\\/}},property:{pattern:/(->\s*)\w+/,lookbehind:!0},number:a,operator:r,punctuation:i};var o={pattern:/\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,lookbehind:!0,inside:e.languages.php},l=[{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,alias:"nowdoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:o}},{pattern:/`(?:\\[\s\S]|[^\\`])*`/,alias:"backtick-quoted-string",greedy:!0},{pattern:/'(?:\\[\s\S]|[^\\'])*'/,alias:"single-quoted-string",greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,alias:"double-quoted-string",greedy:!0,inside:{interpolation:o}}];e.languages.insertBefore("php","variable",{string:l,attribute:{pattern:/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,greedy:!0,inside:{"attribute-content":{pattern:/^(#\[)[\s\S]+(?=\]$)/,lookbehind:!0,inside:{comment:t,string:l,"attribute-class-name":[{pattern:/([^:]|^)\b[a-z_]\w*(?!\\)\b/i,alias:"class-name",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\?\b[a-z_]\w*)+/i,alias:["class-name","class-name-fully-qualified"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,number:a,operator:r,punctuation:i}},delimiter:{pattern:/^#\[|\]$/,alias:"punctuation"}}}}),e.hooks.add("before-tokenize",(function(t){if(/<\?/.test(t.code)){e.languages["markup-templating"].buildPlaceholders(t,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g)}})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"php")}))}(Prism)},542:function(e,t){!function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,a="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",r=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*/.source.replace(//g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),i=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function o(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<>/g,(function(){return a})).replace(/<>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<>/g,(function(){return a}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)<>(?=\s*:\s)/.source.replace(/<>/g,(function(){return a})).replace(/<>/g,(function(){return"(?:"+r+"|"+i+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:o(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:o(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:o(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:o(i),lookbehind:!0,greedy:!0},number:{pattern:o(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(Prism)},543:function(e,t){e.exports={plain:{color:"#bfc7d5",backgroundColor:"#292d3e"},styles:[{types:["comment"],style:{color:"rgb(105, 112, 152)",fontStyle:"italic"}},{types:["string"],style:{color:"rgb(195, 232, 141)"}},{types:["number"],style:{color:"rgb(247, 140, 108)"}},{types:["builtin","char","constant","function"],style:{color:"rgb(130, 170, 255)"}},{types:["punctuation","selector"],style:{color:"rgb(199, 146, 234)"}},{types:["variable"],style:{color:"rgb(191, 199, 213)"}},{types:["class-name","attr-name"],style:{color:"rgb(255, 203, 107)"}},{types:["tag"],style:{color:"rgb(255, 85, 114)"}},{types:["operator"],style:{color:"rgb(137, 221, 255)"}},{types:["boolean"],style:{color:"rgb(255, 88, 116)"}},{types:["keyword"],style:{fontStyle:"italic"}},{types:["doctype"],style:{color:"rgb(199, 146, 234)",fontStyle:"italic"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)"}},{types:["url"],style:{color:"rgb(221, 221, 221)"}}]}},563:function(e,t,n){"use strict";n.d(t,"b",(function(){return o}));var a=n(53),r={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","at-rule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]},i=n(0),o={Prism:a.a,theme:r};function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(){return(s=Object.assign||function(e){for(var t=1;t0&&e[n-1]===t?e:e.concat(t)},p=function(e,t){var n=e.plain,a=Object.create(null),r=e.styles.reduce((function(e,n){var a=n.languages,r=n.style;return a&&!a.includes(t)||n.types.forEach((function(t){var n=s({},e[t],r);e[t]=n})),e}),a);return r.root=n,r.plain=s({},n,{backgroundColor:null}),r};function m(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&-1===t.indexOf(a)&&(n[a]=e[a]);return n}var f=function(e){function t(){for(var t=this,n=[],a=arguments.length;a--;)n[a]=arguments[a];e.apply(this,n),l(this,"getThemeDict",(function(e){if(void 0!==t.themeDict&&e.theme===t.prevTheme&&e.language===t.prevLanguage)return t.themeDict;t.prevTheme=e.theme,t.prevLanguage=e.language;var n=e.theme?p(e.theme,e.language):void 0;return t.themeDict=n})),l(this,"getLineProps",(function(e){var n=e.key,a=e.className,r=e.style,i=s({},m(e,["key","className","style","line"]),{className:"token-line",style:void 0,key:void 0}),o=t.getThemeDict(t.props);return void 0!==o&&(i.style=o.plain),void 0!==r&&(i.style=void 0!==i.style?s({},i.style,r):r),void 0!==n&&(i.key=n),a&&(i.className+=" "+a),i})),l(this,"getStyleForToken",(function(e){var n=e.types,a=e.empty,r=n.length,i=t.getThemeDict(t.props);if(void 0!==i){if(1===r&&"plain"===n[0])return a?{display:"inline-block"}:void 0;if(1===r&&!a)return i[n[0]];var o=a?{display:"inline-block"}:{},l=n.map((function(e){return i[e]}));return Object.assign.apply(Object,[o].concat(l))}})),l(this,"getTokenProps",(function(e){var n=e.key,a=e.className,r=e.style,i=e.token,o=s({},m(e,["key","className","style","token"]),{className:"token "+i.types.join(" "),children:i.content,style:t.getStyleForToken(i),key:void 0});return void 0!==r&&(o.style=void 0!==o.style?s({},o.style,r):r),void 0!==n&&(o.key=n),a&&(o.className+=" "+a),o}))}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.render=function(){var e=this.props,t=e.Prism,n=e.language,a=e.code,r=e.children,i=this.getThemeDict(this.props),o=t.languages[n];return r({tokens:function(e){for(var t=[[]],n=[e],a=[0],r=[e.length],i=0,o=0,l=[],s=[l];o>-1;){for(;(i=a[o]++)0?m:["plain"],p=f):(m=d(m,f.type),f.alias&&(m=d(m,f.alias)),p=f.content),"string"==typeof p){var b=p.split(c),g=b.length;l.push({types:m,content:b[0]});for(var h=1;h/":G?V="/guides/integrate/sources/"+G.name+"//":H&&(V="/guides/integrate/sinks//");var K=H?"/guides/integrate/sources//"+H.name+"/":"/guides/integrate/sources//",Z=Object(u.useState)(!1),J=Z[0],Y=Z[1],Q=Object(u.useState)(!1),X=Q[0],ee=Q[1];return Object(O.a)("contents__link","contents__link--active",100),r.a.createElement(l.a,{title:v,description:v+", in minutes, for free"},J&&r.a.createElement(p.a,{className:"modal",onRequestClose:function(){return Y(!1)},overlayClassName:"modal-overlay",isOpen:null!==J,contentLabel:"Minimal Modal Example"},r.a.createElement("header",null,r.a.createElement("h1",null,"Where do you receive your data from?")),r.a.createElement(_.a,{exceptFunctions:["test"],exceptNames:[G&&G.name,"docker","qovery"],eventTypes:H&&H.event_types,pathTemplate:K,titles:!1,sources:!0,transforms:!1,sinks:!1})),X&&r.a.createElement(p.a,{className:"modal",onRequestClose:function(){return ee(!1)},overlayClassName:"modal-overlay",isOpen:null!==X,contentLabel:"Minimal Modal Example"},r.a.createElement("header",null,r.a.createElement("h1",null,"Where do you want to send your data?")),r.a.createElement(_.a,{exceptFunctions:["test"],exceptNames:[H&&H.name,"qovery"],eventTypes:G&&G.event_types,pathTemplate:V,titles:!1,sources:!1,transforms:!1,sinks:!0})),r.a.createElement("header",{className:"hero domain-bg domain-bg--"+M},r.a.createElement("div",{className:"container"},(z||G||H)&&r.a.createElement("div",{className:"component-icons"},z&&r.a.createElement("div",{className:"icon panel"},z.logo_path?r.a.createElement(g.a,{src:z.logo_path,alt:z.title+" Logo"}):r.a.createElement("i",{className:"feather icon-server"})),G&&!z&&r.a.createElement("div",{className:"icon panel link",title:"Change your source",onClick:function(e){return Y(!0)}},G.logo_path?r.a.createElement(g.a,{src:G.logo_path,alt:G.title+" Logo"}):r.a.createElement("i",{className:"feather icon-server"})),!G&&!z&&r.a.createElement("div",{className:"icon panel link",title:"Select a source",onClick:function(e){return Y(!0)}},r.a.createElement("i",{className:"feather icon-plus"})),H&&r.a.createElement("div",{className:"icon panel link",title:"Change your destination",onClick:function(e){return ee(!0)}},H.logo_path?r.a.createElement(g.a,{src:H.logo_path,alt:H.title+" Logo"}):r.a.createElement("i",{className:"feather icon-database"})),!H&&r.a.createElement("div",{className:"icon panel link",title:"Select a destination",onClick:function(e){return ee(!0)}},r.a.createElement("i",{className:"feather icon-plus"}))),!z&&!G&&!H&&r.a.createElement("div",{className:"hero--category"},r.a.createElement(f.a,{to:E[0].permalink+"/"},E[0].name)),r.a.createElement("h1",{className:C.a.header},v),r.a.createElement("div",{className:"hero--subtitle"},n.description),r.a.createElement(y.a,{colorProfile:"guides",tags:D}))),r.a.createElement("main",{className:d()("container","container--l",C.a.container)},r.a.createElement("aside",{className:C.a.sidebar},r.a.createElement("section",{className:C.a.avatar},r.a.createElement(i,{bio:!0,github:c,size:"lg",rel:"author",subTitle:!1,vertical:!0})),r.a.createElement("section",{className:d()("table-of-contents",C.a.tableOfContents)},r.a.createElement("div",{className:"section"},r.a.createElement("div",{className:"title"},"Stats"),r.a.createElement("div",{className:"text--secondary text--bold"},r.a.createElement("i",{className:"feather icon-book"})," ",w),r.a.createElement("div",{className:"text--secondary text--bold"},r.a.createElement("i",{className:"feather icon-clock"})," Updated ",r.a.createElement("time",{pubdate:"pubdate",dateTime:s},k()(R,"mmm dS, yyyy")))),t.rightToc.length>0&&r.a.createElement("div",{className:"section"},r.a.createElement("div",{className:"title"},"Contents"),r.a.createElement(I,{headings:t.rightToc})))),r.a.createElement("div",{className:C.a.article},r.a.createElement("article",null,r.a.createElement("div",{className:"markdown"},r.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"anchor",id:"overview"}),r.a.createElement(h.a,{components:m.a},r.a.createElement(t,null)))),!n.hide_pagination&&r.a.createElement(b.a,{previous:a.prevItem,next:a.nextItem,className:C.a.paginator}))))}},421:function(e,t,n){"use strict";n(423);var u=n(0),r=n.n(u),a=n(420),d=n.n(a);n(132);t.a=function(e){var t=e.children,n=e.classNames,u=e.fill,a=e.icon,o=e.type,i=null;switch(o){case"danger":i="alert-triangle";break;case"success":i="check-circle";break;case"warning":i="alert-triangle";break;default:i="info"}return r.a.createElement("div",{className:d()(n,"alert","alert--"+o,{"alert--fill":u,"alert--icon":!1!==a}),role:"alert"},!1!==a&&r.a.createElement("i",{className:d()("feather","icon-"+(a||i))}),t)}},425:function(e,t,n){var u=n(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||n(10)&&u(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(427),d=n(420),o=n.n(d);n(133);t.a=function(e){var t=e.children,n=e.className,u=e.badge,d=e.leftIcon,i=e.rightIcon,c=e.size,l=e.target,f=e.to,s=o()("jump-to","jump-to--"+c,n),p=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},d&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+d})),r.a.createElement("div",{className:"jump-to--main"},u?r.a.createElement("span",{className:"badge badge--primary badge--right"},u):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(i||"chevron-right")+" arrow"}))));return l?r.a.createElement("a",{href:f,target:l,className:s},p):r.a.createElement(a.a,{to:f,className:s},p)}},434:function(e,t,n){"use strict";var u=n(1),r=(n(439),n(436),n(52),n(29),n(22),n(21),n(0)),a=n.n(r),d=n(446),o=n(420),i=n.n(o),c=n(428),l=n.n(c),f=n(445),s=37,p=39;function m(e){var t=e.block,n=e.centered,u=e.changeSelectedValue,r=e.className,d=e.handleKeydown,o=e.style,c=e.values,l=e.selectedValue,f=e.tabRefs;return a.a.createElement("div",{className:n?"tabs--centered":null},a.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:i()("tabs",r,{"tabs--block":t}),style:o},c.map((function(e){var t=e.value,n=e.label;return a.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":l===t,className:i()("tab-item",{"tab-item--active":l===t}),key:t,ref:function(e){return f.push(e)},onKeyDown:function(e){return d(f,e.target,e)},onFocus:function(){return u(t)},onClick:function(){return u(t)}},n)}))))}function h(e){var t=e.placeholder,n=e.selectedValue,u=e.changeSelectedValue,r=e.size,o=e.values,i=o;if(i[0].group){var c=_.groupBy(i,"group");i=Object.keys(c).map((function(e){return{label:e,options:c[e]}}))}return a.a.createElement(d.a,{className:"react-select-container react-select--"+r,classNamePrefix:"react-select",options:i,isClearable:n,placeholder:t,value:o.find((function(e){return e.value==n})),onChange:function(e){return u(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,d=e.groupId,o=e.label,i=e.placeholder,c=e.select,b=e.size,v=(e.style,e.values),g=e.urlKey,y=Object(f.a)(),_=y.tabGroupChoices,E=y.setTabGroupChoices,w=Object(r.useState)(n),D=w[0],k=w[1];if(null!=d){var x=_[d];null!=x&&x!==D&&k(x)}var S=function(e){k(e),null!=d&&E(d,e)},C=[],O=function(e,t,n){switch(n.keyCode){case p:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case s:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(r.useEffect)((function(){if("undefined"!=typeof window&&window.location&&g){var e=l.a.parse(window.location.search);e[g]&&k(e[g])}}),[]),a.a.createElement(a.a.Fragment,null,a.a.createElement("div",{className:"margin-bottom--"+(b||"md")},o&&a.a.createElement("div",{className:"margin-vert--sm"},o),v.length>1&&(c?a.a.createElement(h,Object(u.a)({changeSelectedValue:S,handleKeydown:O,placeholder:i,selectedValue:D,size:b,tabRefs:C},e)):a.a.createElement(m,Object(u.a)({changeSelectedValue:S,handleKeydown:O,selectedValue:D,tabRefs:C},e)))),r.Children.toArray(t).filter((function(e){return e.props.value===D}))[0])}},438:function(e,t,n){"use strict";var u=n(0),r=n(482);t.a=function(){return Object(u.useContext)(r.a)}},441:function(e,t,n){"use strict";var u=n(0),r=n.n(u);t.a=function(e){return r.a.createElement(r.a.Fragment,null,e.children)}},442:function(e,t,n){"use strict";n(454);var u=n(0),r=n.n(u),a=n(455),d=n(440),o=n(1),i=(n(443),n(444),n(456),n(427)),c=n(457),l=n(437),f=n.n(l),s=n(458),p=n.n(s),m=n(433),h=n(420),b=n.n(h),v=n(135),g=n.n(v),y=function(){return r.a.createElement("span",{className:b()(g.a.toggle,g.a.moon)})},_=function(){return r.a.createElement("span",{className:b()(g.a.toggle,g.a.sun)})},E=function(e){var t=Object(m.a)().isClient;return r.a.createElement(p.a,Object(o.a)({disabled:!t,icons:{checked:r.a.createElement(y,null),unchecked:r.a.createElement(_,null)}},e))};function w(){var e=Object(m.a)().siteConfig,t=(void 0===e?{}:e).customFields.metadata.latest_post,n=Date.parse(t.date),u=new Date,r=Math.abs(u-n),a=Math.ceil(r/864e5),d=null;return"undefined"!=typeof window&&(d=new Date(parseInt(window.localStorage.getItem("blogViewedAt")||"0"))),a<30&&(!d||d0&&r.a.createElement("div",{className:"row footer__links"},r.a.createElement("div",{className:"col col--5 footer__col"},r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement(f.a,{className:"navbar__logo",src:p,alt:"Qovery",width:"150",height:"auto"})),r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),r.a.createElement("div",null,r.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},r.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},r.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},r.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},r.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),i.map((function(e,t){return r.a.createElement("div",{key:t,className:"col footer__col"},null!=e.title?r.a.createElement("h4",{className:"footer__title"},e.title):null,null!=e.items&&Array.isArray(e.items)&&e.items.length>0?r.a.createElement("ul",{className:"footer__items"},e.items.map((function(e,t){return e.html?r.a.createElement("li",{key:t,className:"footer__item",dangerouslySetInnerHTML:{__html:e.html}}):r.a.createElement("li",{key:e.href||e.to,className:"footer__item"},r.a.createElement(M,e))}))):null)}))),(l||d)&&r.a.createElement("div",{className:"text--center"},l&&l.src&&r.a.createElement("div",{className:"margin-bottom--sm"},l.href?r.a.createElement("a",{href:l.href,target:"_blank",rel:"noopener noreferrer",className:P.a.footerLogoLink},r.a.createElement(R,{alt:l.alt,url:s})):r.a.createElement(R,{alt:l.alt,url:s})),r.a.createElement("small",null,d),r.a.createElement("br",null))))},B=n(459),z=n(460),U=n(3);n(138);t.a=function(e){var t=Object(m.a)().siteConfig,n=void 0===t?{}:t,u=n.favicon,o=(n.tagline,n.title),i=n.themeConfig.image,c=n.url,l=e.children,f=e.title,s=e.noFooter,p=e.description,h=e.image,b=e.keywords,v=(e.permalink,e.version),g=f?f+" | "+o:o,y=h||i,_=c+Object(k.a)(y),E=Object(k.a)(u),w=Object(U.h)(),D=w?"https://docs.qovery.com"+(w.pathname.endsWith("/")?w.pathname:w.pathname+"/"):null;return r.a.createElement(z.a,null,r.a.createElement(B.a,null,r.a.createElement(d.a,null,r.a.createElement("html",{lang:"en"}),r.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),g&&r.a.createElement("title",null,g),g&&r.a.createElement("meta",{property:"og:title",content:g}),u&&r.a.createElement("link",{rel:"shortcut icon",href:E}),p&&r.a.createElement("meta",{name:"description",content:p}),p&&r.a.createElement("meta",{property:"og:description",content:p}),v&&r.a.createElement("meta",{name:"docsearch:version",content:v}),b&&b.length&&r.a.createElement("meta",{name:"keywords",content:b.join(",")}),y&&r.a.createElement("meta",{property:"og:image",content:_}),y&&r.a.createElement("meta",{property:"twitter:image",content:_}),y&&r.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+g}),D&&r.a.createElement("meta",{property:"og:url",content:D}),r.a.createElement("meta",{name:"twitter:card",content:"summary"}),D&&r.a.createElement("link",{rel:"canonical",href:D})),r.a.createElement(a.a,null),r.a.createElement(N,null),r.a.createElement("div",{className:"main-wrapper"},l),!s&&r.a.createElement(L,null)))}},447:function(e,t,n){"use strict";var u=n(9),r=n(0),a=n.n(r),d=n(420),o=n.n(d),i=n(433),c=(n(139),n(140)),l=n.n(c);t.a=function(e){return function(t){var n,r=t.id,d=Object(u.a)(t,["id"]),c=Object(i.a)().siteConfig,f=(c=void 0===c?{}:c).themeConfig,s=(f=void 0===f?{}:f).navbar,p=(s=void 0===s?{}:s).hideOnScroll,m=void 0!==p&&p;return r?a.a.createElement(e,d,a.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:o()("anchor",(n={},n[l.a.enhancedAnchor]=!m,n)),id:r}),a.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+r,title:"Direct link to heading"},"#"),d.children):a.a.createElement(e,d)}}},448:function(e,t,n){(function(e,u){var r;(function(){var a="Expected a function",d="__lodash_placeholder__",o=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],i="[object Arguments]",c="[object Array]",l="[object Boolean]",f="[object Date]",s="[object Error]",p="[object Function]",m="[object GeneratorFunction]",h="[object Map]",b="[object Number]",v="[object Object]",g="[object RegExp]",y="[object Set]",_="[object String]",E="[object Symbol]",w="[object WeakMap]",D="[object ArrayBuffer]",k="[object DataView]",x="[object Float32Array]",S="[object Float64Array]",C="[object Int8Array]",O="[object Int16Array]",I="[object Int32Array]",A="[object Uint8Array]",j="[object Uint16Array]",N="[object Uint32Array]",F=/\b__p \+= '';/g,T=/\b(__p \+=) '' \+/g,P=/(__e\(.*?\)|\b__t\)) \+\n'';/g,M=/&(?:amp|lt|gt|quot|#39);/g,R=/[&<>"']/g,L=RegExp(M.source),B=RegExp(R.source),z=/<%-([\s\S]+?)%>/g,U=/<%([\s\S]+?)%>/g,W=/<%=([\s\S]+?)%>/g,H=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,$=/^\w*$/,q=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,G=/[\\^$.*+?()[\]{}|]/g,V=RegExp(G.source),K=/^\s+|\s+$/g,Z=/^\s+/,J=/\s+$/,Y=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Q=/\{\n\/\* \[wrapped with (.+)\] \*/,X=/,? & /,ee=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,te=/\\(\\)?/g,ne=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,ue=/\w*$/,re=/^[-+]0x[0-9a-f]+$/i,ae=/^0b[01]+$/i,de=/^\[object .+?Constructor\]$/,oe=/^0o[0-7]+$/i,ie=/^(?:0|[1-9]\d*)$/,ce=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,le=/($^)/,fe=/['\n\r\u2028\u2029\\]/g,se="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",pe="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",me="[\\ud800-\\udfff]",he="["+pe+"]",be="["+se+"]",ve="\\d+",ge="[\\u2700-\\u27bf]",ye="[a-z\\xdf-\\xf6\\xf8-\\xff]",_e="[^\\ud800-\\udfff"+pe+ve+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",Ee="\\ud83c[\\udffb-\\udfff]",we="[^\\ud800-\\udfff]",De="(?:\\ud83c[\\udde6-\\uddff]){2}",ke="[\\ud800-\\udbff][\\udc00-\\udfff]",xe="[A-Z\\xc0-\\xd6\\xd8-\\xde]",Se="(?:"+ye+"|"+_e+")",Ce="(?:"+xe+"|"+_e+")",Oe="(?:"+be+"|"+Ee+")"+"?",Ie="[\\ufe0e\\ufe0f]?"+Oe+("(?:\\u200d(?:"+[we,De,ke].join("|")+")[\\ufe0e\\ufe0f]?"+Oe+")*"),Ae="(?:"+[ge,De,ke].join("|")+")"+Ie,je="(?:"+[we+be+"?",be,De,ke,me].join("|")+")",Ne=RegExp("['\u2019]","g"),Fe=RegExp(be,"g"),Te=RegExp(Ee+"(?="+Ee+")|"+je+Ie,"g"),Pe=RegExp([xe+"?"+ye+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?="+[he,xe,"$"].join("|")+")",Ce+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?="+[he,xe+Se,"$"].join("|")+")",xe+"?"+Se+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?",xe+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",ve,Ae].join("|"),"g"),Me=RegExp("[\\u200d\\ud800-\\udfff"+se+"\\ufe0e\\ufe0f]"),Re=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Le=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Be=-1,ze={};ze[x]=ze[S]=ze[C]=ze[O]=ze[I]=ze[A]=ze["[object Uint8ClampedArray]"]=ze[j]=ze[N]=!0,ze[i]=ze[c]=ze[D]=ze[l]=ze[k]=ze[f]=ze[s]=ze[p]=ze[h]=ze[b]=ze[v]=ze[g]=ze[y]=ze[_]=ze[w]=!1;var Ue={};Ue[i]=Ue[c]=Ue[D]=Ue[k]=Ue[l]=Ue[f]=Ue[x]=Ue[S]=Ue[C]=Ue[O]=Ue[I]=Ue[h]=Ue[b]=Ue[v]=Ue[g]=Ue[y]=Ue[_]=Ue[E]=Ue[A]=Ue["[object Uint8ClampedArray]"]=Ue[j]=Ue[N]=!0,Ue[s]=Ue[p]=Ue[w]=!1;var We={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},He=parseFloat,$e=parseInt,qe="object"==typeof e&&e&&e.Object===Object&&e,Ge="object"==typeof self&&self&&self.Object===Object&&self,Ve=qe||Ge||Function("return this")(),Ke=t&&!t.nodeType&&t,Ze=Ke&&"object"==typeof u&&u&&!u.nodeType&&u,Je=Ze&&Ze.exports===Ke,Ye=Je&&qe.process,Qe=function(){try{var e=Ze&&Ze.require&&Ze.require("util").types;return e||Ye&&Ye.binding&&Ye.binding("util")}catch(t){}}(),Xe=Qe&&Qe.isArrayBuffer,et=Qe&&Qe.isDate,tt=Qe&&Qe.isMap,nt=Qe&&Qe.isRegExp,ut=Qe&&Qe.isSet,rt=Qe&&Qe.isTypedArray;function at(e,t,n){switch(n.length){case 0:return e.call(t);case 1:return e.call(t,n[0]);case 2:return e.call(t,n[0],n[1]);case 3:return e.call(t,n[0],n[1],n[2])}return e.apply(t,n)}function dt(e,t,n,u){for(var r=-1,a=null==e?0:e.length;++r-1}function st(e,t,n){for(var u=-1,r=null==e?0:e.length;++u-1;);return n}function Tt(e,t){for(var n=e.length;n--&&Et(t,e[n],0)>-1;);return n}function Pt(e,t){for(var n=e.length,u=0;n--;)e[n]===t&&++u;return u}var Mt=St({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),Rt=St({"&":"&","<":"<",">":">",'"':""","'":"'"});function Lt(e){return"\\"+We[e]}function Bt(e){return Me.test(e)}function zt(e){var t=-1,n=Array(e.size);return e.forEach((function(e,u){n[++t]=[u,e]})),n}function Ut(e,t){return function(n){return e(t(n))}}function Wt(e,t){for(var n=-1,u=e.length,r=0,a=[];++n",""":'"',"'":"'"});var Kt=function e(t){var n,u=(t=null==t?Ve:Kt.defaults(Ve.Object(),t,Kt.pick(Ve,Le))).Array,r=t.Date,se=t.Error,pe=t.Function,me=t.Math,he=t.Object,be=t.RegExp,ve=t.String,ge=t.TypeError,ye=u.prototype,_e=pe.prototype,Ee=he.prototype,we=t["__core-js_shared__"],De=_e.toString,ke=Ee.hasOwnProperty,xe=0,Se=(n=/[^.]+$/.exec(we&&we.keys&&we.keys.IE_PROTO||""))?"Symbol(src)_1."+n:"",Ce=Ee.toString,Oe=De.call(he),Ie=Ve._,Ae=be("^"+De.call(ke).replace(G,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),je=Je?t.Buffer:void 0,Te=t.Symbol,Me=t.Uint8Array,We=je?je.allocUnsafe:void 0,qe=Ut(he.getPrototypeOf,he),Ge=he.create,Ke=Ee.propertyIsEnumerable,Ze=ye.splice,Ye=Te?Te.isConcatSpreadable:void 0,Qe=Te?Te.iterator:void 0,gt=Te?Te.toStringTag:void 0,St=function(){try{var e=Xr(he,"defineProperty");return e({},"",{}),e}catch(t){}}(),Zt=t.clearTimeout!==Ve.clearTimeout&&t.clearTimeout,Jt=r&&r.now!==Ve.Date.now&&r.now,Yt=t.setTimeout!==Ve.setTimeout&&t.setTimeout,Qt=me.ceil,Xt=me.floor,en=he.getOwnPropertySymbols,tn=je?je.isBuffer:void 0,nn=t.isFinite,un=ye.join,rn=Ut(he.keys,he),an=me.max,dn=me.min,on=r.now,cn=t.parseInt,ln=me.random,fn=ye.reverse,sn=Xr(t,"DataView"),pn=Xr(t,"Map"),mn=Xr(t,"Promise"),hn=Xr(t,"Set"),bn=Xr(t,"WeakMap"),vn=Xr(he,"create"),gn=bn&&new bn,yn={},_n=Sa(sn),En=Sa(pn),wn=Sa(mn),Dn=Sa(hn),kn=Sa(bn),xn=Te?Te.prototype:void 0,Sn=xn?xn.valueOf:void 0,Cn=xn?xn.toString:void 0;function On(e){if(Hd(e)&&!Nd(e)&&!(e instanceof Nn)){if(e instanceof jn)return e;if(ke.call(e,"__wrapped__"))return Ca(e)}return new jn(e)}var In=function(){function e(){}return function(t){if(!Wd(t))return{};if(Ge)return Ge(t);e.prototype=t;var n=new e;return e.prototype=void 0,n}}();function An(){}function jn(e,t){this.__wrapped__=e,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=void 0}function Nn(e){this.__wrapped__=e,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Fn(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t=t?e:t)),e}function Jn(e,t,n,u,r,a){var d,o=1&t,c=2&t,s=4&t;if(n&&(d=r?n(e,u,r,a):n(e)),void 0!==d)return d;if(!Wd(e))return e;var w=Nd(e);if(w){if(d=function(e){var t=e.length,n=new e.constructor(t);t&&"string"==typeof e[0]&&ke.call(e,"index")&&(n.index=e.index,n.input=e.input);return n}(e),!o)return vr(e,d)}else{var F=na(e),T=F==p||F==m;if(Md(e))return fr(e,o);if(F==v||F==i||T&&!r){if(d=c||T?{}:ra(e),!o)return c?function(e,t){return gr(e,ta(e),t)}(e,function(e,t){return e&&gr(t,Eo(t),e)}(d,e)):function(e,t){return gr(e,ea(e),t)}(e,Gn(d,e))}else{if(!Ue[F])return r?e:{};d=function(e,t,n){var u=e.constructor;switch(t){case D:return sr(e);case l:case f:return new u(+e);case k:return function(e,t){var n=t?sr(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.byteLength)}(e,n);case x:case S:case C:case O:case I:case A:case"[object Uint8ClampedArray]":case j:case N:return pr(e,n);case h:return new u;case b:case _:return new u(e);case g:return function(e){var t=new e.constructor(e.source,ue.exec(e));return t.lastIndex=e.lastIndex,t}(e);case y:return new u;case E:return r=e,Sn?he(Sn.call(r)):{}}var r}(e,F,o)}}a||(a=new Rn);var P=a.get(e);if(P)return P;a.set(e,d),Kd(e)?e.forEach((function(u){d.add(Jn(u,t,n,u,e,a))})):$d(e)&&e.forEach((function(u,r){d.set(r,Jn(u,t,n,r,e,a))}));var M=w?void 0:(s?c?Gr:qr:c?Eo:_o)(e);return ot(M||e,(function(u,r){M&&(u=e[r=u]),Hn(d,r,Jn(u,t,n,r,e,a))})),d}function Yn(e,t,n){var u=n.length;if(null==e)return!u;for(e=he(e);u--;){var r=n[u],a=t[r],d=e[r];if(void 0===d&&!(r in e)||!a(d))return!1}return!0}function Qn(e,t,n){if("function"!=typeof e)throw new ge(a);return ya((function(){e.apply(void 0,n)}),t)}function Xn(e,t,n,u){var r=-1,a=ft,d=!0,o=e.length,i=[],c=t.length;if(!o)return i;n&&(t=pt(t,At(n))),u?(a=st,d=!1):t.length>=200&&(a=Nt,d=!1,t=new Mn(t));e:for(;++r-1},Tn.prototype.set=function(e,t){var n=this.__data__,u=$n(n,e);return u<0?(++this.size,n.push([e,t])):n[u][1]=t,this},Pn.prototype.clear=function(){this.size=0,this.__data__={hash:new Fn,map:new(pn||Tn),string:new Fn}},Pn.prototype.delete=function(e){var t=Yr(this,e).delete(e);return this.size-=t?1:0,t},Pn.prototype.get=function(e){return Yr(this,e).get(e)},Pn.prototype.has=function(e){return Yr(this,e).has(e)},Pn.prototype.set=function(e,t){var n=Yr(this,e),u=n.size;return n.set(e,t),this.size+=n.size==u?0:1,this},Mn.prototype.add=Mn.prototype.push=function(e){return this.__data__.set(e,"__lodash_hash_undefined__"),this},Mn.prototype.has=function(e){return this.__data__.has(e)},Rn.prototype.clear=function(){this.__data__=new Tn,this.size=0},Rn.prototype.delete=function(e){var t=this.__data__,n=t.delete(e);return this.size=t.size,n},Rn.prototype.get=function(e){return this.__data__.get(e)},Rn.prototype.has=function(e){return this.__data__.has(e)},Rn.prototype.set=function(e,t){var n=this.__data__;if(n instanceof Tn){var u=n.__data__;if(!pn||u.length<199)return u.push([e,t]),this.size=++n.size,this;n=this.__data__=new Pn(u)}return n.set(e,t),this.size=n.size,this};var eu=Er(iu),tu=Er(cu,!0);function nu(e,t){var n=!0;return eu(e,(function(e,u,r){return n=!!t(e,u,r)})),n}function uu(e,t,n){for(var u=-1,r=e.length;++u0&&n(o)?t>1?au(o,t-1,n,u,r):mt(r,o):u||(r[r.length]=o)}return r}var du=wr(),ou=wr(!0);function iu(e,t){return e&&du(e,t,_o)}function cu(e,t){return e&&ou(e,t,_o)}function lu(e,t){return lt(t,(function(t){return Bd(e[t])}))}function fu(e,t){for(var n=0,u=(t=or(t,e)).length;null!=e&&nt}function hu(e,t){return null!=e&&ke.call(e,t)}function bu(e,t){return null!=e&&t in he(e)}function vu(e,t,n){for(var r=n?st:ft,a=e[0].length,d=e.length,o=d,i=u(d),c=1/0,l=[];o--;){var f=e[o];o&&t&&(f=pt(f,At(t))),c=dn(f.length,c),i[o]=!n&&(t||a>=120&&f.length>=120)?new Mn(o&&f):void 0}f=e[0];var s=-1,p=i[0];e:for(;++s=o)return i;var c=n[u];return i*("desc"==c?-1:1)}}return e.index-t.index}(e,t,n)}))}function Fu(e,t,n){for(var u=-1,r=t.length,a={};++u-1;)o!==e&&Ze.call(o,i,1),Ze.call(e,i,1);return e}function Pu(e,t){for(var n=e?t.length:0,u=n-1;n--;){var r=t[n];if(n==u||r!==a){var a=r;da(r)?Ze.call(e,r,1):Xu(e,r)}}return e}function Mu(e,t){return e+Xt(ln()*(t-e+1))}function Ru(e,t){var n="";if(!e||t<1||t>9007199254740991)return n;do{t%2&&(n+=e),(t=Xt(t/2))&&(e+=e)}while(t);return n}function Lu(e,t){return _a(ma(e,t,Go),e+"")}function Bu(e){return Bn(Io(e))}function zu(e,t){var n=Io(e);return Da(n,Zn(t,0,n.length))}function Uu(e,t,n,u){if(!Wd(e))return e;for(var r=-1,a=(t=or(t,e)).length,d=a-1,o=e;null!=o&&++ra?0:a+t),(n=n>a?a:n)<0&&(n+=a),a=t>n?0:n-t>>>0,t>>>=0;for(var d=u(a);++r>>1,d=e[a];null!==d&&!Jd(d)&&(n?d<=t:d=200){var c=t?null:Rr(e);if(c)return Ht(c);d=!1,r=Nt,i=new Mn}else i=t?[]:o;e:for(;++u=u?e:qu(e,t,n)}var lr=Zt||function(e){return Ve.clearTimeout(e)};function fr(e,t){if(t)return e.slice();var n=e.length,u=We?We(n):new e.constructor(n);return e.copy(u),u}function sr(e){var t=new e.constructor(e.byteLength);return new Me(t).set(new Me(e)),t}function pr(e,t){var n=t?sr(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.length)}function mr(e,t){if(e!==t){var n=void 0!==e,u=null===e,r=e==e,a=Jd(e),d=void 0!==t,o=null===t,i=t==t,c=Jd(t);if(!o&&!c&&!a&&e>t||a&&d&&i&&!o&&!c||u&&d&&i||!n&&i||!r)return 1;if(!u&&!a&&!c&&e1?n[r-1]:void 0,d=r>2?n[2]:void 0;for(a=e.length>3&&"function"==typeof a?(r--,a):void 0,d&&oa(n[0],n[1],d)&&(a=r<3?void 0:a,r=1),t=he(t);++u-1?r[a?t[d]:d]:void 0}}function Cr(e){return $r((function(t){var n=t.length,u=n,r=jn.prototype.thru;for(e&&t.reverse();u--;){var d=t[u];if("function"!=typeof d)throw new ge(a);if(r&&!o&&"wrapper"==Kr(d))var o=new jn([],!0)}for(u=o?u:n;++u1&&y.reverse(),f&&co))return!1;var c=a.get(e);if(c&&a.get(t))return c==t;var l=-1,f=!0,s=2&n?new Mn:void 0;for(a.set(e,t),a.set(t,e);++l-1&&e%1==0&&e1?"& ":"")+t[u],t=t.join(n>2?", ":" "),e.replace(Y,"{\n/* [wrapped with "+t+"] */\n")}(u,function(e,t){return ot(o,(function(n){var u="_."+n[0];t&n[1]&&!ft(e,u)&&e.push(u)})),e.sort()}(function(e){var t=e.match(Q);return t?t[1].split(X):[]}(u),n)))}function wa(e){var t=0,n=0;return function(){var u=on(),r=16-(u-n);if(n=u,r>0){if(++t>=800)return arguments[0]}else t=0;return e.apply(void 0,arguments)}}function Da(e,t){var n=-1,u=e.length,r=u-1;for(t=void 0===t?u:t;++n1?e[t-1]:void 0;return n="function"==typeof n?(e.pop(),n):void 0,Va(e,n)}));function ed(e){var t=On(e);return t.__chain__=!0,t}function td(e,t){return t(e)}var nd=$r((function(e){var t=e.length,n=t?e[0]:0,u=this.__wrapped__,r=function(t){return Kn(t,e)};return!(t>1||this.__actions__.length)&&u instanceof Nn&&da(n)?((u=u.slice(n,+n+(t?1:0))).__actions__.push({func:td,args:[r],thisArg:void 0}),new jn(u,this.__chain__).thru((function(e){return t&&!e.length&&e.push(void 0),e}))):this.thru(r)}));var ud=yr((function(e,t,n){ke.call(e,n)?++e[n]:Vn(e,n,1)}));var rd=Sr(ja),ad=Sr(Na);function dd(e,t){return(Nd(e)?ot:eu)(e,Jr(t,3))}function od(e,t){return(Nd(e)?it:tu)(e,Jr(t,3))}var id=yr((function(e,t,n){ke.call(e,n)?e[n].push(t):Vn(e,n,[t])}));var cd=Lu((function(e,t,n){var r=-1,a="function"==typeof t,d=Td(e)?u(e.length):[];return eu(e,(function(e){d[++r]=a?at(t,e,n):gu(e,t,n)})),d})),ld=yr((function(e,t,n){Vn(e,n,t)}));function fd(e,t){return(Nd(e)?pt:Cu)(e,Jr(t,3))}var sd=yr((function(e,t,n){e[n?0:1].push(t)}),(function(){return[[],[]]}));var pd=Lu((function(e,t){if(null==e)return[];var n=t.length;return n>1&&oa(e,t[0],t[1])?t=[]:n>2&&oa(t[0],t[1],t[2])&&(t=[t[0]]),Nu(e,au(t,1),[])})),md=Jt||function(){return Ve.Date.now()};function hd(e,t,n){return t=n?void 0:t,Br(e,128,void 0,void 0,void 0,void 0,t=e&&null==t?e.length:t)}function bd(e,t){var n;if("function"!=typeof t)throw new ge(a);return e=no(e),function(){return--e>0&&(n=t.apply(this,arguments)),e<=1&&(t=void 0),n}}var vd=Lu((function(e,t,n){var u=1;if(n.length){var r=Wt(n,Zr(vd));u|=32}return Br(e,u,t,n,r)})),gd=Lu((function(e,t,n){var u=3;if(n.length){var r=Wt(n,Zr(gd));u|=32}return Br(t,u,e,n,r)}));function yd(e,t,n){var u,r,d,o,i,c,l=0,f=!1,s=!1,p=!0;if("function"!=typeof e)throw new ge(a);function m(t){var n=u,a=r;return u=r=void 0,l=t,o=e.apply(a,n)}function h(e){return l=e,i=ya(v,t),f?m(e):o}function b(e){var n=e-c;return void 0===c||n>=t||n<0||s&&e-l>=d}function v(){var e=md();if(b(e))return g(e);i=ya(v,function(e){var n=t-(e-c);return s?dn(n,d-(e-l)):n}(e))}function g(e){return i=void 0,p&&u?m(e):(u=r=void 0,o)}function y(){var e=md(),n=b(e);if(u=arguments,r=this,c=e,n){if(void 0===i)return h(c);if(s)return lr(i),i=ya(v,t),m(c)}return void 0===i&&(i=ya(v,t)),o}return t=ro(t)||0,Wd(n)&&(f=!!n.leading,d=(s="maxWait"in n)?an(ro(n.maxWait)||0,t):d,p="trailing"in n?!!n.trailing:p),y.cancel=function(){void 0!==i&&lr(i),l=0,u=c=r=i=void 0},y.flush=function(){return void 0===i?o:g(md())},y}var _d=Lu((function(e,t){return Qn(e,1,t)})),Ed=Lu((function(e,t,n){return Qn(e,ro(t)||0,n)}));function wd(e,t){if("function"!=typeof e||null!=t&&"function"!=typeof t)throw new ge(a);var n=function(){var u=arguments,r=t?t.apply(this,u):u[0],a=n.cache;if(a.has(r))return a.get(r);var d=e.apply(this,u);return n.cache=a.set(r,d)||a,d};return n.cache=new(wd.Cache||Pn),n}function Dd(e){if("function"!=typeof e)throw new ge(a);return function(){var t=arguments;switch(t.length){case 0:return!e.call(this);case 1:return!e.call(this,t[0]);case 2:return!e.call(this,t[0],t[1]);case 3:return!e.call(this,t[0],t[1],t[2])}return!e.apply(this,t)}}wd.Cache=Pn;var kd=ir((function(e,t){var n=(t=1==t.length&&Nd(t[0])?pt(t[0],At(Jr())):pt(au(t,1),At(Jr()))).length;return Lu((function(u){for(var r=-1,a=dn(u.length,n);++r=t})),jd=yu(function(){return arguments}())?yu:function(e){return Hd(e)&&ke.call(e,"callee")&&!Ke.call(e,"callee")},Nd=u.isArray,Fd=Xe?At(Xe):function(e){return Hd(e)&&pu(e)==D};function Td(e){return null!=e&&Ud(e.length)&&!Bd(e)}function Pd(e){return Hd(e)&&Td(e)}var Md=tn||ai,Rd=et?At(et):function(e){return Hd(e)&&pu(e)==f};function Ld(e){if(!Hd(e))return!1;var t=pu(e);return t==s||"[object DOMException]"==t||"string"==typeof e.message&&"string"==typeof e.name&&!Gd(e)}function Bd(e){if(!Wd(e))return!1;var t=pu(e);return t==p||t==m||"[object AsyncFunction]"==t||"[object Proxy]"==t}function zd(e){return"number"==typeof e&&e==no(e)}function Ud(e){return"number"==typeof e&&e>-1&&e%1==0&&e<=9007199254740991}function Wd(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}function Hd(e){return null!=e&&"object"==typeof e}var $d=tt?At(tt):function(e){return Hd(e)&&na(e)==h};function qd(e){return"number"==typeof e||Hd(e)&&pu(e)==b}function Gd(e){if(!Hd(e)||pu(e)!=v)return!1;var t=qe(e);if(null===t)return!0;var n=ke.call(t,"constructor")&&t.constructor;return"function"==typeof n&&n instanceof n&&De.call(n)==Oe}var Vd=nt?At(nt):function(e){return Hd(e)&&pu(e)==g};var Kd=ut?At(ut):function(e){return Hd(e)&&na(e)==y};function Zd(e){return"string"==typeof e||!Nd(e)&&Hd(e)&&pu(e)==_}function Jd(e){return"symbol"==typeof e||Hd(e)&&pu(e)==E}var Yd=rt?At(rt):function(e){return Hd(e)&&Ud(e.length)&&!!ze[pu(e)]};var Qd=Tr(Su),Xd=Tr((function(e,t){return e<=t}));function eo(e){if(!e)return[];if(Td(e))return Zd(e)?Gt(e):vr(e);if(Qe&&e[Qe])return function(e){for(var t,n=[];!(t=e.next()).done;)n.push(t.value);return n}(e[Qe]());var t=na(e);return(t==h?zt:t==y?Ht:Io)(e)}function to(e){return e?(e=ro(e))===1/0||e===-1/0?17976931348623157e292*(e<0?-1:1):e==e?e:0:0===e?e:0}function no(e){var t=to(e),n=t%1;return t==t?n?t-n:t:0}function uo(e){return e?Zn(no(e),0,4294967295):0}function ro(e){if("number"==typeof e)return e;if(Jd(e))return NaN;if(Wd(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=Wd(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(K,"");var n=ae.test(e);return n||oe.test(e)?$e(e.slice(2),n?2:8):re.test(e)?NaN:+e}function ao(e){return gr(e,Eo(e))}function oo(e){return null==e?"":Yu(e)}var io=_r((function(e,t){if(fa(t)||Td(t))gr(t,_o(t),e);else for(var n in t)ke.call(t,n)&&Hn(e,n,t[n])})),co=_r((function(e,t){gr(t,Eo(t),e)})),lo=_r((function(e,t,n,u){gr(t,Eo(t),e,u)})),fo=_r((function(e,t,n,u){gr(t,_o(t),e,u)})),so=$r(Kn);var po=Lu((function(e,t){e=he(e);var n=-1,u=t.length,r=u>2?t[2]:void 0;for(r&&oa(t[0],t[1],r)&&(u=1);++n1),t})),gr(e,Gr(e),n),u&&(n=Jn(n,7,Wr));for(var r=t.length;r--;)Xu(n,t[r]);return n}));var xo=$r((function(e,t){return null==e?{}:function(e,t){return Fu(e,t,(function(t,n){return bo(e,n)}))}(e,t)}));function So(e,t){if(null==e)return{};var n=pt(Gr(e),(function(e){return[e]}));return t=Jr(t),Fu(e,n,(function(e,n){return t(e,n[0])}))}var Co=Lr(_o),Oo=Lr(Eo);function Io(e){return null==e?[]:jt(e,_o(e))}var Ao=kr((function(e,t,n){return t=t.toLowerCase(),e+(n?jo(t):t)}));function jo(e){return Bo(oo(e).toLowerCase())}function No(e){return(e=oo(e))&&e.replace(ce,Mt).replace(Fe,"")}var Fo=kr((function(e,t,n){return e+(n?"-":"")+t.toLowerCase()})),To=kr((function(e,t,n){return e+(n?" ":"")+t.toLowerCase()})),Po=Dr("toLowerCase");var Mo=kr((function(e,t,n){return e+(n?"_":"")+t.toLowerCase()}));var Ro=kr((function(e,t,n){return e+(n?" ":"")+Bo(t)}));var Lo=kr((function(e,t,n){return e+(n?" ":"")+t.toUpperCase()})),Bo=Dr("toUpperCase");function zo(e,t,n){return e=oo(e),void 0===(t=n?void 0:t)?function(e){return Re.test(e)}(e)?function(e){return e.match(Pe)||[]}(e):function(e){return e.match(ee)||[]}(e):e.match(t)||[]}var Uo=Lu((function(e,t){try{return at(e,void 0,t)}catch(n){return Ld(n)?n:new se(n)}})),Wo=$r((function(e,t){return ot(t,(function(t){t=xa(t),Vn(e,t,vd(e[t],e))})),e}));function Ho(e){return function(){return e}}var $o=Cr(),qo=Cr(!0);function Go(e){return e}function Vo(e){return Du("function"==typeof e?e:Jn(e,1))}var Ko=Lu((function(e,t){return function(n){return gu(n,e,t)}})),Zo=Lu((function(e,t){return function(n){return gu(e,n,t)}}));function Jo(e,t,n){var u=_o(t),r=lu(t,u);null!=n||Wd(t)&&(r.length||!u.length)||(n=t,t=e,e=this,r=lu(t,_o(t)));var a=!(Wd(n)&&"chain"in n&&!n.chain),d=Bd(e);return ot(r,(function(n){var u=t[n];e[n]=u,d&&(e.prototype[n]=function(){var t=this.__chain__;if(a||t){var n=e(this.__wrapped__),r=n.__actions__=vr(this.__actions__);return r.push({func:u,args:arguments,thisArg:e}),n.__chain__=t,n}return u.apply(e,mt([this.value()],arguments))})})),e}function Yo(){}var Qo=jr(pt),Xo=jr(ct),ei=jr(vt);function ti(e){return ia(e)?xt(xa(e)):function(e){return function(t){return fu(t,e)}}(e)}var ni=Fr(),ui=Fr(!0);function ri(){return[]}function ai(){return!1}var di=Ar((function(e,t){return e+t}),0),oi=Mr("ceil"),ii=Ar((function(e,t){return e/t}),1),ci=Mr("floor");var li,fi=Ar((function(e,t){return e*t}),1),si=Mr("round"),pi=Ar((function(e,t){return e-t}),0);return On.after=function(e,t){if("function"!=typeof t)throw new ge(a);return e=no(e),function(){if(--e<1)return t.apply(this,arguments)}},On.ary=hd,On.assign=io,On.assignIn=co,On.assignInWith=lo,On.assignWith=fo,On.at=so,On.before=bd,On.bind=vd,On.bindAll=Wo,On.bindKey=gd,On.castArray=function(){if(!arguments.length)return[];var e=arguments[0];return Nd(e)?e:[e]},On.chain=ed,On.chunk=function(e,t,n){t=(n?oa(e,t,n):void 0===t)?1:an(no(t),0);var r=null==e?0:e.length;if(!r||t<1)return[];for(var a=0,d=0,o=u(Qt(r/t));ar?0:r+n),(u=void 0===u||u>r?r:no(u))<0&&(u+=r),u=n>u?0:uo(u);n>>0)?(e=oo(e))&&("string"==typeof t||null!=t&&!Vd(t))&&!(t=Yu(t))&&Bt(e)?cr(Gt(e),0,n):e.split(t,n):[]},On.spread=function(e,t){if("function"!=typeof e)throw new ge(a);return t=null==t?0:an(no(t),0),Lu((function(n){var u=n[t],r=cr(n,0,t);return u&&mt(r,u),at(e,this,r)}))},On.tail=function(e){var t=null==e?0:e.length;return t?qu(e,1,t):[]},On.take=function(e,t,n){return e&&e.length?qu(e,0,(t=n||void 0===t?1:no(t))<0?0:t):[]},On.takeRight=function(e,t,n){var u=null==e?0:e.length;return u?qu(e,(t=u-(t=n||void 0===t?1:no(t)))<0?0:t,u):[]},On.takeRightWhile=function(e,t){return e&&e.length?tr(e,Jr(t,3),!1,!0):[]},On.takeWhile=function(e,t){return e&&e.length?tr(e,Jr(t,3)):[]},On.tap=function(e,t){return t(e),e},On.throttle=function(e,t,n){var u=!0,r=!0;if("function"!=typeof e)throw new ge(a);return Wd(n)&&(u="leading"in n?!!n.leading:u,r="trailing"in n?!!n.trailing:r),yd(e,t,{leading:u,maxWait:t,trailing:r})},On.thru=td,On.toArray=eo,On.toPairs=Co,On.toPairsIn=Oo,On.toPath=function(e){return Nd(e)?pt(e,xa):Jd(e)?[e]:vr(ka(oo(e)))},On.toPlainObject=ao,On.transform=function(e,t,n){var u=Nd(e),r=u||Md(e)||Yd(e);if(t=Jr(t,4),null==n){var a=e&&e.constructor;n=r?u?new a:[]:Wd(e)&&Bd(a)?In(qe(e)):{}}return(r?ot:iu)(e,(function(e,u,r){return t(n,e,u,r)})),n},On.unary=function(e){return hd(e,1)},On.union=Ha,On.unionBy=$a,On.unionWith=qa,On.uniq=function(e){return e&&e.length?Qu(e):[]},On.uniqBy=function(e,t){return e&&e.length?Qu(e,Jr(t,2)):[]},On.uniqWith=function(e,t){return t="function"==typeof t?t:void 0,e&&e.length?Qu(e,void 0,t):[]},On.unset=function(e,t){return null==e||Xu(e,t)},On.unzip=Ga,On.unzipWith=Va,On.update=function(e,t,n){return null==e?e:er(e,t,dr(n))},On.updateWith=function(e,t,n,u){return u="function"==typeof u?u:void 0,null==e?e:er(e,t,dr(n),u)},On.values=Io,On.valuesIn=function(e){return null==e?[]:jt(e,Eo(e))},On.without=Ka,On.words=zo,On.wrap=function(e,t){return xd(dr(t),e)},On.xor=Za,On.xorBy=Ja,On.xorWith=Ya,On.zip=Qa,On.zipObject=function(e,t){return rr(e||[],t||[],Hn)},On.zipObjectDeep=function(e,t){return rr(e||[],t||[],Uu)},On.zipWith=Xa,On.entries=Co,On.entriesIn=Oo,On.extend=co,On.extendWith=lo,Jo(On,On),On.add=di,On.attempt=Uo,On.camelCase=Ao,On.capitalize=jo,On.ceil=oi,On.clamp=function(e,t,n){return void 0===n&&(n=t,t=void 0),void 0!==n&&(n=(n=ro(n))==n?n:0),void 0!==t&&(t=(t=ro(t))==t?t:0),Zn(ro(e),t,n)},On.clone=function(e){return Jn(e,4)},On.cloneDeep=function(e){return Jn(e,5)},On.cloneDeepWith=function(e,t){return Jn(e,5,t="function"==typeof t?t:void 0)},On.cloneWith=function(e,t){return Jn(e,4,t="function"==typeof t?t:void 0)},On.conformsTo=function(e,t){return null==t||Yn(e,t,_o(t))},On.deburr=No,On.defaultTo=function(e,t){return null==e||e!=e?t:e},On.divide=ii,On.endsWith=function(e,t,n){e=oo(e),t=Yu(t);var u=e.length,r=n=void 0===n?u:Zn(no(n),0,u);return(n-=t.length)>=0&&e.slice(n,r)==t},On.eq=Od,On.escape=function(e){return(e=oo(e))&&B.test(e)?e.replace(R,Rt):e},On.escapeRegExp=function(e){return(e=oo(e))&&V.test(e)?e.replace(G,"\\$&"):e},On.every=function(e,t,n){var u=Nd(e)?ct:nu;return n&&oa(e,t,n)&&(t=void 0),u(e,Jr(t,3))},On.find=rd,On.findIndex=ja,On.findKey=function(e,t){return yt(e,Jr(t,3),iu)},On.findLast=ad,On.findLastIndex=Na,On.findLastKey=function(e,t){return yt(e,Jr(t,3),cu)},On.floor=ci,On.forEach=dd,On.forEachRight=od,On.forIn=function(e,t){return null==e?e:du(e,Jr(t,3),Eo)},On.forInRight=function(e,t){return null==e?e:ou(e,Jr(t,3),Eo)},On.forOwn=function(e,t){return e&&iu(e,Jr(t,3))},On.forOwnRight=function(e,t){return e&&cu(e,Jr(t,3))},On.get=ho,On.gt=Id,On.gte=Ad,On.has=function(e,t){return null!=e&&ua(e,t,hu)},On.hasIn=bo,On.head=Ta,On.identity=Go,On.includes=function(e,t,n,u){e=Td(e)?e:Io(e),n=n&&!u?no(n):0;var r=e.length;return n<0&&(n=an(r+n,0)),Zd(e)?n<=r&&e.indexOf(t,n)>-1:!!r&&Et(e,t,n)>-1},On.indexOf=function(e,t,n){var u=null==e?0:e.length;if(!u)return-1;var r=null==n?0:no(n);return r<0&&(r=an(u+r,0)),Et(e,t,r)},On.inRange=function(e,t,n){return t=to(t),void 0===n?(n=t,t=0):n=to(n),function(e,t,n){return e>=dn(t,n)&&e=-9007199254740991&&e<=9007199254740991},On.isSet=Kd,On.isString=Zd,On.isSymbol=Jd,On.isTypedArray=Yd,On.isUndefined=function(e){return void 0===e},On.isWeakMap=function(e){return Hd(e)&&na(e)==w},On.isWeakSet=function(e){return Hd(e)&&"[object WeakSet]"==pu(e)},On.join=function(e,t){return null==e?"":un.call(e,t)},On.kebabCase=Fo,On.last=La,On.lastIndexOf=function(e,t,n){var u=null==e?0:e.length;if(!u)return-1;var r=u;return void 0!==n&&(r=(r=no(n))<0?an(u+r,0):dn(r,u-1)),t==t?function(e,t,n){for(var u=n+1;u--;)if(e[u]===t)return u;return u}(e,t,r):_t(e,Dt,r,!0)},On.lowerCase=To,On.lowerFirst=Po,On.lt=Qd,On.lte=Xd,On.max=function(e){return e&&e.length?uu(e,Go,mu):void 0},On.maxBy=function(e,t){return e&&e.length?uu(e,Jr(t,2),mu):void 0},On.mean=function(e){return kt(e,Go)},On.meanBy=function(e,t){return kt(e,Jr(t,2))},On.min=function(e){return e&&e.length?uu(e,Go,Su):void 0},On.minBy=function(e,t){return e&&e.length?uu(e,Jr(t,2),Su):void 0},On.stubArray=ri,On.stubFalse=ai,On.stubObject=function(){return{}},On.stubString=function(){return""},On.stubTrue=function(){return!0},On.multiply=fi,On.nth=function(e,t){return e&&e.length?ju(e,no(t)):void 0},On.noConflict=function(){return Ve._===this&&(Ve._=Ie),this},On.noop=Yo,On.now=md,On.pad=function(e,t,n){e=oo(e);var u=(t=no(t))?qt(e):0;if(!t||u>=t)return e;var r=(t-u)/2;return Nr(Xt(r),n)+e+Nr(Qt(r),n)},On.padEnd=function(e,t,n){e=oo(e);var u=(t=no(t))?qt(e):0;return t&&ut){var u=e;e=t,t=u}if(n||e%1||t%1){var r=ln();return dn(e+r*(t-e+He("1e-"+((r+"").length-1))),t)}return Mu(e,t)},On.reduce=function(e,t,n){var u=Nd(e)?ht:Ct,r=arguments.length<3;return u(e,Jr(t,4),n,r,eu)},On.reduceRight=function(e,t,n){var u=Nd(e)?bt:Ct,r=arguments.length<3;return u(e,Jr(t,4),n,r,tu)},On.repeat=function(e,t,n){return t=(n?oa(e,t,n):void 0===t)?1:no(t),Ru(oo(e),t)},On.replace=function(){var e=arguments,t=oo(e[0]);return e.length<3?t:t.replace(e[1],e[2])},On.result=function(e,t,n){var u=-1,r=(t=or(t,e)).length;for(r||(r=1,e=void 0);++u9007199254740991)return[];var n=4294967295,u=dn(e,4294967295);e-=4294967295;for(var r=It(u,t=Jr(t));++n=a)return e;var o=n-qt(u);if(o<1)return u;var i=d?cr(d,0,o).join(""):e.slice(0,o);if(void 0===r)return i+u;if(d&&(o+=i.length-o),Vd(r)){if(e.slice(o).search(r)){var c,l=i;for(r.global||(r=be(r.source,oo(ue.exec(r))+"g")),r.lastIndex=0;c=r.exec(l);)var f=c.index;i=i.slice(0,void 0===f?o:f)}}else if(e.indexOf(Yu(r),o)!=o){var s=i.lastIndexOf(r);s>-1&&(i=i.slice(0,s))}return i+u},On.unescape=function(e){return(e=oo(e))&&L.test(e)?e.replace(M,Vt):e},On.uniqueId=function(e){var t=++xe;return oo(e)+t},On.upperCase=Lo,On.upperFirst=Bo,On.each=dd,On.eachRight=od,On.first=Ta,Jo(On,(li={},iu(On,(function(e,t){ke.call(On.prototype,t)||(li[t]=e)})),li),{chain:!1}),On.VERSION="4.17.15",ot(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(e){On[e].placeholder=On})),ot(["drop","take"],(function(e,t){Nn.prototype[e]=function(n){n=void 0===n?1:an(no(n),0);var u=this.__filtered__&&!t?new Nn(this):this.clone();return u.__filtered__?u.__takeCount__=dn(n,u.__takeCount__):u.__views__.push({size:dn(n,4294967295),type:e+(u.__dir__<0?"Right":"")}),u},Nn.prototype[e+"Right"]=function(t){return this.reverse()[e](t).reverse()}})),ot(["filter","map","takeWhile"],(function(e,t){var n=t+1,u=1==n||3==n;Nn.prototype[e]=function(e){var t=this.clone();return t.__iteratees__.push({iteratee:Jr(e,3),type:n}),t.__filtered__=t.__filtered__||u,t}})),ot(["head","last"],(function(e,t){var n="take"+(t?"Right":"");Nn.prototype[e]=function(){return this[n](1).value()[0]}})),ot(["initial","tail"],(function(e,t){var n="drop"+(t?"":"Right");Nn.prototype[e]=function(){return this.__filtered__?new Nn(this):this[n](1)}})),Nn.prototype.compact=function(){return this.filter(Go)},Nn.prototype.find=function(e){return this.filter(e).head()},Nn.prototype.findLast=function(e){return this.reverse().find(e)},Nn.prototype.invokeMap=Lu((function(e,t){return"function"==typeof e?new Nn(this):this.map((function(n){return gu(n,e,t)}))})),Nn.prototype.reject=function(e){return this.filter(Dd(Jr(e)))},Nn.prototype.slice=function(e,t){e=no(e);var n=this;return n.__filtered__&&(e>0||t<0)?new Nn(n):(e<0?n=n.takeRight(-e):e&&(n=n.drop(e)),void 0!==t&&(n=(t=no(t))<0?n.dropRight(-t):n.take(t-e)),n)},Nn.prototype.takeRightWhile=function(e){return this.reverse().takeWhile(e).reverse()},Nn.prototype.toArray=function(){return this.take(4294967295)},iu(Nn.prototype,(function(e,t){var n=/^(?:filter|find|map|reject)|While$/.test(t),u=/^(?:head|last)$/.test(t),r=On[u?"take"+("last"==t?"Right":""):t],a=u||/^find/.test(t);r&&(On.prototype[t]=function(){var t=this.__wrapped__,d=u?[1]:arguments,o=t instanceof Nn,i=d[0],c=o||Nd(t),l=function(e){var t=r.apply(On,mt([e],d));return u&&f?t[0]:t};c&&n&&"function"==typeof i&&1!=i.length&&(o=c=!1);var f=this.__chain__,s=!!this.__actions__.length,p=a&&!f,m=o&&!s;if(!a&&c){t=m?t:new Nn(this);var h=e.apply(t,d);return h.__actions__.push({func:td,args:[l],thisArg:void 0}),new jn(h,f)}return p&&m?e.apply(this,d):(h=this.thru(l),p?u?h.value()[0]:h.value():h)})})),ot(["pop","push","shift","sort","splice","unshift"],(function(e){var t=ye[e],n=/^(?:push|sort|unshift)$/.test(e)?"tap":"thru",u=/^(?:pop|shift)$/.test(e);On.prototype[e]=function(){var e=arguments;if(u&&!this.__chain__){var r=this.value();return t.apply(Nd(r)?r:[],e)}return this[n]((function(n){return t.apply(Nd(n)?n:[],e)}))}})),iu(Nn.prototype,(function(e,t){var n=On[t];if(n){var u=n.name+"";ke.call(yn,u)||(yn[u]=[]),yn[u].push({name:t,func:n})}})),yn[Or(void 0,2).name]=[{name:"wrapper",func:void 0}],Nn.prototype.clone=function(){var e=new Nn(this.__wrapped__);return e.__actions__=vr(this.__actions__),e.__dir__=this.__dir__,e.__filtered__=this.__filtered__,e.__iteratees__=vr(this.__iteratees__),e.__takeCount__=this.__takeCount__,e.__views__=vr(this.__views__),e},Nn.prototype.reverse=function(){if(this.__filtered__){var e=new Nn(this);e.__dir__=-1,e.__filtered__=!0}else(e=this.clone()).__dir__*=-1;return e},Nn.prototype.value=function(){var e=this.__wrapped__.value(),t=this.__dir__,n=Nd(e),u=t<0,r=n?e.length:0,a=function(e,t,n){var u=-1,r=n.length;for(;++u=this.__values__.length;return{done:e,value:e?void 0:this.__values__[this.__index__++]}},On.prototype.plant=function(e){for(var t,n=this;n instanceof An;){var u=Ca(n);u.__index__=0,u.__values__=void 0,t?r.__wrapped__=u:t=u;var r=u;n=n.__wrapped__}return r.__wrapped__=e,t},On.prototype.reverse=function(){var e=this.__wrapped__;if(e instanceof Nn){var t=e;return this.__actions__.length&&(t=new Nn(this)),(t=t.reverse()).__actions__.push({func:td,args:[Wa],thisArg:void 0}),new jn(t,this.__chain__)}return this.thru(Wa)},On.prototype.toJSON=On.prototype.valueOf=On.prototype.value=function(){return nr(this.__wrapped__,this.__actions__)},On.prototype.first=On.prototype.head,Qe&&(On.prototype[Qe]=function(){return this}),On}();Ve._=Kt,void 0===(r=function(){return Kt}.call(t,n,t,u))||(u.exports=r)}).call(this)}).call(this,n(76),n(453)(e))},449:function(e,t,n){"use strict";var u=n(0);t.a=function(e){void 0===e&&(e=!0),Object(u.useEffect)((function(){return document.body.style.overflow=e?"hidden":"visible",function(){document.body.style.overflow="visible"}}),[e])}},450:function(e,t,n){"use strict";var u=n(433),r=n(438),a=n(435),d=n(430);t.a=function(){var e=Object(u.a)().siteConfig,t=(e=void 0===e?{}:e).baseUrl,n=e.themeConfig.navbar,o=(n=void 0===n?{}:n).logo,i=void 0===o?{}:o,c=Object(r.a)().isDarkTheme,l=i.href||t,f={};i.target?f={target:i.target}:Object(d.a)(l)||(f={rel:"noopener noreferrer",target:"_blank"});var s=i.srcDark&&c?i.srcDark:i.src;return{logoLink:l,logoLinkProps:f,logoImageUrl:Object(a.a)(s),logoAlt:i.alt}}},452:function(e,t,n){"use strict";n.d(t,"a",(function(){return a}));n(77),n(470),n(436),n(78);var u=n(472),r=n.n(u);function a(e,t){var n=new r.a;return e.map((function(e){var u=e;return"string"==typeof e&&(u={label:e,permalink:"/blog/tags/"+n.slug(e)}),function(e,t){var n=e.label.split(": ",2),u=n[0],r=n[1],a="primary";switch(t){case"blog":case"guides":a=function(e){switch(e){case"domain":return"blue";case"type":return"pink";default:return"primary"}}(u)}return{category:u,count:e.count,label:e.label,permalink:e.permalink,style:a,value:r}}(u,t)}))}},453:function(e,t){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),e.webpackPolyfill=1),e}},454:function(e,t,n){"use strict";var u=n(12),r=n(26),a=n(514),d="".endsWith;u(u.P+u.F*n(515)("endsWith"),"String",{endsWith:function(e){var t=a(this,e,"endsWith"),n=arguments.length>1?arguments[1]:void 0,u=r(t.length),o=void 0===n?u:Math.min(r(n),u),i=String(e);return d?d.call(t,i,o):t.slice(o-i.length,o)===i}})},455:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(433),d=n(145),o=n.n(d);t.a=function(){var e=Object(a.a)().siteConfig,t=(e=void 0===e?{}:e).themeConfig.announcementBar,n=void 0===t?{}:t,d=n.id,i=n.content,c=n.backgroundColor,l=n.textColor,f=Object(u.useState)(!0),s=f[0],p=f[1];return Object(u.useEffect)((function(){var e=localStorage.getItem("docusaurus.announcement.id"),t=d!==e;localStorage.setItem("docusaurus.announcement.id",d),t&&localStorage.setItem("docusaurus.announcement.dismiss",!1),(t||"false"===localStorage.getItem("docusaurus.announcement.dismiss"))&&p(!1)}),[]),!i||s?null:r.a.createElement("div",{className:o.a.announcementBar,style:{backgroundColor:c,color:l},role:"banner"},r.a.createElement("div",{className:o.a.announcementBarContent,dangerouslySetInnerHTML:{__html:i}}),r.a.createElement("button",{type:"button",className:o.a.announcementBarClose,onClick:function(){localStorage.setItem("docusaurus.announcement.dismiss",!0),p(!0)},"aria-label":"Close"},r.a.createElement("span",{"aria-hidden":"true"},"\xd7")))}},456:function(e,t,n){"use strict";var u=n(0);u.PureComponent},457:function(e,t,n){"use strict";n(58),n(29),n(22),n(21),n(79);var u=n(0),r=n.n(u),a=n(420),d=n.n(a),o=n(433),i=n(469);n(146);t.a=function(e){var t=Object(u.useState)(!1),a=t[0],c=t[1],l=Object(u.useRef)(null),f=Object(o.a)().siteConfig,s=(void 0===f?{}:f).themeConfig.algolia,p=Object(i.c)();var m=function(e){void 0===e&&(e=!0),a||Promise.all([n.e(266).then(n.t.bind(null,567,7)),n.e(173).then(n.t.bind(null,580,7))]).then((function(t){var n=t[0].default;c(!0),window.docsearch=n,function(e){window.docsearch({appId:s.appId,apiKey:s.apiKey,indexName:s.indexName,inputSelector:"#search_input_react",algoliaOptions:s.algoliaOptions,handleSelected:function(e,t,n){var u=document.createElement("a");u.href=n.url;var r="#__docusaurus"===u.hash?""+u.pathname:""+u.pathname+u.hash;p.push(r)}}),e&&l.current.focus()}(e)}))},h=Object(u.useCallback)((function(){m(),a&&l.current.focus(),e.handleSearchBarToggle(!e.isSearchBarExpanded)}),[e.isSearchBarExpanded]),b=Object(u.useCallback)((function(){e.handleSearchBarToggle(!e.isSearchBarExpanded)}),[e.isSearchBarExpanded]),v=Object(u.useCallback)((function(e){var t="mouseover"!==e.type;m(t)}));return r.a.createElement("div",{className:"navbar__search",key:"search-box"},r.a.createElement("span",{"aria-label":"expand searchbar",role:"button",className:d()("search-icon",{"search-icon-hidden":e.isSearchBarExpanded}),onClick:h,onKeyDown:h,tabIndex:0}),r.a.createElement("input",{id:"search_input_react",type:"search",placeholder:"Search","aria-label":"Search",className:d()("navbar__search-input",{"search-bar-expanded":e.isSearchBarExpanded},{"search-bar":!e.isSearchBarExpanded}),onMouseOver:v,onFocus:v,onBlur:b,ref:l}))}},458:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u=Object.assign||function(e){for(var t=1;tthis.startX&&(this.setState({checked:!0}),this.startX=t,this.activated=tn?this.previouslyChecked!==this.state.checked&&(this.setState({checked:!1}),this.previouslyChecked=this.state.checked,t.click()):this.startX-4=0||Object.prototype.hasOwnProperty.call(e,u)&&(n[u]=e[u]);return n}(t,["className","icons"])),a=(0,o.default)("react-toggle",{"react-toggle--checked":this.state.checked,"react-toggle--focus":this.state.hasFocus,"react-toggle--disabled":this.props.disabled},n);return d.default.createElement("div",{className:a,onClick:this.handleClick,onTouchStart:this.handleTouchStart,onTouchMove:this.handleTouchMove,onTouchEnd:this.handleTouchEnd},d.default.createElement("div",{className:"react-toggle-track"},d.default.createElement("div",{className:"react-toggle-track-check"},this.getIcon("checked")),d.default.createElement("div",{className:"react-toggle-track-x"},this.getIcon("unchecked"))),d.default.createElement("div",{className:"react-toggle-thumb"}),d.default.createElement("input",u({},r,{ref:function(t){e.input=t},onFocus:this.handleFocus,onBlur:this.handleBlur,className:"react-toggle-screenreader-only",type:"checkbox"})))}}]),t}(a.PureComponent);t.default=p,p.displayName="Toggle",p.defaultProps={icons:{checked:d.default.createElement(c.default,null),unchecked:d.default.createElement(l.default,null)}},p.propTypes={checked:i.default.bool,disabled:i.default.bool,defaultChecked:i.default.bool,onChange:i.default.func,onFocus:i.default.func,onBlur:i.default.func,className:i.default.string,name:i.default.string,value:i.default.string,id:i.default.string,"aria-labelledby":i.default.string,"aria-label":i.default.string,icons:i.default.oneOfType([i.default.bool,i.default.shape({checked:i.default.node,unchecked:i.default.node})])}},459:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=(n(84),n(470),function(){var e=Object(u.useState)({}),t=e[0],n=e[1],r=Object(u.useCallback)((function(e,t){try{localStorage.setItem("docusaurus.tab."+e,t)}catch(n){console.error(n)}}),[]);return Object(u.useEffect)((function(){try{for(var e={},t=0;t=f?d(!1):e+n1&&"boolean"!=typeof t)throw new a('"allowMissing" argument must be a boolean');if(null===w(/^%?[^%]*%?$/,e))throw new u("`%` may not be present anywhere but at the beginning and end of the intrinsic name");var n=x(e),r=n.length>0?n[0]:"",d=S("%"+r+"%",t),i=d.name,c=d.value,l=!1,f=d.alias;f&&(r=f[0],y(n,g([0,1],f)));for(var s=1,p=!0;s=n.length){var D=o(c,h);c=(p=!!D)&&"get"in D&&!("originalValue"in D.get)?D.get:c[h]}else p=v(c,h),c=c[h];p&&!l&&(m[i]=c)}}return c}},467:function(e,t,n){"use strict";var u=n(506);e.exports=Function.prototype.bind||u},468:function(e,t,n){"use strict";var u=String.prototype.replace,r=/%20/g,a="RFC1738",d="RFC3986";e.exports={default:d,formatters:{RFC1738:function(e){return u.call(e,r,"+")},RFC3986:function(e){return String(e)}},RFC1738:a,RFC3986:d}},469:function(e,t,n){"use strict";var u=n(39);n.d(t,"a",(function(){return u.c})),n.d(t,"b",(function(){return u.d})),n.d(t,"c",(function(){return u.e})),n.d(t,"d",(function(){return u.f}))},471:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(427),d=n(420),o=n.n(d);t.a=function(e){var t=e.count,n=e.label,u=e.permalink,d=e.style,i=e.value,c=e.valueOnly;return r.a.createElement(a.a,{to:u+"/",className:o()("badge","badge--rounded","badge--"+d)},c?i:n,t&&r.a.createElement(r.a.Fragment,null," (",t,")"))}},472:function(e,t,n){var u=n(473);e.exports=o;var r=Object.hasOwnProperty,a=/\s/g,d=/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~\u2019]/g;function o(){if(!(this instanceof o))return new o;this.reset()}function i(e,t){return"string"!=typeof e?"":(t||(e=e.toLowerCase()),e.trim().replace(d,"").replace(u(),"").replace(a,"-"))}o.prototype.slug=function(e,t){for(var n=i(e,!0===t),u=n;r.call(this.occurrences,n);)this.occurrences[u]++,n=u+"-"+this.occurrences[u];return this.occurrences[n]=0,n},o.prototype.reset=function(){this.occurrences=Object.create(null)},o.slug=i},473:function(e,t){e.exports=function(){return/[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD79\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED0\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3]|\uD83E[\uDD10-\uDD18\uDD80-\uDD84\uDDC0]|\uD83C\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uD83C\uDDFE\uD83C[\uDDEA\uDDF9]|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDFC\uD83C[\uDDEB\uDDF8]|\uD83C\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uD83C\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF8\uDDFE\uDDFF]|\uD83C\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uD83C\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uD83C\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uD83C\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uD83C\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uD83C\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uD83C\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uD83C\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uD83C\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uD83C\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uD83C\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uD83C\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uD83C\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uD83C\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uD83C\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uD83C\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|[#\*0-9]\u20E3/g}},475:function(e,t,n){"use strict";var u=n(468),r=Object.prototype.hasOwnProperty,a=Array.isArray,d=function(){for(var e=[],t=0;t<256;++t)e.push("%"+((t<16?"0":"")+t.toString(16)).toUpperCase());return e}(),o=function(e,t){for(var n=t&&t.plainObjects?Object.create(null):{},u=0;u1;){var t=e.pop(),n=t.obj[t.prop];if(a(n)){for(var u=[],r=0;r=48&&l<=57||l>=65&&l<=90||l>=97&&l<=122||a===u.RFC1738&&(40===l||41===l)?i+=o.charAt(c):l<128?i+=d[l]:l<2048?i+=d[192|l>>6]+d[128|63&l]:l<55296||l>=57344?i+=d[224|l>>12]+d[128|l>>6&63]+d[128|63&l]:(c+=1,l=65536+((1023&l)<<10|1023&o.charCodeAt(c)),i+=d[240|l>>18]+d[128|l>>12&63]+d[128|l>>6&63]+d[128|63&l])}return i},isBuffer:function(e){return!(!e||"object"!=typeof e)&&!!(e.constructor&&e.constructor.isBuffer&&e.constructor.isBuffer(e))},isRegExp:function(e){return"[object RegExp]"===Object.prototype.toString.call(e)},maybeMap:function(e,t){if(a(e)){for(var n=[],u=0;u{if("string"!=typeof e)throw new TypeError("Expected a string");return e=(e=(e=u(e)).toLowerCase().replace(/[_-]+/g," ").replace(/\s{2,}/g," ").trim()).charAt(0).toUpperCase()+e.slice(1)};e.exports=r,e.exports.default=r},482:function(e,t,n){"use strict";var u=n(0),r=n.n(u).a.createContext({isDarkTheme:!1,setLightTheme:function(){},setDarkTheme:function(){}});t.a=r},484:function(e,t,n){"use strict";(function(e){var u=n(1),r=(n(443),n(444),n(78),n(77),n(527),n(0)),a=n.n(r),d=n(528),o=n.n(d),i=n(560),c=n(53),l=n(420),f=n.n(l),s=n(540),p=n.n(s),m=n(529),h=n.n(m),b=n(433),v=n(438),g=n(148),y=n.n(g);(void 0!==e?e:window).Prism=c.a,n(530),n(531),n(532),n(533),n(90),n(534),n(535),n(536),n(537),n(538),n(539);var _=/{([\d,-]+)}/,E=/title=".*"/;t.a=function(e){var t=e.children,n=e.className,d=e.metastring,c=Object(b.a)().siteConfig.themeConfig.prism,l=void 0===c?{}:c,s=Object(r.useState)(!1),m=s[0],g=s[1],w=Object(r.useState)(!1),D=w[0],k=w[1];Object(r.useEffect)((function(){k(!0)}),[]);var x=Object(r.useRef)(null),S=Object(r.useRef)(null),C=[],O="",I=Object(v.a)().isDarkTheme,A=l.theme||p.a,j=l.darkTheme||A,N=I?j:A;if(d&&_.test(d)){var F=d.match(_)[1];C=h.a.parse(F).filter((function(e){return e>0}))}d&&E.test(d)&&(O=d.match(E)[0].split("title=")[1].replace(/"+/g,"")),Object(r.useEffect)((function(){var e;return S.current&&(e=new o.a(S.current,{target:function(){return x.current}})),function(){e&&e.destroy()}}),[S.current,x.current]);var T=n&&n.replace(/language-/,"");!T&&l.defaultLanguage&&(T=l.defaultLanguage);var P=function(){window.getSelection().empty(),g(!0),setTimeout((function(){return g(!1)}),2e3)};return a.a.createElement(i.a,Object(u.a)({},i.b,{key:D,theme:N,code:t.trim(),language:T}),(function(e){var t,n,r=e.className,d=e.style,o=e.tokens,i=e.getLineProps,c=e.getTokenProps;return a.a.createElement(a.a.Fragment,null,O&&a.a.createElement("div",{style:d,className:y.a.codeBlockTitle},O),a.a.createElement("div",{className:y.a.codeBlockContent},a.a.createElement("button",{ref:S,type:"button","aria-label":"Copy code to clipboard",className:f()(y.a.copyButton,(t={},t[y.a.copyButtonWithTitle]=O,t)),onClick:P},m?"Copied":"Copy"),a.a.createElement("pre",{className:f()(r,y.a.codeBlock,(n={},n[y.a.codeBlockWithTitle]=O,n))},a.a.createElement("div",{ref:x,className:y.a.codeBlockLines,style:d},o.map((function(e,t){1===e.length&&""===e[0].content&&(e[0].content="\n");var n=i({line:e,key:t});return C.includes(t+1)&&(n.className=n.className+" docusaurus-highlight-code-line"),a.a.createElement("div",Object(u.a)({key:t},n),e.map((function(e,t){return a.a.createElement("span",Object(u.a)({key:t},c({token:e,key:t})))})))}))))))}))}}).call(this,n(76))},485:function(e,t,n){"use strict";var u=n(0),r=n.n(u);n(421),n(144);t.a=function(e){var t=e.children,n=Object(u.useState)(!1),a=n[0],d=n[1];return a?r.a.createElement("div",{className:"code-explanation code-explanation--expanded"},t,r.a.createElement("div",{className:"code-explanation--toggle",onClick:function(){return d(!a)}},r.a.createElement("i",{className:"feather icon-arrow-up-circle"})," hide")):r.a.createElement("div",{className:"code-explanation code-explanation--collapsed"},r.a.createElement("div",{className:"code-explanation--toggle",onClick:function(){return d(!a)}},r.a.createElement("i",{className:"feather icon-info"})," explain this command"))}},486:function(e,t,n){"use strict";var u=n(30),r=n(12),a=n(27),d=n(91),o=n(92),i=n(26),c=n(542),l=n(93);r(r.S+r.F*!n(83)((function(e){Array.from(e)})),"Array",{from:function(e){var t,n,r,f,s=a(e),p="function"==typeof this?this:Array,m=arguments.length,h=m>1?arguments[1]:void 0,b=void 0!==h,v=0,g=l(s);if(b&&(h=u(h,m>2?arguments[2]:void 0,2)),null==g||p==Array&&o(g))for(n=new p(t=i(s.length));t>v;v++)c(n,v,b?h(s[v],v):s[v]);else for(f=g.call(s),n=new p;!(r=f.next()).done;v++)c(n,v,b?d(f,h,[r.value,v],!0):r.value);return n.length=v,n}})},487:function(e,t,n){"use strict";var u=n(543),r=n(489);e.exports=n(544)("Set",(function(e){return function(){return e(this,arguments.length>0?arguments[0]:void 0)}}),{add:function(e){return u.def(r(this,"Set"),e=0===e?0:e,e)}},u)},488:function(e,t,n){var u=n(40)("meta"),r=n(13),a=n(31),d=n(28).f,o=0,i=Object.isExtensible||function(){return!0},c=!n(14)((function(){return i(Object.preventExtensions({}))})),l=function(e){d(e,u,{value:{i:"O"+ ++o,w:{}}})},f=e.exports={KEY:u,NEED:!1,fastKey:function(e,t){if(!r(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!a(e,u)){if(!i(e))return"F";if(!t)return"E";l(e)}return e[u].i},getWeak:function(e,t){if(!a(e,u)){if(!i(e))return!0;if(!t)return!1;l(e)}return e[u].w},onFreeze:function(e){return c&&f.NEED&&i(e)&&!a(e,u)&&l(e),e}}},489:function(e,t,n){var u=n(13);e.exports=function(e,t){if(!u(e)||e._t!==t)throw TypeError("Incompatible receiver, "+t+" required!");return e}},490:function(e,t,n){"use strict";const u=n(491);e.exports=(e,t)=>{if("string"!=typeof e)throw new TypeError("Expected a string");t=void 0===t?"_":t;const n=u("([\\p{Ll}\\d])(\\p{Lu})","g"),r=u("(\\p{Lu}+)(\\p{Lu}[\\p{Ll}\\d]+)","g");return e.replace(n,`$1${t}$2`).replace(r,`$1${t}$2`).toLowerCase()}},491:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u=f(n(492)),r=f(n(493)),a=f(n(494)),d=f(n(495)),o=f(n(496)),i=f(n(497)),c=f(n(498)),l=f(n(499));function f(e){return e&&e.__esModule?e:{default:e}}(0,r.default)(u.default),(0,a.default)(u.default),(0,d.default)(u.default),(0,o.default)(u.default),(0,i.default)(u.default),(0,c.default)(u.default),(0,l.default)(u.default),t.default=u.default,e.exports=t.default},492:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u={astral:!1},r={exec:RegExp.prototype.exec,test:RegExp.prototype.test,match:String.prototype.match,replace:String.prototype.replace,split:String.prototype.split},a={},d={},o={},i=[],c={default:/\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|\(\?(?:[:=!]|<[=!])|[?*+]\?|{\d+(?:,\d*)?}\??|[\s\S]/,class:/\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|[\s\S]/},l=/\$(?:{([\w$]+)}|<([\w$]+)>|(\d\d?|[\s\S]))/g,f=void 0===r.exec.call(/()??/,"")[1],s=void 0!==/x/.flags,p={}.toString;function m(e){var t=!0;try{new RegExp("",e)}catch(n){t=!1}return t}var h=m("u"),b=m("y"),v={g:!0,i:!0,m:!0,u:h,y:b};function g(e,t,n,u,r){var a=void 0;if(e.xregexp={captureNames:t},r)return e;if(e.__proto__)e.__proto__=j.prototype;else for(a in j.prototype)e[a]=j.prototype[a];return e.xregexp.source=n,e.xregexp.flags=u?u.split("").sort().join(""):u,e}function y(e){return r.replace.call(e,/([\s\S])(?=[\s\S]*\1)/g,"")}function _(e,t){if(!j.isRegExp(e))throw new TypeError("Type RegExp expected");var n=e.xregexp||{},u=function(e){return s?e.flags:r.exec.call(/\/([a-z]*)$/i,RegExp.prototype.toString.call(e))[1]}(e),a="",d="",o=null,i=null;return(t=t||{}).removeG&&(d+="g"),t.removeY&&(d+="y"),d&&(u=r.replace.call(u,new RegExp("["+d+"]+","g"),"")),t.addG&&(a+="g"),t.addY&&(a+="y"),a&&(u=y(u+a)),t.isInternalOnly||(void 0!==n.source&&(o=n.source),null!=n.flags&&(i=a?y(n.flags+a):n.flags)),e=g(new RegExp(t.source||e.source,u),function(e){return!(!e.xregexp||!e.xregexp.captureNames)}(e)?n.captureNames.slice(0):null,o,i,t.isInternalOnly)}function E(e){return parseInt(e,16)}function w(e,t,n){return"("===e.input[e.index-1]||")"===e.input[e.index+e[0].length]||function(e,t,n){return r.test.call(-1!==n.indexOf("x")?/^(?:\s|#[^#\n]*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/:/^(?:\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/,e.slice(t))}(e.input,e.index+e[0].length,n)?"":"(?:)"}function D(e){return parseInt(e,10).toString(16)}function k(e,t){return p.call(e)==="[object "+t+"]"}function x(e){for(;e.length<4;)e="0"+e;return e}function S(e){var t={};return k(e,"String")?(j.forEach(e,/[^\s,]+/,(function(e){t[e]=!0})),t):e}function C(e){if(!/^[\w$]$/.test(e))throw new Error("Flag must be a single character A-Za-z0-9_$");v[e]=!0}function O(e,t,n,u,r){for(var a=i.length,d=e[n],o=null,c=void 0,l=void 0;a--;)if(!((l=i[a]).leadChar&&l.leadChar!==d||l.scope!==u&&"all"!==l.scope||l.flag&&-1===t.indexOf(l.flag))&&(c=j.exec(e,l.regex,n,"sticky"))){o={matchLength:c[0].length,output:l.handler.call(r,c,u,t),reparse:l.reparse};break}return o}function I(e){u.astral=e}function A(e){if(null==e)throw new TypeError("Cannot convert null or undefined to object");return e}function j(e,t){if(j.isRegExp(e)){if(void 0!==t)throw new TypeError("Cannot supply flags when copying a RegExp");return _(e)}if(e=void 0===e?"":String(e),t=void 0===t?"":String(t),j.isInstalled("astral")&&-1===t.indexOf("A")&&(t+="A"),o[e]||(o[e]={}),!o[e][t]){for(var n={hasNamedCapture:!1,captureNames:[]},u="default",a="",d=0,i=void 0,l=function(e,t){var n=void 0;if(y(t)!==t)throw new SyntaxError("Invalid duplicate regex flag "+t);for(e=r.replace.call(e,/^\(\?([\w$]+)\)/,(function(e,n){if(r.test.call(/[gy]/,n))throw new SyntaxError("Cannot use flag g or y in mode modifier "+e);return t=y(t+n),""})),n=0;n"}else if(n)return"\\"+(+n+d);return e}if(!k(e,"Array")||!e.length)throw new TypeError("Must provide a nonempty array of patterns to merge");for(var c=/(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*\]/g,l=[],f=void 0,s=0;s1&&-1!==n.indexOf("")){var u=_(this,{removeG:!0,isInternalOnly:!0});r.replace.call(String(e).slice(n.index),u,(function(){for(var e=arguments.length,t=Array(e),u=0;un.index&&(this.lastIndex=n.index)}return this.global||(this.lastIndex=t),n},a.test=function(e){return!!a.exec.call(this,e)},a.match=function(e){if(j.isRegExp(e)){if(e.global){var t=r.match.apply(this,arguments);return e.lastIndex=0,t}}else e=new RegExp(e);return a.exec.call(e,A(this))},a.replace=function(e,t){var n=j.isRegExp(e),u=void 0,a=void 0,d=void 0;return n?(e.xregexp&&(a=e.xregexp.captureNames),u=e.lastIndex):e+="",d=k(t,"Function")?r.replace.call(String(this),e,(function(){for(var u=arguments.length,r=Array(u),d=0;dn.length-3)throw new SyntaxError("Backreference to undefined group "+e);return n[r]||""}throw new SyntaxError("Invalid token "+e)}})),n&&(e.global?e.lastIndex=0:e.lastIndex=u),d},a.split=function(e,t){if(!j.isRegExp(e))return r.split.apply(this,arguments);var n=String(this),u=[],a=e.lastIndex,d=0,o=void 0;return t=(void 0===t?-1:t)>>>0,j.forEach(n,e,(function(e){e.index+e[0].length>d&&(u.push(n.slice(d,e.index)),e.length>1&&e.indext?u.slice(0,t):u},j.addToken(/\\([ABCE-RTUVXYZaeg-mopqyz]|c(?![A-Za-z])|u(?![\dA-Fa-f]{4}|{[\dA-Fa-f]+})|x(?![\dA-Fa-f]{2}))/,(function(e,t){if("B"===e[1]&&"default"===t)return e[0];throw new SyntaxError("Invalid escape "+e[0])}),{scope:"all",leadChar:"\\"}),j.addToken(/\\u{([\dA-Fa-f]+)}/,(function(e,t,n){var u=E(e[1]);if(u>1114111)throw new SyntaxError("Invalid Unicode code point "+e[0]);if(u<=65535)return"\\u"+x(D(u));if(h&&-1!==n.indexOf("u"))return e[0];throw new SyntaxError("Cannot use Unicode code point above \\u{FFFF} without flag u")}),{scope:"all",leadChar:"\\"}),j.addToken(/\[(\^?)\]/,(function(e){return e[1]?"[\\s\\S]":"\\b\\B"}),{leadChar:"["}),j.addToken(/\(\?#[^)]*\)/,w,{leadChar:"("}),j.addToken(/\s+|#[^\n]*\n?/,w,{flag:"x"}),j.addToken(/\./,(function(){return"[\\s\\S]"}),{flag:"s",leadChar:"."}),j.addToken(/\\k<([\w$]+)>/,(function(e){var t=isNaN(e[1])?this.captureNames.indexOf(e[1])+1:+e[1],n=e.index+e[0].length;if(!t||t>this.captureNames.length)throw new SyntaxError("Backreference to undefined group "+e[0]);return"\\"+t+(n===e.input.length||isNaN(e.input[n])?"":"(?:)")}),{leadChar:"\\"}),j.addToken(/\\(\d+)/,(function(e,t){if(!("default"===t&&/^[1-9]/.test(e[1])&&+e[1]<=this.captureNames.length)&&"0"!==e[1])throw new SyntaxError("Cannot use octal escape or backreference to undefined group "+e[0]);return e[0]}),{scope:"all",leadChar:"\\"}),j.addToken(/\(\?P?<([\w$]+)>/,(function(e){if(!isNaN(e[1]))throw new SyntaxError("Cannot use integer as capture name "+e[0]);if("length"===e[1]||"__proto__"===e[1])throw new SyntaxError("Cannot use reserved word as capture name "+e[0]);if(-1!==this.captureNames.indexOf(e[1]))throw new SyntaxError("Cannot use same name for multiple groups "+e[0]);return this.captureNames.push(e[1]),this.hasNamedCapture=!0,"("}),{leadChar:"("}),j.addToken(/\((?!\?)/,(function(e,t,n){return-1!==n.indexOf("n")?"(?:":(this.captureNames.push(null),"(")}),{optionalFlags:"n",leadChar:"("}),t.default=j,e.exports=t.default},493:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){var t=/(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*\]/g,n=e.union([/\({{([\w$]+)}}\)|{{([\w$]+)}}/,t],"g",{conjunction:"or"});function u(e){var t=/^(?:\(\?:\))*\^/,n=/\$(?:\(\?:\))*$/;return t.test(e)&&n.test(e)&&n.test(e.replace(/\\[\s\S]/g,""))?e.replace(t,"").replace(n,""):e}function r(t,n){var u=n?"x":"";return e.isRegExp(t)?t.xregexp&&t.xregexp.captureNames?t:e(t.source,u):e(t,u)}function a(t){return t instanceof RegExp?t:e.escape(t)}function d(e,t,n){return e["subpattern"+n]=t,e}function o(e,t,n){return e+(t1?u-1:0),i=1;i"):i="(?:",h=m,""+i+l[d].pattern.replace(t,(function(e,t,n){if(t){if(o=l[d].names[m-h],++m,o)return"(?<"+o+">"}else if(n)return c=+n-1,l[d].names[c]?"\\k<"+l[d].names[c]+">":"\\"+(+n+h);return e}))+")"}if(r){if(o=g[b],v[++b]=++m,o)return"(?<"+o+">"}else if(a)return g[c=+a-1]?"\\k<"+g[c]+">":"\\"+v[+a];return e}));return e(y,o)}},e.exports=t.default},494:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){function t(e,t,n,u){return{name:e,value:t,start:n,end:u}}e.matchRecursive=function(n,u,r,a,d){d=d||{};var o=-1!==(a=a||"").indexOf("g"),i=-1!==a.indexOf("y"),c=a.replace(/y/g,""),l=d.escapeChar,f=d.valueNames,s=[],p=0,m=0,h=0,b=0,v=void 0,g=void 0,y=void 0,_=void 0,E=void 0;if(u=e(u,c),r=e(r,c),l){if(l.length>1)throw new Error("Cannot use more than one escape character");l=e.escape(l),E=new RegExp("(?:"+l+"[\\S\\s]|(?:(?!"+e.union([u,r],"",{conjunction:"or"}).source+")[^"+l+"])+)+",a.replace(/[^imu]+/g,""))}for(;;){if(l&&(h+=(e.exec(n,E,h,"sticky")||[""])[0].length),y=e.exec(n,u,h),_=e.exec(n,r,h),y&&_&&(y.index<=_.index?_=null:y=null),y||_)h=(m=(y||_).index)+(y||_)[0].length;else if(!p)break;if(i&&!p&&m>b)break;if(y)p||(v=m,g=h),++p;else{if(!_||!p)throw new Error("Unbalanced delimiter found in string");if(!--p&&(f?(f[0]&&v>b&&s.push(t(f[0],n.slice(b,v),b,v)),f[1]&&s.push(t(f[1],n.slice(v,g),v,g)),f[2]&&s.push(t(f[2],n.slice(g,m),g,m)),f[3]&&s.push(t(f[3],n.slice(m,h),m,h))):s.push(n.slice(g,m)),b=h,!o))break}m===h&&++h}return o&&!i&&f&&f[0]&&n.length>b&&s.push(t(f[0],n.slice(b),b,n.length)),s}},e.exports=t.default},495:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){var t={},n=e._dec,u=e._hex,r=e._pad4;function a(e){return e.replace(/[- _]+/g,"").toLowerCase()}function d(e){var t=/^\\[xu](.+)/.exec(e);return t?n(t[1]):e.charCodeAt("\\"===e[0]?1:0)}function o(n){var a,o,i;return t[n]["b!"]||(t[n]["b!"]=(a=t[n].bmp,o="",i=-1,e.forEach(a,/(\\x..|\\u....|\\?[\s\S])(?:-(\\x..|\\u....|\\?[\s\S]))?/,(function(e){var t=d(e[1]);t>i+1&&(o+="\\u"+r(u(i+1)),t>i+2&&(o+="-\\u"+r(u(t-1)))),i=d(e[2]||e[1])})),i<65535&&(o+="\\u"+r(u(i+1)),i<65534&&(o+="-\\uFFFF")),o))}function i(e,n){var u=n?"a!":"a=";return t[e][u]||(t[e][u]=function(e,n){var u=t[e],r="";return u.bmp&&!u.isBmpLast&&(r="["+u.bmp+"]"+(u.astral?"|":"")),u.astral&&(r+=u.astral),u.isBmpLast&&u.bmp&&(r+=(u.astral?"|":"")+"["+u.bmp+"]"),n?"(?:(?!"+r+")(?:[\ud800-\udbff][\udc00-\udfff]|[\0-\uffff]))":"(?:"+r+")"}(e,n))}e.addToken(/\\([pP])(?:{(\^?)([^}]*)}|([A-Za-z]))/,(function(e,n,u){var r="P"===e[1]||!!e[2],d=-1!==u.indexOf("A"),c=a(e[4]||e[3]),l=t[c];if("P"===e[1]&&e[2])throw new SyntaxError("Invalid double negation "+e[0]);if(!t.hasOwnProperty(c))throw new SyntaxError("Unknown Unicode token "+e[0]);if(l.inverseOf){if(c=a(l.inverseOf),!t.hasOwnProperty(c))throw new ReferenceError("Unicode token missing data "+e[0]+" -> "+l.inverseOf);l=t[c],r=!r}if(!l.bmp&&!d)throw new SyntaxError("Astral mode required for Unicode token "+e[0]);if(d){if("class"===n)throw new SyntaxError("Astral mode does not support Unicode tokens within character classes");return i(c,r)}return"class"===n?r?o(c):l.bmp:(r?"[^":"[")+l.bmp+"]"}),{scope:"all",optionalFlags:"A",leadChar:"\\"}),e.addUnicodeData=function(n){for(var u=void 0,r=0;r\\x5E`\\x7C~\xa2-\xa6\xa8\xa9\xac\xae-\xb1\xb4\xb8\xd7\xf7\u02c2-\u02c5\u02d2-\u02df\u02e5-\u02eb\u02ed\u02ef-\u02ff\u0375\u0384\u0385\u03f6\u0482\u058d-\u058f\u0606-\u0608\u060b\u060e\u060f\u06de\u06e9\u06fd\u06fe\u07f6\u09f2\u09f3\u09fa\u09fb\u0af1\u0b70\u0bf3-\u0bfa\u0c7f\u0d4f\u0d79\u0e3f\u0f01-\u0f03\u0f13\u0f15-\u0f17\u0f1a-\u0f1f\u0f34\u0f36\u0f38\u0fbe-\u0fc5\u0fc7-\u0fcc\u0fce\u0fcf\u0fd5-\u0fd8\u109e\u109f\u1390-\u1399\u17db\u1940\u19de-\u19ff\u1b61-\u1b6a\u1b74-\u1b7c\u1fbd\u1fbf-\u1fc1\u1fcd-\u1fcf\u1fdd-\u1fdf\u1fed-\u1fef\u1ffd\u1ffe\u2044\u2052\u207a-\u207c\u208a-\u208c\u20a0-\u20be\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116-\u2118\u211e-\u2123\u2125\u2127\u2129\u212e\u213a\u213b\u2140-\u2144\u214a-\u214d\u214f\u218a\u218b\u2190-\u2307\u230c-\u2328\u232b-\u23fe\u2400-\u2426\u2440-\u244a\u249c-\u24e9\u2500-\u2767\u2794-\u27c4\u27c7-\u27e5\u27f0-\u2982\u2999-\u29d7\u29dc-\u29fb\u29fe-\u2b73\u2b76-\u2b95\u2b98-\u2bb9\u2bbd-\u2bc8\u2bca-\u2bd1\u2bec-\u2bef\u2ce5-\u2cea\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u2ff0-\u2ffb\u3004\u3012\u3013\u3020\u3036\u3037\u303e\u303f\u309b\u309c\u3190\u3191\u3196-\u319f\u31c0-\u31e3\u3200-\u321e\u322a-\u3247\u3250\u3260-\u327f\u328a-\u32b0\u32c0-\u32fe\u3300-\u33ff\u4dc0-\u4dff\ua490-\ua4c6\ua700-\ua716\ua720\ua721\ua789\ua78a\ua828-\ua82b\ua836-\ua839\uaa77-\uaa79\uab5b\ufb29\ufbb2-\ufbc1\ufdfc\ufdfd\ufe62\ufe64-\ufe66\ufe69\uff04\uff0b\uff1c-\uff1e\uff3e\uff40\uff5c\uff5e\uffe0-\uffe6\uffe8-\uffee\ufffc\ufffd",astral:"\ud800[\udd37-\udd3f\udd79-\udd89\udd8c-\udd8e\udd90-\udd9b\udda0\uddd0-\uddfc]|\ud802[\udc77\udc78\udec8]|\ud805\udf3f|\ud81a[\udf3c-\udf3f\udf45]|\ud82f\udc9c|\ud834[\udc00-\udcf5\udd00-\udd26\udd29-\udd64\udd6a-\udd6c\udd83\udd84\udd8c-\udda9\uddae-\udde8\ude00-\ude41\ude45\udf00-\udf56]|\ud835[\udec1\udedb\udefb\udf15\udf35\udf4f\udf6f\udf89\udfa9\udfc3]|\ud836[\udc00-\uddff\ude37-\ude3a\ude6d-\ude74\ude76-\ude83\ude85\ude86]|\ud83b[\udef0\udef1]|\ud83c[\udc00-\udc2b\udc30-\udc93\udca0-\udcae\udcb1-\udcbf\udcc1-\udccf\udcd1-\udcf5\udd10-\udd2e\udd30-\udd6b\udd70-\uddac\udde6-\ude02\ude10-\ude3b\ude40-\ude48\ude50\ude51\udf00-\udfff]|\ud83d[\udc00-\uded2\udee0-\udeec\udef0-\udef6\udf00-\udf73\udf80-\udfd4]|\ud83e[\udc00-\udc0b\udc10-\udc47\udc50-\udc59\udc60-\udc87\udc90-\udcad\udd10-\udd1e\udd20-\udd27\udd30\udd33-\udd3e\udd40-\udd4b\udd50-\udd5e\udd80-\udd91\uddc0]"},{name:"Sc",alias:"Currency_Symbol",bmp:"\\x24\xa2-\xa5\u058f\u060b\u09f2\u09f3\u09fb\u0af1\u0bf9\u0e3f\u17db\u20a0-\u20be\ua838\ufdfc\ufe69\uff04\uffe0\uffe1\uffe5\uffe6"},{name:"Sk",alias:"Modifier_Symbol",bmp:"\\x5E`\xa8\xaf\xb4\xb8\u02c2-\u02c5\u02d2-\u02df\u02e5-\u02eb\u02ed\u02ef-\u02ff\u0375\u0384\u0385\u1fbd\u1fbf-\u1fc1\u1fcd-\u1fcf\u1fdd-\u1fdf\u1fed-\u1fef\u1ffd\u1ffe\u309b\u309c\ua700-\ua716\ua720\ua721\ua789\ua78a\uab5b\ufbb2-\ufbc1\uff3e\uff40\uffe3",astral:"\ud83c[\udffb-\udfff]"},{name:"Sm",alias:"Math_Symbol",bmp:"\\x2B<->\\x7C~\xac\xb1\xd7\xf7\u03f6\u0606-\u0608\u2044\u2052\u207a-\u207c\u208a-\u208c\u2118\u2140-\u2144\u214b\u2190-\u2194\u219a\u219b\u21a0\u21a3\u21a6\u21ae\u21ce\u21cf\u21d2\u21d4\u21f4-\u22ff\u2320\u2321\u237c\u239b-\u23b3\u23dc-\u23e1\u25b7\u25c1\u25f8-\u25ff\u266f\u27c0-\u27c4\u27c7-\u27e5\u27f0-\u27ff\u2900-\u2982\u2999-\u29d7\u29dc-\u29fb\u29fe-\u2aff\u2b30-\u2b44\u2b47-\u2b4c\ufb29\ufe62\ufe64-\ufe66\uff0b\uff1c-\uff1e\uff5c\uff5e\uffe2\uffe9-\uffec",astral:"\ud835[\udec1\udedb\udefb\udf15\udf35\udf4f\udf6f\udf89\udfa9\udfc3]|\ud83b[\udef0\udef1]"},{name:"So",alias:"Other_Symbol",bmp:"\xa6\xa9\xae\xb0\u0482\u058d\u058e\u060e\u060f\u06de\u06e9\u06fd\u06fe\u07f6\u09fa\u0b70\u0bf3-\u0bf8\u0bfa\u0c7f\u0d4f\u0d79\u0f01-\u0f03\u0f13\u0f15-\u0f17\u0f1a-\u0f1f\u0f34\u0f36\u0f38\u0fbe-\u0fc5\u0fc7-\u0fcc\u0fce\u0fcf\u0fd5-\u0fd8\u109e\u109f\u1390-\u1399\u1940\u19de-\u19ff\u1b61-\u1b6a\u1b74-\u1b7c\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116\u2117\u211e-\u2123\u2125\u2127\u2129\u212e\u213a\u213b\u214a\u214c\u214d\u214f\u218a\u218b\u2195-\u2199\u219c-\u219f\u21a1\u21a2\u21a4\u21a5\u21a7-\u21ad\u21af-\u21cd\u21d0\u21d1\u21d3\u21d5-\u21f3\u2300-\u2307\u230c-\u231f\u2322-\u2328\u232b-\u237b\u237d-\u239a\u23b4-\u23db\u23e2-\u23fe\u2400-\u2426\u2440-\u244a\u249c-\u24e9\u2500-\u25b6\u25b8-\u25c0\u25c2-\u25f7\u2600-\u266e\u2670-\u2767\u2794-\u27bf\u2800-\u28ff\u2b00-\u2b2f\u2b45\u2b46\u2b4d-\u2b73\u2b76-\u2b95\u2b98-\u2bb9\u2bbd-\u2bc8\u2bca-\u2bd1\u2bec-\u2bef\u2ce5-\u2cea\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u2ff0-\u2ffb\u3004\u3012\u3013\u3020\u3036\u3037\u303e\u303f\u3190\u3191\u3196-\u319f\u31c0-\u31e3\u3200-\u321e\u322a-\u3247\u3250\u3260-\u327f\u328a-\u32b0\u32c0-\u32fe\u3300-\u33ff\u4dc0-\u4dff\ua490-\ua4c6\ua828-\ua82b\ua836\ua837\ua839\uaa77-\uaa79\ufdfd\uffe4\uffe8\uffed\uffee\ufffc\ufffd",astral:"\ud800[\udd37-\udd3f\udd79-\udd89\udd8c-\udd8e\udd90-\udd9b\udda0\uddd0-\uddfc]|\ud802[\udc77\udc78\udec8]|\ud805\udf3f|\ud81a[\udf3c-\udf3f\udf45]|\ud82f\udc9c|\ud834[\udc00-\udcf5\udd00-\udd26\udd29-\udd64\udd6a-\udd6c\udd83\udd84\udd8c-\udda9\uddae-\udde8\ude00-\ude41\ude45\udf00-\udf56]|\ud836[\udc00-\uddff\ude37-\ude3a\ude6d-\ude74\ude76-\ude83\ude85\ude86]|\ud83c[\udc00-\udc2b\udc30-\udc93\udca0-\udcae\udcb1-\udcbf\udcc1-\udccf\udcd1-\udcf5\udd10-\udd2e\udd30-\udd6b\udd70-\uddac\udde6-\ude02\ude10-\ude3b\ude40-\ude48\ude50\ude51\udf00-\udffa]|\ud83d[\udc00-\uded2\udee0-\udeec\udef0-\udef6\udf00-\udf73\udf80-\udfd4]|\ud83e[\udc00-\udc0b\udc10-\udc47\udc50-\udc59\udc60-\udc87\udc90-\udcad\udd10-\udd1e\udd20-\udd27\udd30\udd33-\udd3e\udd40-\udd4b\udd50-\udd5e\udd80-\udd91\uddc0]"},{name:"Z",alias:"Separator",bmp:" \xa0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000"},{name:"Zl",alias:"Line_Separator",bmp:"\u2028"},{name:"Zp",alias:"Paragraph_Separator",bmp:"\u2029"},{name:"Zs",alias:"Space_Separator",bmp:" \xa0\u1680\u2000-\u200a\u202f\u205f\u3000"}])},e.exports=t.default},498:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){if(!e.addUnicodeData)throw new ReferenceError("Unicode Base must be loaded before Unicode Properties");var t=[{name:"ASCII",bmp:"\0-\x7f"},{name:"Alphabetic",bmp:"A-Za-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0345\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0561-\u0587\u05b0-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0657\u0659-\u065f\u066e-\u06d3\u06d5-\u06dc\u06e1-\u06e8\u06ed-\u06ef\u06fa-\u06fc\u06ff\u0710-\u073f\u074d-\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0817\u081a-\u082c\u0840-\u0858\u08a0-\u08b4\u08b6-\u08bd\u08d4-\u08df\u08e3-\u08e9\u08f0-\u093b\u093d-\u094c\u094e-\u0950\u0955-\u0963\u0971-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd-\u09c4\u09c7\u09c8\u09cb\u09cc\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09f0\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3e-\u0a42\u0a47\u0a48\u0a4b\u0a4c\u0a51\u0a59-\u0a5c\u0a5e\u0a70-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd-\u0ac5\u0ac7-\u0ac9\u0acb\u0acc\u0ad0\u0ae0-\u0ae3\u0af9\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d-\u0b44\u0b47\u0b48\u0b4b\u0b4c\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcc\u0bd0\u0bd7\u0c00-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4c\u0c55\u0c56\u0c58-\u0c5a\u0c60-\u0c63\u0c80-\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccc\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0cf1\u0cf2\u0d01-\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4c\u0d4e\u0d54-\u0d57\u0d5f-\u0d63\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e46\u0e4d\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ecd\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f71-\u0f81\u0f88-\u0f97\u0f99-\u0fbc\u1000-\u1036\u1038\u103b-\u103f\u1050-\u1062\u1065-\u1068\u106e-\u1086\u108e\u109c\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135f\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1713\u1720-\u1733\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17b3\u17b6-\u17c8\u17d7\u17dc\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191e\u1920-\u192b\u1930-\u1938\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a1b\u1a20-\u1a5e\u1a61-\u1a74\u1aa7\u1b00-\u1b33\u1b35-\u1b43\u1b45-\u1b4b\u1b80-\u1ba9\u1bac-\u1baf\u1bba-\u1be5\u1be7-\u1bf1\u1c00-\u1c35\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1d00-\u1dbf\u1de7-\u1df4\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u24b6-\u24e9\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fd5\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua674-\ua67b\ua67f-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7ae\ua7b0-\ua7b7\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua827\ua840-\ua873\ua880-\ua8c3\ua8c5\ua8f2-\ua8f7\ua8fb\ua8fd\ua90a-\ua92a\ua930-\ua952\ua960-\ua97c\ua980-\ua9b2\ua9b4-\ua9bf\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa36\uaa40-\uaa4d\uaa60-\uaa76\uaa7a\uaa7e-\uaabe\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf5\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab65\uab70-\uabea\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc",astral:"\ud800[\udc00-\udc0b\udc0d-\udc26\udc28-\udc3a\udc3c\udc3d\udc3f-\udc4d\udc50-\udc5d\udc80-\udcfa\udd40-\udd74\ude80-\ude9c\udea0-\uded0\udf00-\udf1f\udf30-\udf4a\udf50-\udf7a\udf80-\udf9d\udfa0-\udfc3\udfc8-\udfcf\udfd1-\udfd5]|\ud801[\udc00-\udc9d\udcb0-\udcd3\udcd8-\udcfb\udd00-\udd27\udd30-\udd63\ude00-\udf36\udf40-\udf55\udf60-\udf67]|\ud802[\udc00-\udc05\udc08\udc0a-\udc35\udc37\udc38\udc3c\udc3f-\udc55\udc60-\udc76\udc80-\udc9e\udce0-\udcf2\udcf4\udcf5\udd00-\udd15\udd20-\udd39\udd80-\uddb7\uddbe\uddbf\ude00-\ude03\ude05\ude06\ude0c-\ude13\ude15-\ude17\ude19-\ude33\ude60-\ude7c\ude80-\ude9c\udec0-\udec7\udec9-\udee4\udf00-\udf35\udf40-\udf55\udf60-\udf72\udf80-\udf91]|\ud803[\udc00-\udc48\udc80-\udcb2\udcc0-\udcf2]|\ud804[\udc00-\udc45\udc82-\udcb8\udcd0-\udce8\udd00-\udd32\udd50-\udd72\udd76\udd80-\uddbf\uddc1-\uddc4\uddda\udddc\ude00-\ude11\ude13-\ude34\ude37\ude3e\ude80-\ude86\ude88\ude8a-\ude8d\ude8f-\ude9d\ude9f-\udea8\udeb0-\udee8\udf00-\udf03\udf05-\udf0c\udf0f\udf10\udf13-\udf28\udf2a-\udf30\udf32\udf33\udf35-\udf39\udf3d-\udf44\udf47\udf48\udf4b\udf4c\udf50\udf57\udf5d-\udf63]|\ud805[\udc00-\udc41\udc43-\udc45\udc47-\udc4a\udc80-\udcc1\udcc4\udcc5\udcc7\udd80-\uddb5\uddb8-\uddbe\uddd8-\udddd\ude00-\ude3e\ude40\ude44\ude80-\udeb5\udf00-\udf19\udf1d-\udf2a]|\ud806[\udca0-\udcdf\udcff\udec0-\udef8]|\ud807[\udc00-\udc08\udc0a-\udc36\udc38-\udc3e\udc40\udc72-\udc8f\udc92-\udca7\udca9-\udcb6]|\ud808[\udc00-\udf99]|\ud809[\udc00-\udc6e\udc80-\udd43]|[\ud80c\ud81c-\ud820\ud840-\ud868\ud86a-\ud86c\ud86f-\ud872][\udc00-\udfff]|\ud80d[\udc00-\udc2e]|\ud811[\udc00-\ude46]|\ud81a[\udc00-\ude38\ude40-\ude5e\uded0-\udeed\udf00-\udf36\udf40-\udf43\udf63-\udf77\udf7d-\udf8f]|\ud81b[\udf00-\udf44\udf50-\udf7e\udf93-\udf9f\udfe0]|\ud821[\udc00-\udfec]|\ud822[\udc00-\udef2]|\ud82c[\udc00\udc01]|\ud82f[\udc00-\udc6a\udc70-\udc7c\udc80-\udc88\udc90-\udc99\udc9e]|\ud835[\udc00-\udc54\udc56-\udc9c\udc9e\udc9f\udca2\udca5\udca6\udca9-\udcac\udcae-\udcb9\udcbb\udcbd-\udcc3\udcc5-\udd05\udd07-\udd0a\udd0d-\udd14\udd16-\udd1c\udd1e-\udd39\udd3b-\udd3e\udd40-\udd44\udd46\udd4a-\udd50\udd52-\udea5\udea8-\udec0\udec2-\udeda\udedc-\udefa\udefc-\udf14\udf16-\udf34\udf36-\udf4e\udf50-\udf6e\udf70-\udf88\udf8a-\udfa8\udfaa-\udfc2\udfc4-\udfcb]|\ud838[\udc00-\udc06\udc08-\udc18\udc1b-\udc21\udc23\udc24\udc26-\udc2a]|\ud83a[\udc00-\udcc4\udd00-\udd43\udd47]|\ud83b[\ude00-\ude03\ude05-\ude1f\ude21\ude22\ude24\ude27\ude29-\ude32\ude34-\ude37\ude39\ude3b\ude42\ude47\ude49\ude4b\ude4d-\ude4f\ude51\ude52\ude54\ude57\ude59\ude5b\ude5d\ude5f\ude61\ude62\ude64\ude67-\ude6a\ude6c-\ude72\ude74-\ude77\ude79-\ude7c\ude7e\ude80-\ude89\ude8b-\ude9b\udea1-\udea3\udea5-\udea9\udeab-\udebb]|\ud83c[\udd30-\udd49\udd50-\udd69\udd70-\udd89]|\ud869[\udc00-\uded6\udf00-\udfff]|\ud86d[\udc00-\udf34\udf40-\udfff]|\ud86e[\udc00-\udc1d\udc20-\udfff]|\ud873[\udc00-\udea1]|\ud87e[\udc00-\ude1d]"},{name:"Any",isBmpLast:!0,bmp:"\0-\uffff",astral:"[\ud800-\udbff][\udc00-\udfff]"},{name:"Default_Ignorable_Code_Point",bmp:"\xad\u034f\u061c\u115f\u1160\u17b4\u17b5\u180b-\u180e\u200b-\u200f\u202a-\u202e\u2060-\u206f\u3164\ufe00-\ufe0f\ufeff\uffa0\ufff0-\ufff8",astral:"\ud82f[\udca0-\udca3]|\ud834[\udd73-\udd7a]|[\udb40-\udb43][\udc00-\udfff]"},{name:"Lowercase",bmp:"a-z\xaa\xb5\xba\xdf-\xf6\xf8-\xff\u0101\u0103\u0105\u0107\u0109\u010b\u010d\u010f\u0111\u0113\u0115\u0117\u0119\u011b\u011d\u011f\u0121\u0123\u0125\u0127\u0129\u012b\u012d\u012f\u0131\u0133\u0135\u0137\u0138\u013a\u013c\u013e\u0140\u0142\u0144\u0146\u0148\u0149\u014b\u014d\u014f\u0151\u0153\u0155\u0157\u0159\u015b\u015d\u015f\u0161\u0163\u0165\u0167\u0169\u016b\u016d\u016f\u0171\u0173\u0175\u0177\u017a\u017c\u017e-\u0180\u0183\u0185\u0188\u018c\u018d\u0192\u0195\u0199-\u019b\u019e\u01a1\u01a3\u01a5\u01a8\u01aa\u01ab\u01ad\u01b0\u01b4\u01b6\u01b9\u01ba\u01bd-\u01bf\u01c6\u01c9\u01cc\u01ce\u01d0\u01d2\u01d4\u01d6\u01d8\u01da\u01dc\u01dd\u01df\u01e1\u01e3\u01e5\u01e7\u01e9\u01eb\u01ed\u01ef\u01f0\u01f3\u01f5\u01f9\u01fb\u01fd\u01ff\u0201\u0203\u0205\u0207\u0209\u020b\u020d\u020f\u0211\u0213\u0215\u0217\u0219\u021b\u021d\u021f\u0221\u0223\u0225\u0227\u0229\u022b\u022d\u022f\u0231\u0233-\u0239\u023c\u023f\u0240\u0242\u0247\u0249\u024b\u024d\u024f-\u0293\u0295-\u02b8\u02c0\u02c1\u02e0-\u02e4\u0345\u0371\u0373\u0377\u037a-\u037d\u0390\u03ac-\u03ce\u03d0\u03d1\u03d5-\u03d7\u03d9\u03db\u03dd\u03df\u03e1\u03e3\u03e5\u03e7\u03e9\u03eb\u03ed\u03ef-\u03f3\u03f5\u03f8\u03fb\u03fc\u0430-\u045f\u0461\u0463\u0465\u0467\u0469\u046b\u046d\u046f\u0471\u0473\u0475\u0477\u0479\u047b\u047d\u047f\u0481\u048b\u048d\u048f\u0491\u0493\u0495\u0497\u0499\u049b\u049d\u049f\u04a1\u04a3\u04a5\u04a7\u04a9\u04ab\u04ad\u04af\u04b1\u04b3\u04b5\u04b7\u04b9\u04bb\u04bd\u04bf\u04c2\u04c4\u04c6\u04c8\u04ca\u04cc\u04ce\u04cf\u04d1\u04d3\u04d5\u04d7\u04d9\u04db\u04dd\u04df\u04e1\u04e3\u04e5\u04e7\u04e9\u04eb\u04ed\u04ef\u04f1\u04f3\u04f5\u04f7\u04f9\u04fb\u04fd\u04ff\u0501\u0503\u0505\u0507\u0509\u050b\u050d\u050f\u0511\u0513\u0515\u0517\u0519\u051b\u051d\u051f\u0521\u0523\u0525\u0527\u0529\u052b\u052d\u052f\u0561-\u0587\u13f8-\u13fd\u1c80-\u1c88\u1d00-\u1dbf\u1e01\u1e03\u1e05\u1e07\u1e09\u1e0b\u1e0d\u1e0f\u1e11\u1e13\u1e15\u1e17\u1e19\u1e1b\u1e1d\u1e1f\u1e21\u1e23\u1e25\u1e27\u1e29\u1e2b\u1e2d\u1e2f\u1e31\u1e33\u1e35\u1e37\u1e39\u1e3b\u1e3d\u1e3f\u1e41\u1e43\u1e45\u1e47\u1e49\u1e4b\u1e4d\u1e4f\u1e51\u1e53\u1e55\u1e57\u1e59\u1e5b\u1e5d\u1e5f\u1e61\u1e63\u1e65\u1e67\u1e69\u1e6b\u1e6d\u1e6f\u1e71\u1e73\u1e75\u1e77\u1e79\u1e7b\u1e7d\u1e7f\u1e81\u1e83\u1e85\u1e87\u1e89\u1e8b\u1e8d\u1e8f\u1e91\u1e93\u1e95-\u1e9d\u1e9f\u1ea1\u1ea3\u1ea5\u1ea7\u1ea9\u1eab\u1ead\u1eaf\u1eb1\u1eb3\u1eb5\u1eb7\u1eb9\u1ebb\u1ebd\u1ebf\u1ec1\u1ec3\u1ec5\u1ec7\u1ec9\u1ecb\u1ecd\u1ecf\u1ed1\u1ed3\u1ed5\u1ed7\u1ed9\u1edb\u1edd\u1edf\u1ee1\u1ee3\u1ee5\u1ee7\u1ee9\u1eeb\u1eed\u1eef\u1ef1\u1ef3\u1ef5\u1ef7\u1ef9\u1efb\u1efd\u1eff-\u1f07\u1f10-\u1f15\u1f20-\u1f27\u1f30-\u1f37\u1f40-\u1f45\u1f50-\u1f57\u1f60-\u1f67\u1f70-\u1f7d\u1f80-\u1f87\u1f90-\u1f97\u1fa0-\u1fa7\u1fb0-\u1fb4\u1fb6\u1fb7\u1fbe\u1fc2-\u1fc4\u1fc6\u1fc7\u1fd0-\u1fd3\u1fd6\u1fd7\u1fe0-\u1fe7\u1ff2-\u1ff4\u1ff6\u1ff7\u2071\u207f\u2090-\u209c\u210a\u210e\u210f\u2113\u212f\u2134\u2139\u213c\u213d\u2146-\u2149\u214e\u2170-\u217f\u2184\u24d0-\u24e9\u2c30-\u2c5e\u2c61\u2c65\u2c66\u2c68\u2c6a\u2c6c\u2c71\u2c73\u2c74\u2c76-\u2c7d\u2c81\u2c83\u2c85\u2c87\u2c89\u2c8b\u2c8d\u2c8f\u2c91\u2c93\u2c95\u2c97\u2c99\u2c9b\u2c9d\u2c9f\u2ca1\u2ca3\u2ca5\u2ca7\u2ca9\u2cab\u2cad\u2caf\u2cb1\u2cb3\u2cb5\u2cb7\u2cb9\u2cbb\u2cbd\u2cbf\u2cc1\u2cc3\u2cc5\u2cc7\u2cc9\u2ccb\u2ccd\u2ccf\u2cd1\u2cd3\u2cd5\u2cd7\u2cd9\u2cdb\u2cdd\u2cdf\u2ce1\u2ce3\u2ce4\u2cec\u2cee\u2cf3\u2d00-\u2d25\u2d27\u2d2d\ua641\ua643\ua645\ua647\ua649\ua64b\ua64d\ua64f\ua651\ua653\ua655\ua657\ua659\ua65b\ua65d\ua65f\ua661\ua663\ua665\ua667\ua669\ua66b\ua66d\ua681\ua683\ua685\ua687\ua689\ua68b\ua68d\ua68f\ua691\ua693\ua695\ua697\ua699\ua69b-\ua69d\ua723\ua725\ua727\ua729\ua72b\ua72d\ua72f-\ua731\ua733\ua735\ua737\ua739\ua73b\ua73d\ua73f\ua741\ua743\ua745\ua747\ua749\ua74b\ua74d\ua74f\ua751\ua753\ua755\ua757\ua759\ua75b\ua75d\ua75f\ua761\ua763\ua765\ua767\ua769\ua76b\ua76d\ua76f-\ua778\ua77a\ua77c\ua77f\ua781\ua783\ua785\ua787\ua78c\ua78e\ua791\ua793-\ua795\ua797\ua799\ua79b\ua79d\ua79f\ua7a1\ua7a3\ua7a5\ua7a7\ua7a9\ua7b5\ua7b7\ua7f8-\ua7fa\uab30-\uab5a\uab5c-\uab65\uab70-\uabbf\ufb00-\ufb06\ufb13-\ufb17\uff41-\uff5a",astral:"\ud801[\udc28-\udc4f\udcd8-\udcfb]|\ud803[\udcc0-\udcf2]|\ud806[\udcc0-\udcdf]|\ud835[\udc1a-\udc33\udc4e-\udc54\udc56-\udc67\udc82-\udc9b\udcb6-\udcb9\udcbb\udcbd-\udcc3\udcc5-\udccf\udcea-\udd03\udd1e-\udd37\udd52-\udd6b\udd86-\udd9f\uddba-\uddd3\uddee-\ude07\ude22-\ude3b\ude56-\ude6f\ude8a-\udea5\udec2-\udeda\udedc-\udee1\udefc-\udf14\udf16-\udf1b\udf36-\udf4e\udf50-\udf55\udf70-\udf88\udf8a-\udf8f\udfaa-\udfc2\udfc4-\udfc9\udfcb]|\ud83a[\udd22-\udd43]"},{name:"Noncharacter_Code_Point",bmp:"\ufdd0-\ufdef\ufffe\uffff",astral:"[\ud83f\ud87f\ud8bf\ud8ff\ud93f\ud97f\ud9bf\ud9ff\uda3f\uda7f\udabf\udaff\udb3f\udb7f\udbbf\udbff][\udffe\udfff]"},{name:"Uppercase",bmp:"A-Z\xc0-\xd6\xd8-\xde\u0100\u0102\u0104\u0106\u0108\u010a\u010c\u010e\u0110\u0112\u0114\u0116\u0118\u011a\u011c\u011e\u0120\u0122\u0124\u0126\u0128\u012a\u012c\u012e\u0130\u0132\u0134\u0136\u0139\u013b\u013d\u013f\u0141\u0143\u0145\u0147\u014a\u014c\u014e\u0150\u0152\u0154\u0156\u0158\u015a\u015c\u015e\u0160\u0162\u0164\u0166\u0168\u016a\u016c\u016e\u0170\u0172\u0174\u0176\u0178\u0179\u017b\u017d\u0181\u0182\u0184\u0186\u0187\u0189-\u018b\u018e-\u0191\u0193\u0194\u0196-\u0198\u019c\u019d\u019f\u01a0\u01a2\u01a4\u01a6\u01a7\u01a9\u01ac\u01ae\u01af\u01b1-\u01b3\u01b5\u01b7\u01b8\u01bc\u01c4\u01c7\u01ca\u01cd\u01cf\u01d1\u01d3\u01d5\u01d7\u01d9\u01db\u01de\u01e0\u01e2\u01e4\u01e6\u01e8\u01ea\u01ec\u01ee\u01f1\u01f4\u01f6-\u01f8\u01fa\u01fc\u01fe\u0200\u0202\u0204\u0206\u0208\u020a\u020c\u020e\u0210\u0212\u0214\u0216\u0218\u021a\u021c\u021e\u0220\u0222\u0224\u0226\u0228\u022a\u022c\u022e\u0230\u0232\u023a\u023b\u023d\u023e\u0241\u0243-\u0246\u0248\u024a\u024c\u024e\u0370\u0372\u0376\u037f\u0386\u0388-\u038a\u038c\u038e\u038f\u0391-\u03a1\u03a3-\u03ab\u03cf\u03d2-\u03d4\u03d8\u03da\u03dc\u03de\u03e0\u03e2\u03e4\u03e6\u03e8\u03ea\u03ec\u03ee\u03f4\u03f7\u03f9\u03fa\u03fd-\u042f\u0460\u0462\u0464\u0466\u0468\u046a\u046c\u046e\u0470\u0472\u0474\u0476\u0478\u047a\u047c\u047e\u0480\u048a\u048c\u048e\u0490\u0492\u0494\u0496\u0498\u049a\u049c\u049e\u04a0\u04a2\u04a4\u04a6\u04a8\u04aa\u04ac\u04ae\u04b0\u04b2\u04b4\u04b6\u04b8\u04ba\u04bc\u04be\u04c0\u04c1\u04c3\u04c5\u04c7\u04c9\u04cb\u04cd\u04d0\u04d2\u04d4\u04d6\u04d8\u04da\u04dc\u04de\u04e0\u04e2\u04e4\u04e6\u04e8\u04ea\u04ec\u04ee\u04f0\u04f2\u04f4\u04f6\u04f8\u04fa\u04fc\u04fe\u0500\u0502\u0504\u0506\u0508\u050a\u050c\u050e\u0510\u0512\u0514\u0516\u0518\u051a\u051c\u051e\u0520\u0522\u0524\u0526\u0528\u052a\u052c\u052e\u0531-\u0556\u10a0-\u10c5\u10c7\u10cd\u13a0-\u13f5\u1e00\u1e02\u1e04\u1e06\u1e08\u1e0a\u1e0c\u1e0e\u1e10\u1e12\u1e14\u1e16\u1e18\u1e1a\u1e1c\u1e1e\u1e20\u1e22\u1e24\u1e26\u1e28\u1e2a\u1e2c\u1e2e\u1e30\u1e32\u1e34\u1e36\u1e38\u1e3a\u1e3c\u1e3e\u1e40\u1e42\u1e44\u1e46\u1e48\u1e4a\u1e4c\u1e4e\u1e50\u1e52\u1e54\u1e56\u1e58\u1e5a\u1e5c\u1e5e\u1e60\u1e62\u1e64\u1e66\u1e68\u1e6a\u1e6c\u1e6e\u1e70\u1e72\u1e74\u1e76\u1e78\u1e7a\u1e7c\u1e7e\u1e80\u1e82\u1e84\u1e86\u1e88\u1e8a\u1e8c\u1e8e\u1e90\u1e92\u1e94\u1e9e\u1ea0\u1ea2\u1ea4\u1ea6\u1ea8\u1eaa\u1eac\u1eae\u1eb0\u1eb2\u1eb4\u1eb6\u1eb8\u1eba\u1ebc\u1ebe\u1ec0\u1ec2\u1ec4\u1ec6\u1ec8\u1eca\u1ecc\u1ece\u1ed0\u1ed2\u1ed4\u1ed6\u1ed8\u1eda\u1edc\u1ede\u1ee0\u1ee2\u1ee4\u1ee6\u1ee8\u1eea\u1eec\u1eee\u1ef0\u1ef2\u1ef4\u1ef6\u1ef8\u1efa\u1efc\u1efe\u1f08-\u1f0f\u1f18-\u1f1d\u1f28-\u1f2f\u1f38-\u1f3f\u1f48-\u1f4d\u1f59\u1f5b\u1f5d\u1f5f\u1f68-\u1f6f\u1fb8-\u1fbb\u1fc8-\u1fcb\u1fd8-\u1fdb\u1fe8-\u1fec\u1ff8-\u1ffb\u2102\u2107\u210b-\u210d\u2110-\u2112\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u2130-\u2133\u213e\u213f\u2145\u2160-\u216f\u2183\u24b6-\u24cf\u2c00-\u2c2e\u2c60\u2c62-\u2c64\u2c67\u2c69\u2c6b\u2c6d-\u2c70\u2c72\u2c75\u2c7e-\u2c80\u2c82\u2c84\u2c86\u2c88\u2c8a\u2c8c\u2c8e\u2c90\u2c92\u2c94\u2c96\u2c98\u2c9a\u2c9c\u2c9e\u2ca0\u2ca2\u2ca4\u2ca6\u2ca8\u2caa\u2cac\u2cae\u2cb0\u2cb2\u2cb4\u2cb6\u2cb8\u2cba\u2cbc\u2cbe\u2cc0\u2cc2\u2cc4\u2cc6\u2cc8\u2cca\u2ccc\u2cce\u2cd0\u2cd2\u2cd4\u2cd6\u2cd8\u2cda\u2cdc\u2cde\u2ce0\u2ce2\u2ceb\u2ced\u2cf2\ua640\ua642\ua644\ua646\ua648\ua64a\ua64c\ua64e\ua650\ua652\ua654\ua656\ua658\ua65a\ua65c\ua65e\ua660\ua662\ua664\ua666\ua668\ua66a\ua66c\ua680\ua682\ua684\ua686\ua688\ua68a\ua68c\ua68e\ua690\ua692\ua694\ua696\ua698\ua69a\ua722\ua724\ua726\ua728\ua72a\ua72c\ua72e\ua732\ua734\ua736\ua738\ua73a\ua73c\ua73e\ua740\ua742\ua744\ua746\ua748\ua74a\ua74c\ua74e\ua750\ua752\ua754\ua756\ua758\ua75a\ua75c\ua75e\ua760\ua762\ua764\ua766\ua768\ua76a\ua76c\ua76e\ua779\ua77b\ua77d\ua77e\ua780\ua782\ua784\ua786\ua78b\ua78d\ua790\ua792\ua796\ua798\ua79a\ua79c\ua79e\ua7a0\ua7a2\ua7a4\ua7a6\ua7a8\ua7aa-\ua7ae\ua7b0-\ua7b4\ua7b6\uff21-\uff3a",astral:"\ud801[\udc00-\udc27\udcb0-\udcd3]|\ud803[\udc80-\udcb2]|\ud806[\udca0-\udcbf]|\ud835[\udc00-\udc19\udc34-\udc4d\udc68-\udc81\udc9c\udc9e\udc9f\udca2\udca5\udca6\udca9-\udcac\udcae-\udcb5\udcd0-\udce9\udd04\udd05\udd07-\udd0a\udd0d-\udd14\udd16-\udd1c\udd38\udd39\udd3b-\udd3e\udd40-\udd44\udd46\udd4a-\udd50\udd6c-\udd85\udda0-\uddb9\uddd4-\udded\ude08-\ude21\ude3c-\ude55\ude70-\ude89\udea8-\udec0\udee2-\udefa\udf1c-\udf34\udf56-\udf6e\udf90-\udfa8\udfca]|\ud83a[\udd00-\udd21]|\ud83c[\udd30-\udd49\udd50-\udd69\udd70-\udd89]"},{name:"White_Space",bmp:"\t-\r \x85\xa0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000"}];t.push({name:"Assigned",inverseOf:"Cn"}),e.addUnicodeData(t)},e.exports=t.default},499:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){if(!e.addUnicodeData)throw new ReferenceError("Unicode Base must be loaded before Unicode Scripts");e.addUnicodeData([{name:"Adlam",astral:"\ud83a[\udd00-\udd4a\udd50-\udd59\udd5e\udd5f]"},{name:"Ahom",astral:"\ud805[\udf00-\udf19\udf1d-\udf2b\udf30-\udf3f]"},{name:"Anatolian_Hieroglyphs",astral:"\ud811[\udc00-\ude46]"},{name:"Arabic",bmp:"\u0600-\u0604\u0606-\u060b\u060d-\u061a\u061e\u0620-\u063f\u0641-\u064a\u0656-\u066f\u0671-\u06dc\u06de-\u06ff\u0750-\u077f\u08a0-\u08b4\u08b6-\u08bd\u08d4-\u08e1\u08e3-\u08ff\ufb50-\ufbc1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfd\ufe70-\ufe74\ufe76-\ufefc",astral:"\ud803[\ude60-\ude7e]|\ud83b[\ude00-\ude03\ude05-\ude1f\ude21\ude22\ude24\ude27\ude29-\ude32\ude34-\ude37\ude39\ude3b\ude42\ude47\ude49\ude4b\ude4d-\ude4f\ude51\ude52\ude54\ude57\ude59\ude5b\ude5d\ude5f\ude61\ude62\ude64\ude67-\ude6a\ude6c-\ude72\ude74-\ude77\ude79-\ude7c\ude7e\ude80-\ude89\ude8b-\ude9b\udea1-\udea3\udea5-\udea9\udeab-\udebb\udef0\udef1]"},{name:"Armenian",bmp:"\u0531-\u0556\u0559-\u055f\u0561-\u0587\u058a\u058d-\u058f\ufb13-\ufb17"},{name:"Avestan",astral:"\ud802[\udf00-\udf35\udf39-\udf3f]"},{name:"Balinese",bmp:"\u1b00-\u1b4b\u1b50-\u1b7c"},{name:"Bamum",bmp:"\ua6a0-\ua6f7",astral:"\ud81a[\udc00-\ude38]"},{name:"Bassa_Vah",astral:"\ud81a[\uded0-\udeed\udef0-\udef5]"},{name:"Batak",bmp:"\u1bc0-\u1bf3\u1bfc-\u1bff"},{name:"Bengali",bmp:"\u0980-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09fb"},{name:"Bhaiksuki",astral:"\ud807[\udc00-\udc08\udc0a-\udc36\udc38-\udc45\udc50-\udc6c]"},{name:"Bopomofo",bmp:"\u02ea\u02eb\u3105-\u312d\u31a0-\u31ba"},{name:"Brahmi",astral:"\ud804[\udc00-\udc4d\udc52-\udc6f\udc7f]"},{name:"Braille",bmp:"\u2800-\u28ff"},{name:"Buginese",bmp:"\u1a00-\u1a1b\u1a1e\u1a1f"},{name:"Buhid",bmp:"\u1740-\u1753"},{name:"Canadian_Aboriginal",bmp:"\u1400-\u167f\u18b0-\u18f5"},{name:"Carian",astral:"\ud800[\udea0-\uded0]"},{name:"Caucasian_Albanian",astral:"\ud801[\udd30-\udd63\udd6f]"},{name:"Chakma",astral:"\ud804[\udd00-\udd34\udd36-\udd43]"},{name:"Cham",bmp:"\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa5c-\uaa5f"},{name:"Cherokee",bmp:"\u13a0-\u13f5\u13f8-\u13fd\uab70-\uabbf"},{name:"Common",bmp:"\0-@\\x5B-`\\x7B-\xa9\xab-\xb9\xbb-\xbf\xd7\xf7\u02b9-\u02df\u02e5-\u02e9\u02ec-\u02ff\u0374\u037e\u0385\u0387\u0589\u0605\u060c\u061b\u061c\u061f\u0640\u06dd\u08e2\u0964\u0965\u0e3f\u0fd5-\u0fd8\u10fb\u16eb-\u16ed\u1735\u1736\u1802\u1803\u1805\u1cd3\u1ce1\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u2000-\u200b\u200e-\u2064\u2066-\u2070\u2074-\u207e\u2080-\u208e\u20a0-\u20be\u2100-\u2125\u2127-\u2129\u212c-\u2131\u2133-\u214d\u214f-\u215f\u2189-\u218b\u2190-\u23fe\u2400-\u2426\u2440-\u244a\u2460-\u27ff\u2900-\u2b73\u2b76-\u2b95\u2b98-\u2bb9\u2bbd-\u2bc8\u2bca-\u2bd1\u2bec-\u2bef\u2e00-\u2e44\u2ff0-\u2ffb\u3000-\u3004\u3006\u3008-\u3020\u3030-\u3037\u303c-\u303f\u309b\u309c\u30a0\u30fb\u30fc\u3190-\u319f\u31c0-\u31e3\u3220-\u325f\u327f-\u32cf\u3358-\u33ff\u4dc0-\u4dff\ua700-\ua721\ua788-\ua78a\ua830-\ua839\ua92e\ua9cf\uab5b\ufd3e\ufd3f\ufe10-\ufe19\ufe30-\ufe52\ufe54-\ufe66\ufe68-\ufe6b\ufeff\uff01-\uff20\uff3b-\uff40\uff5b-\uff65\uff70\uff9e\uff9f\uffe0-\uffe6\uffe8-\uffee\ufff9-\ufffd",astral:"\ud800[\udd00-\udd02\udd07-\udd33\udd37-\udd3f\udd90-\udd9b\uddd0-\uddfc\udee1-\udefb]|\ud82f[\udca0-\udca3]|\ud834[\udc00-\udcf5\udd00-\udd26\udd29-\udd66\udd6a-\udd7a\udd83\udd84\udd8c-\udda9\uddae-\udde8\udf00-\udf56\udf60-\udf71]|\ud835[\udc00-\udc54\udc56-\udc9c\udc9e\udc9f\udca2\udca5\udca6\udca9-\udcac\udcae-\udcb9\udcbb\udcbd-\udcc3\udcc5-\udd05\udd07-\udd0a\udd0d-\udd14\udd16-\udd1c\udd1e-\udd39\udd3b-\udd3e\udd40-\udd44\udd46\udd4a-\udd50\udd52-\udea5\udea8-\udfcb\udfce-\udfff]|\ud83c[\udc00-\udc2b\udc30-\udc93\udca0-\udcae\udcb1-\udcbf\udcc1-\udccf\udcd1-\udcf5\udd00-\udd0c\udd10-\udd2e\udd30-\udd6b\udd70-\uddac\udde6-\uddff\ude01\ude02\ude10-\ude3b\ude40-\ude48\ude50\ude51\udf00-\udfff]|\ud83d[\udc00-\uded2\udee0-\udeec\udef0-\udef6\udf00-\udf73\udf80-\udfd4]|\ud83e[\udc00-\udc0b\udc10-\udc47\udc50-\udc59\udc60-\udc87\udc90-\udcad\udd10-\udd1e\udd20-\udd27\udd30\udd33-\udd3e\udd40-\udd4b\udd50-\udd5e\udd80-\udd91\uddc0]|\udb40[\udc01\udc20-\udc7f]"},{name:"Coptic",bmp:"\u03e2-\u03ef\u2c80-\u2cf3\u2cf9-\u2cff"},{name:"Cuneiform",astral:"\ud808[\udc00-\udf99]|\ud809[\udc00-\udc6e\udc70-\udc74\udc80-\udd43]"},{name:"Cypriot",astral:"\ud802[\udc00-\udc05\udc08\udc0a-\udc35\udc37\udc38\udc3c\udc3f]"},{name:"Cyrillic",bmp:"\u0400-\u0484\u0487-\u052f\u1c80-\u1c88\u1d2b\u1d78\u2de0-\u2dff\ua640-\ua69f\ufe2e\ufe2f"},{name:"Deseret",astral:"\ud801[\udc00-\udc4f]"},{name:"Devanagari",bmp:"\u0900-\u0950\u0953-\u0963\u0966-\u097f\ua8e0-\ua8fd"},{name:"Duployan",astral:"\ud82f[\udc00-\udc6a\udc70-\udc7c\udc80-\udc88\udc90-\udc99\udc9c-\udc9f]"},{name:"Egyptian_Hieroglyphs",astral:"\ud80c[\udc00-\udfff]|\ud80d[\udc00-\udc2e]"},{name:"Elbasan",astral:"\ud801[\udd00-\udd27]"},{name:"Ethiopic",bmp:"\u1200-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u137c\u1380-\u1399\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e"},{name:"Georgian",bmp:"\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u10ff\u2d00-\u2d25\u2d27\u2d2d"},{name:"Glagolitic",bmp:"\u2c00-\u2c2e\u2c30-\u2c5e",astral:"\ud838[\udc00-\udc06\udc08-\udc18\udc1b-\udc21\udc23\udc24\udc26-\udc2a]"},{name:"Gothic",astral:"\ud800[\udf30-\udf4a]"},{name:"Grantha",astral:"\ud804[\udf00-\udf03\udf05-\udf0c\udf0f\udf10\udf13-\udf28\udf2a-\udf30\udf32\udf33\udf35-\udf39\udf3c-\udf44\udf47\udf48\udf4b-\udf4d\udf50\udf57\udf5d-\udf63\udf66-\udf6c\udf70-\udf74]"},{name:"Greek",bmp:"\u0370-\u0373\u0375-\u0377\u037a-\u037d\u037f\u0384\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03e1\u03f0-\u03ff\u1d26-\u1d2a\u1d5d-\u1d61\u1d66-\u1d6a\u1dbf\u1f00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fc4\u1fc6-\u1fd3\u1fd6-\u1fdb\u1fdd-\u1fef\u1ff2-\u1ff4\u1ff6-\u1ffe\u2126\uab65",astral:"\ud800[\udd40-\udd8e\udda0]|\ud834[\ude00-\ude45]"},{name:"Gujarati",bmp:"\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0af1\u0af9"},{name:"Gurmukhi",bmp:"\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75"},{name:"Han",bmp:"\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u3005\u3007\u3021-\u3029\u3038-\u303b\u3400-\u4db5\u4e00-\u9fd5\uf900-\ufa6d\ufa70-\ufad9",astral:"[\ud840-\ud868\ud86a-\ud86c\ud86f-\ud872][\udc00-\udfff]|\ud869[\udc00-\uded6\udf00-\udfff]|\ud86d[\udc00-\udf34\udf40-\udfff]|\ud86e[\udc00-\udc1d\udc20-\udfff]|\ud873[\udc00-\udea1]|\ud87e[\udc00-\ude1d]"},{name:"Hangul",bmp:"\u1100-\u11ff\u302e\u302f\u3131-\u318e\u3200-\u321e\u3260-\u327e\ua960-\ua97c\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uffa0-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc"},{name:"Hanunoo",bmp:"\u1720-\u1734"},{name:"Hatran",astral:"\ud802[\udce0-\udcf2\udcf4\udcf5\udcfb-\udcff]"},{name:"Hebrew",bmp:"\u0591-\u05c7\u05d0-\u05ea\u05f0-\u05f4\ufb1d-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufb4f"},{name:"Hiragana",bmp:"\u3041-\u3096\u309d-\u309f",astral:"\ud82c\udc01|\ud83c\ude00"},{name:"Imperial_Aramaic",astral:"\ud802[\udc40-\udc55\udc57-\udc5f]"},{name:"Inherited",bmp:"\u0300-\u036f\u0485\u0486\u064b-\u0655\u0670\u0951\u0952\u1ab0-\u1abe\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1cf4\u1cf8\u1cf9\u1dc0-\u1df5\u1dfb-\u1dff\u200c\u200d\u20d0-\u20f0\u302a-\u302d\u3099\u309a\ufe00-\ufe0f\ufe20-\ufe2d",astral:"\ud800[\uddfd\udee0]|\ud834[\udd67-\udd69\udd7b-\udd82\udd85-\udd8b\uddaa-\uddad]|\udb40[\udd00-\uddef]"},{name:"Inscriptional_Pahlavi",astral:"\ud802[\udf60-\udf72\udf78-\udf7f]"},{name:"Inscriptional_Parthian",astral:"\ud802[\udf40-\udf55\udf58-\udf5f]"},{name:"Javanese",bmp:"\ua980-\ua9cd\ua9d0-\ua9d9\ua9de\ua9df"},{name:"Kaithi",astral:"\ud804[\udc80-\udcc1]"},{name:"Kannada",bmp:"\u0c80-\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2"},{name:"Katakana",bmp:"\u30a1-\u30fa\u30fd-\u30ff\u31f0-\u31ff\u32d0-\u32fe\u3300-\u3357\uff66-\uff6f\uff71-\uff9d",astral:"\ud82c\udc00"},{name:"Kayah_Li",bmp:"\ua900-\ua92d\ua92f"},{name:"Kharoshthi",astral:"\ud802[\ude00-\ude03\ude05\ude06\ude0c-\ude13\ude15-\ude17\ude19-\ude33\ude38-\ude3a\ude3f-\ude47\ude50-\ude58]"},{name:"Khmer",bmp:"\u1780-\u17dd\u17e0-\u17e9\u17f0-\u17f9\u19e0-\u19ff"},{name:"Khojki",astral:"\ud804[\ude00-\ude11\ude13-\ude3e]"},{name:"Khudawadi",astral:"\ud804[\udeb0-\udeea\udef0-\udef9]"},{name:"Lao",bmp:"\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf"},{name:"Latin",bmp:"A-Za-z\xaa\xba\xc0-\xd6\xd8-\xf6\xf8-\u02b8\u02e0-\u02e4\u1d00-\u1d25\u1d2c-\u1d5c\u1d62-\u1d65\u1d6b-\u1d77\u1d79-\u1dbe\u1e00-\u1eff\u2071\u207f\u2090-\u209c\u212a\u212b\u2132\u214e\u2160-\u2188\u2c60-\u2c7f\ua722-\ua787\ua78b-\ua7ae\ua7b0-\ua7b7\ua7f7-\ua7ff\uab30-\uab5a\uab5c-\uab64\ufb00-\ufb06\uff21-\uff3a\uff41-\uff5a"},{name:"Lepcha",bmp:"\u1c00-\u1c37\u1c3b-\u1c49\u1c4d-\u1c4f"},{name:"Limbu",bmp:"\u1900-\u191e\u1920-\u192b\u1930-\u193b\u1940\u1944-\u194f"},{name:"Linear_A",astral:"\ud801[\ude00-\udf36\udf40-\udf55\udf60-\udf67]"},{name:"Linear_B",astral:"\ud800[\udc00-\udc0b\udc0d-\udc26\udc28-\udc3a\udc3c\udc3d\udc3f-\udc4d\udc50-\udc5d\udc80-\udcfa]"},{name:"Lisu",bmp:"\ua4d0-\ua4ff"},{name:"Lycian",astral:"\ud800[\ude80-\ude9c]"},{name:"Lydian",astral:"\ud802[\udd20-\udd39\udd3f]"},{name:"Mahajani",astral:"\ud804[\udd50-\udd76]"},{name:"Malayalam",bmp:"\u0d01-\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4f\u0d54-\u0d63\u0d66-\u0d7f"},{name:"Mandaic",bmp:"\u0840-\u085b\u085e"},{name:"Manichaean",astral:"\ud802[\udec0-\udee6\udeeb-\udef6]"},{name:"Marchen",astral:"\ud807[\udc70-\udc8f\udc92-\udca7\udca9-\udcb6]"},{name:"Meetei_Mayek",bmp:"\uaae0-\uaaf6\uabc0-\uabed\uabf0-\uabf9"},{name:"Mende_Kikakui",astral:"\ud83a[\udc00-\udcc4\udcc7-\udcd6]"},{name:"Meroitic_Cursive",astral:"\ud802[\udda0-\uddb7\uddbc-\uddcf\uddd2-\uddff]"},{name:"Meroitic_Hieroglyphs",astral:"\ud802[\udd80-\udd9f]"},{name:"Miao",astral:"\ud81b[\udf00-\udf44\udf50-\udf7e\udf8f-\udf9f]"},{name:"Modi",astral:"\ud805[\ude00-\ude44\ude50-\ude59]"},{name:"Mongolian",bmp:"\u1800\u1801\u1804\u1806-\u180e\u1810-\u1819\u1820-\u1877\u1880-\u18aa",astral:"\ud805[\ude60-\ude6c]"},{name:"Mro",astral:"\ud81a[\ude40-\ude5e\ude60-\ude69\ude6e\ude6f]"},{name:"Multani",astral:"\ud804[\ude80-\ude86\ude88\ude8a-\ude8d\ude8f-\ude9d\ude9f-\udea9]"},{name:"Myanmar",bmp:"\u1000-\u109f\ua9e0-\ua9fe\uaa60-\uaa7f"},{name:"Nabataean",astral:"\ud802[\udc80-\udc9e\udca7-\udcaf]"},{name:"New_Tai_Lue",bmp:"\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19da\u19de\u19df"},{name:"Newa",astral:"\ud805[\udc00-\udc59\udc5b\udc5d]"},{name:"Nko",bmp:"\u07c0-\u07fa"},{name:"Ogham",bmp:"\u1680-\u169c"},{name:"Ol_Chiki",bmp:"\u1c50-\u1c7f"},{name:"Old_Hungarian",astral:"\ud803[\udc80-\udcb2\udcc0-\udcf2\udcfa-\udcff]"},{name:"Old_Italic",astral:"\ud800[\udf00-\udf23]"},{name:"Old_North_Arabian",astral:"\ud802[\ude80-\ude9f]"},{name:"Old_Permic",astral:"\ud800[\udf50-\udf7a]"},{name:"Old_Persian",astral:"\ud800[\udfa0-\udfc3\udfc8-\udfd5]"},{name:"Old_South_Arabian",astral:"\ud802[\ude60-\ude7f]"},{name:"Old_Turkic",astral:"\ud803[\udc00-\udc48]"},{name:"Oriya",bmp:"\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b77"},{name:"Osage",astral:"\ud801[\udcb0-\udcd3\udcd8-\udcfb]"},{name:"Osmanya",astral:"\ud801[\udc80-\udc9d\udca0-\udca9]"},{name:"Pahawh_Hmong",astral:"\ud81a[\udf00-\udf45\udf50-\udf59\udf5b-\udf61\udf63-\udf77\udf7d-\udf8f]"},{name:"Palmyrene",astral:"\ud802[\udc60-\udc7f]"},{name:"Pau_Cin_Hau",astral:"\ud806[\udec0-\udef8]"},{name:"Phags_Pa",bmp:"\ua840-\ua877"},{name:"Phoenician",astral:"\ud802[\udd00-\udd1b\udd1f]"},{name:"Psalter_Pahlavi",astral:"\ud802[\udf80-\udf91\udf99-\udf9c\udfa9-\udfaf]"},{name:"Rejang",bmp:"\ua930-\ua953\ua95f"},{name:"Runic",bmp:"\u16a0-\u16ea\u16ee-\u16f8"},{name:"Samaritan",bmp:"\u0800-\u082d\u0830-\u083e"},{name:"Saurashtra",bmp:"\ua880-\ua8c5\ua8ce-\ua8d9"},{name:"Sharada",astral:"\ud804[\udd80-\uddcd\uddd0-\udddf]"},{name:"Shavian",astral:"\ud801[\udc50-\udc7f]"},{name:"Siddham",astral:"\ud805[\udd80-\uddb5\uddb8-\udddd]"},{name:"SignWriting",astral:"\ud836[\udc00-\ude8b\ude9b-\ude9f\udea1-\udeaf]"},{name:"Sinhala",bmp:"\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2-\u0df4",astral:"\ud804[\udde1-\uddf4]"},{name:"Sora_Sompeng",astral:"\ud804[\udcd0-\udce8\udcf0-\udcf9]"},{name:"Sundanese",bmp:"\u1b80-\u1bbf\u1cc0-\u1cc7"},{name:"Syloti_Nagri",bmp:"\ua800-\ua82b"},{name:"Syriac",bmp:"\u0700-\u070d\u070f-\u074a\u074d-\u074f"},{name:"Tagalog",bmp:"\u1700-\u170c\u170e-\u1714"},{name:"Tagbanwa",bmp:"\u1760-\u176c\u176e-\u1770\u1772\u1773"},{name:"Tai_Le",bmp:"\u1950-\u196d\u1970-\u1974"},{name:"Tai_Tham",bmp:"\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa0-\u1aad"},{name:"Tai_Viet",bmp:"\uaa80-\uaac2\uaadb-\uaadf"},{name:"Takri",astral:"\ud805[\ude80-\udeb7\udec0-\udec9]"},{name:"Tamil",bmp:"\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bfa"},{name:"Tangut",astral:"\ud81b\udfe0|[\ud81c-\ud820][\udc00-\udfff]|\ud821[\udc00-\udfec]|\ud822[\udc00-\udef2]"},{name:"Telugu",bmp:"\u0c00-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58-\u0c5a\u0c60-\u0c63\u0c66-\u0c6f\u0c78-\u0c7f"},{name:"Thaana",bmp:"\u0780-\u07b1"},{name:"Thai",bmp:"\u0e01-\u0e3a\u0e40-\u0e5b"},{name:"Tibetan",bmp:"\u0f00-\u0f47\u0f49-\u0f6c\u0f71-\u0f97\u0f99-\u0fbc\u0fbe-\u0fcc\u0fce-\u0fd4\u0fd9\u0fda"},{name:"Tifinagh",bmp:"\u2d30-\u2d67\u2d6f\u2d70\u2d7f"},{name:"Tirhuta",astral:"\ud805[\udc80-\udcc7\udcd0-\udcd9]"},{name:"Ugaritic",astral:"\ud800[\udf80-\udf9d\udf9f]"},{name:"Vai",bmp:"\ua500-\ua62b"},{name:"Warang_Citi",astral:"\ud806[\udca0-\udcf2\udcff]"},{name:"Yi",bmp:"\ua000-\ua48c\ua490-\ua4c6"}])},e.exports=t.default},500:function(e,t,n){"use strict";var u=n(0),r=n.n(u);t.a=function(e){var t=e.text;return r.a.createElement("section",{className:"empty"},r.a.createElement("div",{className:"icon"},r.a.createElement("img",{src:"/img/logo-square.svg",alt:"The Qovery Logo"})),r.a.createElement("div",{className:"text"},t))}},501:function(e,t,n){"use strict";var u=n(502),r=n(512),a=n(468);e.exports={formats:a,parse:r,stringify:u}},502:function(e,t,n){"use strict";var u=n(503),r=n(475),a=n(468),d=Object.prototype.hasOwnProperty,o={brackets:function(e){return e+"[]"},comma:"comma",indices:function(e,t){return e+"["+t+"]"},repeat:function(e){return e}},i=Array.isArray,c=String.prototype.split,l=Array.prototype.push,f=function(e,t){l.apply(e,i(t)?t:[t])},s=Date.prototype.toISOString,p=a.default,m={addQueryPrefix:!1,allowDots:!1,charset:"utf-8",charsetSentinel:!1,delimiter:"&",encode:!0,encoder:r.encode,encodeValuesOnly:!1,format:p,formatter:a.formatters[p],indices:!1,serializeDate:function(e){return s.call(e)},skipNulls:!1,strictNullHandling:!1},h={},b=function e(t,n,a,d,o,l,s,p,b,v,g,y,_,E,w,D){for(var k,x=t,S=D,C=0,O=!1;void 0!==(S=S.get(h))&&!O;){var I=S.get(t);if(C+=1,void 0!==I){if(I===C)throw new RangeError("Cyclic object value");O=!0}void 0===S.get(h)&&(C=0)}if("function"==typeof p?x=p(n,x):x instanceof Date?x=g(x):"comma"===a&&i(x)&&(x=r.maybeMap(x,(function(e){return e instanceof Date?g(e):e}))),null===x){if(o)return s&&!E?s(n,m.encoder,w,"key",y):n;x=""}if("string"==typeof(k=x)||"number"==typeof k||"boolean"==typeof k||"symbol"==typeof k||"bigint"==typeof k||r.isBuffer(x)){if(s){var A=E?n:s(n,m.encoder,w,"key",y);if("comma"===a&&E){for(var j=c.call(String(x),","),N="",F=0;F0?x.join(",")||null:void 0}];else if(i(p))T=p;else{var M=Object.keys(x);T=b?M.sort(b):M}for(var R=d&&i(x)&&1===x.length?n+"[]":n,L=0;L0?E+_:""}},503:function(e,t,n){"use strict";var u=n(466),r=n(508),a=n(510),d=u("%TypeError%"),o=u("%WeakMap%",!0),i=u("%Map%",!0),c=r("WeakMap.prototype.get",!0),l=r("WeakMap.prototype.set",!0),f=r("WeakMap.prototype.has",!0),s=r("Map.prototype.get",!0),p=r("Map.prototype.set",!0),m=r("Map.prototype.has",!0),h=function(e,t){for(var n,u=e;null!==(n=u.next);u=n)if(n.key===t)return u.next=n.next,n.next=e.next,e.next=n,n};e.exports=function(){var e,t,n,u={assert:function(e){if(!u.has(e))throw new d("Side channel does not contain "+a(e))},get:function(u){if(o&&u&&("object"==typeof u||"function"==typeof u)){if(e)return c(e,u)}else if(i){if(t)return s(t,u)}else if(n)return function(e,t){var n=h(e,t);return n&&n.value}(n,u)},has:function(u){if(o&&u&&("object"==typeof u||"function"==typeof u)){if(e)return f(e,u)}else if(i){if(t)return m(t,u)}else if(n)return function(e,t){return!!h(e,t)}(n,u);return!1},set:function(u,r){o&&u&&("object"==typeof u||"function"==typeof u)?(e||(e=new o),l(e,u,r)):i?(t||(t=new i),p(t,u,r)):(n||(n={key:{},next:null}),function(e,t,n){var u=h(e,t);u?u.value=n:e.next={key:t,next:e.next,value:n}}(n,u,r))}};return u}},504:function(e,t,n){"use strict";var u="undefined"!=typeof Symbol&&Symbol,r=n(505);e.exports=function(){return"function"==typeof u&&("function"==typeof Symbol&&("symbol"==typeof u("foo")&&("symbol"==typeof Symbol("bar")&&r())))}},505:function(e,t,n){"use strict";e.exports=function(){if("function"!=typeof Symbol||"function"!=typeof Object.getOwnPropertySymbols)return!1;if("symbol"==typeof Symbol.iterator)return!0;var e={},t=Symbol("test"),n=Object(t);if("string"==typeof t)return!1;if("[object Symbol]"!==Object.prototype.toString.call(t))return!1;if("[object Symbol]"!==Object.prototype.toString.call(n))return!1;for(t in e[t]=42,e)return!1;if("function"==typeof Object.keys&&0!==Object.keys(e).length)return!1;if("function"==typeof Object.getOwnPropertyNames&&0!==Object.getOwnPropertyNames(e).length)return!1;var u=Object.getOwnPropertySymbols(e);if(1!==u.length||u[0]!==t)return!1;if(!Object.prototype.propertyIsEnumerable.call(e,t))return!1;if("function"==typeof Object.getOwnPropertyDescriptor){var r=Object.getOwnPropertyDescriptor(e,t);if(42!==r.value||!0!==r.enumerable)return!1}return!0}},506:function(e,t,n){"use strict";var u="Function.prototype.bind called on incompatible ",r=Array.prototype.slice,a=Object.prototype.toString;e.exports=function(e){var t=this;if("function"!=typeof t||"[object Function]"!==a.call(t))throw new TypeError(u+t);for(var n,d=r.call(arguments,1),o=function(){if(this instanceof n){var u=t.apply(this,d.concat(r.call(arguments)));return Object(u)===u?u:this}return t.apply(e,d.concat(r.call(arguments)))},i=Math.max(0,t.length-d.length),c=[],l=0;l-1?r(n):n}},509:function(e,t,n){"use strict";var u=n(467),r=n(466),a=r("%Function.prototype.apply%"),d=r("%Function.prototype.call%"),o=r("%Reflect.apply%",!0)||u.call(d,a),i=r("%Object.getOwnPropertyDescriptor%",!0),c=r("%Object.defineProperty%",!0),l=r("%Math.max%");if(c)try{c({},"a",{value:1})}catch(s){c=null}e.exports=function(e){var t=o(u,d,arguments);if(i&&c){var n=i(t,"length");n.configurable&&c(t,"length",{value:1+l(0,e.length-(arguments.length-1))})}return t};var f=function(){return o(u,a,arguments)};c?c(e.exports,"apply",{value:f}):e.exports.apply=f},510:function(e,t,n){var u="function"==typeof Map&&Map.prototype,r=Object.getOwnPropertyDescriptor&&u?Object.getOwnPropertyDescriptor(Map.prototype,"size"):null,a=u&&r&&"function"==typeof r.get?r.get:null,d=u&&Map.prototype.forEach,o="function"==typeof Set&&Set.prototype,i=Object.getOwnPropertyDescriptor&&o?Object.getOwnPropertyDescriptor(Set.prototype,"size"):null,c=o&&i&&"function"==typeof i.get?i.get:null,l=o&&Set.prototype.forEach,f="function"==typeof WeakMap&&WeakMap.prototype?WeakMap.prototype.has:null,s="function"==typeof WeakSet&&WeakSet.prototype?WeakSet.prototype.has:null,p="function"==typeof WeakRef&&WeakRef.prototype?WeakRef.prototype.deref:null,m=Boolean.prototype.valueOf,h=Object.prototype.toString,b=Function.prototype.toString,v=String.prototype.match,g=String.prototype.slice,y=String.prototype.replace,_=String.prototype.toUpperCase,E=String.prototype.toLowerCase,w=RegExp.prototype.test,D=Array.prototype.concat,k=Array.prototype.join,x=Array.prototype.slice,S=Math.floor,C="function"==typeof BigInt?BigInt.prototype.valueOf:null,O=Object.getOwnPropertySymbols,I="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?Symbol.prototype.toString:null,A="function"==typeof Symbol&&"object"==typeof Symbol.iterator,j="function"==typeof Symbol&&Symbol.toStringTag&&(typeof Symbol.toStringTag===A||"symbol")?Symbol.toStringTag:null,N=Object.prototype.propertyIsEnumerable,F=("function"==typeof Reflect?Reflect.getPrototypeOf:Object.getPrototypeOf)||([].__proto__===Array.prototype?function(e){return e.__proto__}:null);function T(e,t){if(e===1/0||e===-1/0||e!=e||e&&e>-1e3&&e<1e3||w.call(/e/,t))return t;var n=/[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;if("number"==typeof e){var u=e<0?-S(-e):S(e);if(u!==e){var r=String(u),a=g.call(t,r.length+1);return y.call(r,n,"$&_")+"."+y.call(y.call(a,/([0-9]{3})/g,"$&_"),/_$/,"")}}return y.call(t,n,"$&_")}var P=n(511),M=P.custom,R=W(M)?M:null;function L(e,t,n){var u="double"===(n.quoteStyle||t)?'"':"'";return u+e+u}function B(e){return y.call(String(e),/"/g,""")}function z(e){return!("[object Array]"!==q(e)||j&&"object"==typeof e&&j in e)}function U(e){return!("[object RegExp]"!==q(e)||j&&"object"==typeof e&&j in e)}function W(e){if(A)return e&&"object"==typeof e&&e instanceof Symbol;if("symbol"==typeof e)return!0;if(!e||"object"!=typeof e||!I)return!1;try{return I.call(e),!0}catch(t){}return!1}e.exports=function e(t,n,u,r){var o=n||{};if($(o,"quoteStyle")&&"single"!==o.quoteStyle&&"double"!==o.quoteStyle)throw new TypeError('option "quoteStyle" must be "single" or "double"');if($(o,"maxStringLength")&&("number"==typeof o.maxStringLength?o.maxStringLength<0&&o.maxStringLength!==1/0:null!==o.maxStringLength))throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`');var i=!$(o,"customInspect")||o.customInspect;if("boolean"!=typeof i&&"symbol"!==i)throw new TypeError("option \"customInspect\", if provided, must be `true`, `false`, or `'symbol'`");if($(o,"indent")&&null!==o.indent&&"\t"!==o.indent&&!(parseInt(o.indent,10)===o.indent&&o.indent>0))throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`');if($(o,"numericSeparator")&&"boolean"!=typeof o.numericSeparator)throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`');var h=o.numericSeparator;if(void 0===t)return"undefined";if(null===t)return"null";if("boolean"==typeof t)return t?"true":"false";if("string"==typeof t)return function e(t,n){if(t.length>n.maxStringLength){var u=t.length-n.maxStringLength,r="... "+u+" more character"+(u>1?"s":"");return e(g.call(t,0,n.maxStringLength),n)+r}return L(y.call(y.call(t,/(['\\])/g,"\\$1"),/[\x00-\x1f]/g,V),"single",n)}(t,o);if("number"==typeof t){if(0===t)return 1/0/t>0?"0":"-0";var _=String(t);return h?T(t,_):_}if("bigint"==typeof t){var w=String(t)+"n";return h?T(t,w):w}var S=void 0===o.depth?5:o.depth;if(void 0===u&&(u=0),u>=S&&S>0&&"object"==typeof t)return z(t)?"[Array]":"[Object]";var O=function(e,t){var n;if("\t"===e.indent)n="\t";else{if(!("number"==typeof e.indent&&e.indent>0))return null;n=k.call(Array(e.indent+1)," ")}return{base:n,prev:k.call(Array(t+1),n)}}(o,u);if(void 0===r)r=[];else if(G(r,t)>=0)return"[Circular]";function M(t,n,a){if(n&&(r=x.call(r)).push(n),a){var d={depth:o.depth};return $(o,"quoteStyle")&&(d.quoteStyle=o.quoteStyle),e(t,d,u+1,r)}return e(t,o,u+1,r)}if("function"==typeof t&&!U(t)){var H=function(e){if(e.name)return e.name;var t=v.call(b.call(e),/^function\s*([\w$]+)/);if(t)return t[1];return null}(t),X=Q(t,M);return"[Function"+(H?": "+H:" (anonymous)")+"]"+(X.length>0?" { "+k.call(X,", ")+" }":"")}if(W(t)){var ee=A?y.call(String(t),/^(Symbol\(.*\))_[^)]*$/,"$1"):I.call(t);return"object"!=typeof t||A?ee:K(ee)}if(function(e){if(!e||"object"!=typeof e)return!1;if("undefined"!=typeof HTMLElement&&e instanceof HTMLElement)return!0;return"string"==typeof e.nodeName&&"function"==typeof e.getAttribute}(t)){for(var te="<"+E.call(String(t.nodeName)),ne=t.attributes||[],ue=0;ue"}if(z(t)){if(0===t.length)return"[]";var re=Q(t,M);return O&&!function(e){for(var t=0;t=0)return!1;return!0}(re)?"["+Y(re,O)+"]":"[ "+k.call(re,", ")+" ]"}if(function(e){return!("[object Error]"!==q(e)||j&&"object"==typeof e&&j in e)}(t)){var ae=Q(t,M);return"cause"in Error.prototype||!("cause"in t)||N.call(t,"cause")?0===ae.length?"["+String(t)+"]":"{ ["+String(t)+"] "+k.call(ae,", ")+" }":"{ ["+String(t)+"] "+k.call(D.call("[cause]: "+M(t.cause),ae),", ")+" }"}if("object"==typeof t&&i){if(R&&"function"==typeof t[R]&&P)return P(t,{depth:S-u});if("symbol"!==i&&"function"==typeof t.inspect)return t.inspect()}if(function(e){if(!a||!e||"object"!=typeof e)return!1;try{a.call(e);try{c.call(e)}catch(te){return!0}return e instanceof Map}catch(t){}return!1}(t)){var de=[];return d.call(t,(function(e,n){de.push(M(n,t,!0)+" => "+M(e,t))})),J("Map",a.call(t),de,O)}if(function(e){if(!c||!e||"object"!=typeof e)return!1;try{c.call(e);try{a.call(e)}catch(t){return!0}return e instanceof Set}catch(n){}return!1}(t)){var oe=[];return l.call(t,(function(e){oe.push(M(e,t))})),J("Set",c.call(t),oe,O)}if(function(e){if(!f||!e||"object"!=typeof e)return!1;try{f.call(e,f);try{s.call(e,s)}catch(te){return!0}return e instanceof WeakMap}catch(t){}return!1}(t))return Z("WeakMap");if(function(e){if(!s||!e||"object"!=typeof e)return!1;try{s.call(e,s);try{f.call(e,f)}catch(te){return!0}return e instanceof WeakSet}catch(t){}return!1}(t))return Z("WeakSet");if(function(e){if(!p||!e||"object"!=typeof e)return!1;try{return p.call(e),!0}catch(t){}return!1}(t))return Z("WeakRef");if(function(e){return!("[object Number]"!==q(e)||j&&"object"==typeof e&&j in e)}(t))return K(M(Number(t)));if(function(e){if(!e||"object"!=typeof e||!C)return!1;try{return C.call(e),!0}catch(t){}return!1}(t))return K(M(C.call(t)));if(function(e){return!("[object Boolean]"!==q(e)||j&&"object"==typeof e&&j in e)}(t))return K(m.call(t));if(function(e){return!("[object String]"!==q(e)||j&&"object"==typeof e&&j in e)}(t))return K(M(String(t)));if(!function(e){return!("[object Date]"!==q(e)||j&&"object"==typeof e&&j in e)}(t)&&!U(t)){var ie=Q(t,M),ce=F?F(t)===Object.prototype:t instanceof Object||t.constructor===Object,le=t instanceof Object?"":"null prototype",fe=!ce&&j&&Object(t)===t&&j in t?g.call(q(t),8,-1):le?"Object":"",se=(ce||"function"!=typeof t.constructor?"":t.constructor.name?t.constructor.name+" ":"")+(fe||le?"["+k.call(D.call([],fe||[],le||[]),": ")+"] ":"");return 0===ie.length?se+"{}":O?se+"{"+Y(ie,O)+"}":se+"{ "+k.call(ie,", ")+" }"}return String(t)};var H=Object.prototype.hasOwnProperty||function(e){return e in this};function $(e,t){return H.call(e,t)}function q(e){return h.call(e)}function G(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0,u=e.length;n-1?e.split(","):e},c=function(e,t,n,u){if(e){var a=n.allowDots?e.replace(/\.([^.[]+)/g,"[$1]"):e,d=/(\[[^[\]]*])/g,o=n.depth>0&&/(\[[^[\]]*])/.exec(a),c=o?a.slice(0,o.index):a,l=[];if(c){if(!n.plainObjects&&r.call(Object.prototype,c)&&!n.allowPrototypes)return;l.push(c)}for(var f=0;n.depth>0&&null!==(o=d.exec(a))&&f=0;--a){var d,o=e[a];if("[]"===o&&n.parseArrays)d=[].concat(r);else{d=n.plainObjects?Object.create(null):{};var c="["===o.charAt(0)&&"]"===o.charAt(o.length-1)?o.slice(1,-1):o,l=parseInt(c,10);n.parseArrays||""!==c?!isNaN(l)&&o!==c&&String(l)===c&&l>=0&&n.parseArrays&&l<=n.arrayLimit?(d=[])[l]=r:"__proto__"!==c&&(d[c]=r):d={0:r}}r=d}return r}(l,t,n,u)}};e.exports=function(e,t){var n=function(e){if(!e)return d;if(null!==e.decoder&&void 0!==e.decoder&&"function"!=typeof e.decoder)throw new TypeError("Decoder has to be a function.");if(void 0!==e.charset&&"utf-8"!==e.charset&&"iso-8859-1"!==e.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var t=void 0===e.charset?d.charset:e.charset;return{allowDots:void 0===e.allowDots?d.allowDots:!!e.allowDots,allowPrototypes:"boolean"==typeof e.allowPrototypes?e.allowPrototypes:d.allowPrototypes,allowSparse:"boolean"==typeof e.allowSparse?e.allowSparse:d.allowSparse,arrayLimit:"number"==typeof e.arrayLimit?e.arrayLimit:d.arrayLimit,charset:t,charsetSentinel:"boolean"==typeof e.charsetSentinel?e.charsetSentinel:d.charsetSentinel,comma:"boolean"==typeof e.comma?e.comma:d.comma,decoder:"function"==typeof e.decoder?e.decoder:d.decoder,delimiter:"string"==typeof e.delimiter||u.isRegExp(e.delimiter)?e.delimiter:d.delimiter,depth:"number"==typeof e.depth||!1===e.depth?+e.depth:d.depth,ignoreQueryPrefix:!0===e.ignoreQueryPrefix,interpretNumericEntities:"boolean"==typeof e.interpretNumericEntities?e.interpretNumericEntities:d.interpretNumericEntities,parameterLimit:"number"==typeof e.parameterLimit?e.parameterLimit:d.parameterLimit,parseArrays:!1!==e.parseArrays,plainObjects:"boolean"==typeof e.plainObjects?e.plainObjects:d.plainObjects,strictNullHandling:"boolean"==typeof e.strictNullHandling?e.strictNullHandling:d.strictNullHandling}}(t);if(""===e||null==e)return n.plainObjects?Object.create(null):{};for(var l="string"==typeof e?function(e,t){var n,c={},l=t.ignoreQueryPrefix?e.replace(/^\?/,""):e,f=t.parameterLimit===1/0?void 0:t.parameterLimit,s=l.split(t.delimiter,f),p=-1,m=t.charset;if(t.charsetSentinel)for(n=0;n-1&&(b=a(b)?[b]:b),r.call(c,h)?c[h]=u.combine(c[h],b):c[h]=b}return c}(e,n):e,f=n.plainObjects?Object.create(null):{},s=Object.keys(l),p=0;p'},heart:{width:12,height:16,path:''},eye:{width:16,height:16,path:''},star:{width:14,height:16,path:''},"repo-forked":{width:10,height:16,path:''},"repo-template":{width:14,height:16,path:''},"issue-opened":{width:14,height:16,path:''},"cloud-download":{width:16,height:16,path:''}},g={},y=function(e,t){var n=g[e]||(g[e]=[]);if(!(n.push(t)>1)){var u=function(e){var t;return function(){t||(t=1,e.apply(this,arguments))}}((function(){for(delete g[e];t=n.shift();)t.apply(null,arguments)}));if(l){var r=new d;s(r,"abort",u),s(r,"error",u),s(r,"load",(function(){var e;try{e=JSON.parse(r.responseText)}catch(t){return void u(t)}u(200!==r.status,e)})),r.open("GET",e),r.send()}else{var a=this||window;a._=function(e){a._=null,u(200!==e.meta.status,e.data)};var i=o(a.document)("script",{async:!0,src:e+(/\?/.test(e)?"&":"?")+"callback=_"}),c=function(){a._&&a._({meta:{}})};s(i,"load",c),s(i,"error",c),i.readyState&&function(e,t,n){var u=function(r){if(t.test(e.readyState))return p(e,"readystatechange",u),n(r)};s(e,"readystatechange",u)}(i,/de|m/,c),a.document.getElementsByTagName("head")[0].appendChild(i)}}},E=function(e,t,n){var u=o(e.ownerDocument),r=e.appendChild(u("style",{type:"text/css"})),a="body{margin:0}a{text-decoration:none;outline:0}.widget{display:inline-block;overflow:hidden;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif;font-size:0;white-space:nowrap}.btn,.social-count{position:relative;display:inline-block;height:14px;padding:2px 5px;font-size:11px;font-weight:600;line-height:14px;vertical-align:bottom;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-repeat:repeat-x;background-position:-1px -1px;background-size:110% 110%;border:1px solid}.btn{border-radius:.25em}.btn:not(:last-child){border-radius:.25em 0 0 .25em}.social-count{border-left:0;border-radius:0 .25em .25em 0}.widget-lg .btn,.widget-lg .social-count{height:20px;padding:3px 10px;font-size:12px;line-height:20px}.octicon{display:inline-block;vertical-align:text-top;fill:currentColor}"+b(t["data-color-scheme"]);r.styleSheet?r.styleSheet.cssText=a:r.appendChild(e.ownerDocument.createTextNode(a));var d,i,l=u("a",{className:"btn",href:t.href,target:"_blank",rel:"noopener",innerHTML:(d=t["data-icon"],i=/^large$/i.test(t["data-size"])?16:14,d=(""+d).toLowerCase().replace(/^octicon-/,""),c(v,d)||(d="mark-github"),'"),"aria-label":t["aria-label"]||void 0},[" ",u("span",{},[t["data-text"]||""])]),f=e.appendChild(u("div",{className:"widget"+(/^large$/i.test(t["data-size"])?" widget-lg":"")},[l])),s=l.hostname.split(".").reverse();if(""===s[0]&&s.shift(),"com"!==s[0]||"github"!==s[1])return l.href="#",l.target="_self",void n(f);var p=s.length,m=(" /"+l.pathname).split(/\/+/);if(((2===p||3===p&&"gist"===s[2])&&"archive"===m[3]||2===p&&"releases"===m[3]&&"download"===m[4]||3===p&&"codeload"===s[2])&&(l.target="_top"),/^true$/i.test(t["data-show-count"])&&2===p){var h,g;if(!m[2]&&m[1])h=g="followers";else if(!m[3]&&m[2])g="stargazers_count",h="stargazers";else if(m[4]||"subscription"!==m[3])if(m[4]||"fork"!==m[3]){if("issues"!==m[3])return void n(f);g="open_issues_count",h="issues"}else g="forks_count",h="network/members";else g="subscribers_count",h="watchers";var _=m[2]?"/repos/"+m[1]+"/"+m[2]:"/users/"+m[1];y.call(this,"https://api.github.com"+_,(function(e,t){if(!e){var r=t[g];f.appendChild(u("a",{className:"social-count",href:t.html_url+"/"+h,target:"_blank",rel:"noopener","aria-label":r+" "+g.replace(/_count$/,"").replace("_"," ").slice(0,r<2?-1:void 0)+" on GitHub"},[(""+r).replace(/\B(?=(\d{3})+(?!\d))/g,",")]))}n(f)}))}else n(f)},w=window.devicePixelRatio||1,D=function(e){return(w>1?r.ceil(r.round(e*w)/w*2)/2:r.ceil(e))||0},k=function(e,t){e.style.width=t[0]+"px",e.style.height=t[1]+"px"},x=function(e,t){if(null!=e&&null!=t)if(e.getAttribute&&(e=function(e){for(var t={href:e.href,title:e.title,"aria-label":e.getAttribute("aria-label")},n=["icon","color-scheme","text","size","show-count"],u=0,r=n.length;u0){var n=t[0];return{x:n.clientX,y:n.clientY}}var u=e.pageX;if(void 0!==u)return{x:u,y:e.pageY}}return{x:0,y:0}}},524:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(427),d=n(420),o=n.n(d);n(147);t.a=function(e){var t=e.className,n=e.previous,u=e.next;return r.a.createElement("nav",{className:o()("pagination-nav",t)},r.a.createElement("div",{className:"pagination-nav__item"},n&&r.a.createElement(a.a,{className:"pagination-nav__link",to:n.permalink},r.a.createElement("h5",{className:"pagination-nav__link--sublabel"},"Previous"),r.a.createElement("h4",{className:"pagination-nav__link--label"},"\xab ",n.title))),r.a.createElement("div",{className:"pagination-nav__item pagination-nav__item--next"},u&&r.a.createElement(a.a,{className:"pagination-nav__link",to:u.permalink},r.a.createElement("h5",{className:"pagination-nav__link--sublabel"},"Next"),r.a.createElement("h4",{className:"pagination-nav__link--label"},u.title," \xbb"))))}},525:function(e,t,n){"use strict";var u=n(0);t.a=function(e,t,n){var r=Object(u.useState)(void 0),a=r[0],d=r[1];Object(u.useEffect)((function(){var u=[],r=[];function o(){var o=function(){var e=0,t=null;for(u=document.getElementsByClassName("anchor");e=0&&a<=n&&(t=r),e+=1}return t}();if(o){var i=0,c=!1;for(r=document.getElementsByClassName(e);i0&&void 0!==arguments[0]?arguments[0]:{};this.action=e.action,this.container=e.container,this.emitter=e.emitter,this.target=e.target,this.text=e.text,this.trigger=e.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function(){var e=this,t="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return e.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[t?"right":"left"]="-9999px";var n=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.style.top=n+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.container.appendChild(this.fakeElem),this.selectedText=r()(this.fakeElem),this.copyText()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=r()(this.target),this.copyText()}},{key:"copyText",value:function(){var e=void 0;try{e=document.execCommand(this.action)}catch(t){e=!1}this.handleResult(e)}},{key:"handleResult",value:function(e){this.emitter.emit(e?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),document.activeElement.blur(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=e,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(e){if(void 0!==e){if(!e||"object"!==(void 0===e?"undefined":a(e))||1!==e.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&e.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(e.hasAttribute("readonly")||e.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=e}},get:function(){return this._target}}]),e}(),i=n(1),c=n.n(i),l=n(2),f=n.n(l),s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},p=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof e.action?e.action:this.defaultAction,this.target="function"==typeof e.target?e.target:this.defaultTarget,this.text="function"==typeof e.text?e.text:this.defaultText,this.container="object"===s(e.container)?e.container:document.body}},{key:"listenClick",value:function(e){var t=this;this.listener=f()(e,"click",(function(e){return t.onClick(e)}))}},{key:"onClick",value:function(e){var t=e.delegateTarget||e.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new o({action:this.action(t),target:this.target(t),text:this.text(t),container:this.container,trigger:t,emitter:this})}},{key:"defaultAction",value:function(e){return h("action",e)}},{key:"defaultTarget",value:function(e){var t=h("target",e);if(t)return document.querySelector(t)}},{key:"defaultText",value:function(e){return h("text",e)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["copy","cut"],t="string"==typeof e?[e]:e,n=!!document.queryCommandSupported;return t.forEach((function(e){n=n&&!!document.queryCommandSupported(e)})),n}}]),t}(c.a);function h(e,t){var n="data-clipboard-"+e;if(t.hasAttribute(n))return t.getAttribute(n)}t.default=m}]).default},e.exports=u()},529:function(e,t){e.exports.parse=function(e){var t=e.split(",").map((function(e){return function(e){if(/^-?\d+$/.test(e))return parseInt(e,10);var t;if(t=e.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){var n=t[1],u=t[2],r=t[3];if(n&&r){var a=[],d=(n=parseInt(n))<(r=parseInt(r))?1:-1;"-"!=u&&".."!=u&&"\u2025"!=u||(r+=d);for(var o=n;o!=r;o+=d)a.push(o);return a}}return[]}(e)}));return 0===t.length?[]:1===t.length?Array.isArray(t[0])?t[0]:t:t.reduce((function(e,t){return Array.isArray(e)||(e=[e]),Array.isArray(t)||(t=[t]),e.concat(t)}))}},530:function(e,t){!function(e){function t(e){return RegExp("(^(?:"+e+"):[ \t]*(?![ \t]))[^]+","i")}e.languages.http={"request-line":{pattern:/^(?:CONNECT|DELETE|GET|HEAD|OPTIONS|PATCH|POST|PRI|PUT|SEARCH|TRACE)\s(?:https?:\/\/|\/)\S*\sHTTP\/[\d.]+/m,inside:{method:{pattern:/^[A-Z]+\b/,alias:"property"},"request-target":{pattern:/^(\s)(?:https?:\/\/|\/)\S*(?=\s)/,lookbehind:!0,alias:"url",inside:e.languages.uri},"http-version":{pattern:/^(\s)HTTP\/[\d.]+/,lookbehind:!0,alias:"property"}}},"response-status":{pattern:/^HTTP\/[\d.]+ \d+ .+/m,inside:{"http-version":{pattern:/^HTTP\/[\d.]+/,alias:"property"},"status-code":{pattern:/^(\s)\d+(?=\s)/,lookbehind:!0,alias:"number"},"reason-phrase":{pattern:/^(\s).+/,lookbehind:!0,alias:"string"}}},header:{pattern:/^[\w-]+:.+(?:(?:\r\n?|\n)[ \t].+)*/m,inside:{"header-value":[{pattern:t(/Content-Security-Policy/.source),lookbehind:!0,alias:["csp","languages-csp"],inside:e.languages.csp},{pattern:t(/Public-Key-Pins(?:-Report-Only)?/.source),lookbehind:!0,alias:["hpkp","languages-hpkp"],inside:e.languages.hpkp},{pattern:t(/Strict-Transport-Security/.source),lookbehind:!0,alias:["hsts","languages-hsts"],inside:e.languages.hsts},{pattern:t(/[^:]+/.source),lookbehind:!0}],"header-name":{pattern:/^[^:]+/,alias:"keyword"},punctuation:/^:/}}};var n,u=e.languages,r={"application/javascript":u.javascript,"application/json":u.json||u.javascript,"application/xml":u.xml,"text/xml":u.xml,"text/html":u.html,"text/css":u.css,"text/plain":u.plain},a={"application/json":!0,"application/xml":!0};function d(e){var t=e.replace(/^[a-z]+\//,"");return"(?:"+e+"|"+("\\w+/(?:[\\w.-]+\\+)+"+t+"(?![+\\w.-])")+")"}for(var o in r)if(r[o]){n=n||{};var i=a[o]?d(o):o;n[o.replace(/\//g,"-")]={pattern:RegExp("("+/content-type:\s*/.source+i+/(?:(?:\r\n?|\n)[\w-].*)*(?:\r(?:\n|(?!\n))|\n)/.source+")"+/[^ \t\w-][\s\S]*/.source,"i"),lookbehind:!0,inside:r[o]}}n&&e.languages.insertBefore("http","header",n)}(Prism)},531:function(e,t){Prism.languages.lua={comment:/^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,string:{pattern:/(["'])(?:(?!\1)[^\\\r\n]|\\z(?:\r\n|\s)|\\(?:\r\n|[^z]))*\1|\[(=*)\[[\s\S]*?\]\2\]/,greedy:!0},number:/\b0x[a-f\d]+(?:\.[a-f\d]*)?(?:p[+-]?\d+)?\b|\b\d+(?:\.\B|(?:\.\d*)?(?:e[+-]?\d+)?\b)|\B\.\d+(?:e[+-]?\d+)?\b/i,keyword:/\b(?:and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,function:/(?!\d)\w+(?=\s*(?:[({]))/,operator:[/[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,{pattern:/(^|[^.])\.\.(?!\.)/,lookbehind:!0}],punctuation:/[\[\](){},;]|\.+|:+/}},532:function(e,t){!function(e){var t=e.languages.powershell={comment:[{pattern:/(^|[^`])<#[\s\S]*?#>/,lookbehind:!0},{pattern:/(^|[^`])#.*/,lookbehind:!0}],string:[{pattern:/"(?:`[\s\S]|[^`"])*"/,greedy:!0,inside:null},{pattern:/'(?:[^']|'')*'/,greedy:!0}],namespace:/\[[a-z](?:\[(?:\[[^\]]*\]|[^\[\]])*\]|[^\[\]])*\]/i,boolean:/\$(?:false|true)\b/i,variable:/\$\w+\b/,function:[/\b(?:Add|Approve|Assert|Backup|Block|Checkpoint|Clear|Close|Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom|ConvertTo|Copy|Debug|Deny|Disable|Disconnect|Dismount|Edit|Enable|Enter|Exit|Expand|Export|Find|ForEach|Format|Get|Grant|Group|Hide|Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push|Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset|Resize|Resolve|Restart|Restore|Resume|Revoke|Save|Search|Select|Send|Set|Show|Skip|Sort|Split|Start|Step|Stop|Submit|Suspend|Switch|Sync|Tee|Test|Trace|Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish|Unregister|Update|Use|Wait|Watch|Where|Write)-[a-z]+\b/i,/\b(?:ac|cat|chdir|clc|cli|clp|clv|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|ebp|echo|epal|epcsv|epsn|erase|fc|fl|ft|fw|gal|gbp|gc|gci|gcs|gdr|gi|gl|gm|gp|gps|group|gsv|gu|gv|gwmi|iex|ii|ipal|ipcsv|ipsn|irm|iwmi|iwr|kill|lp|ls|measure|mi|mount|move|mp|mv|nal|ndr|ni|nv|ogv|popd|ps|pushd|pwd|rbp|rd|rdr|ren|ri|rm|rmdir|rni|rnp|rp|rv|rvpa|rwmi|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spps|spsv|start|sv|swmi|tee|trcm|type|write)\b/i],keyword:/\b(?:Begin|Break|Catch|Class|Continue|Data|Define|Do|DynamicParam|Else|ElseIf|End|Exit|Filter|Finally|For|ForEach|From|Function|If|InlineScript|Parallel|Param|Process|Return|Sequence|Switch|Throw|Trap|Try|Until|Using|Var|While|Workflow)\b/i,operator:{pattern:/(^|\W)(?:!|-(?:b?(?:and|x?or)|as|(?:Not)?(?:Contains|In|Like|Match)|eq|ge|gt|is(?:Not)?|Join|le|lt|ne|not|Replace|sh[lr])\b|-[-=]?|\+[+=]?|[*\/%]=?)/i,lookbehind:!0},punctuation:/[|{}[\];(),.]/};t.string[0].inside={function:{pattern:/(^|[^`])\$\((?:\$\([^\r\n()]*\)|(?!\$\()[^\r\n)])*\)/,lookbehind:!0,inside:t},boolean:t.boolean,variable:t.variable}}(Prism)},533:function(e,t){!function(e){var t=/\b(?:bool|bytes|double|s?fixed(?:32|64)|float|[su]?int(?:32|64)|string)\b/;e.languages.protobuf=e.languages.extend("clike",{"class-name":[{pattern:/(\b(?:enum|extend|message|service)\s+)[A-Za-z_]\w*(?=\s*\{)/,lookbehind:!0},{pattern:/(\b(?:rpc\s+\w+|returns)\s*\(\s*(?:stream\s+)?)\.?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*(?=\s*\))/,lookbehind:!0}],keyword:/\b(?:enum|extend|extensions|import|message|oneof|option|optional|package|public|repeated|required|reserved|returns|rpc(?=\s+\w)|service|stream|syntax|to)\b(?!\s*=\s*\d)/,function:/\b[a-z_]\w*(?=\s*\()/i}),e.languages.insertBefore("protobuf","operator",{map:{pattern:/\bmap<\s*[\w.]+\s*,\s*[\w.]+\s*>(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/[<>.,]/,builtin:t}},builtin:t,"positional-class-name":{pattern:/(?:\b|\B\.)[a-z_]\w*(?:\.[a-z_]\w*)*(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/\./}},annotation:{pattern:/(\[\s*)[a-z_]\w*(?=\s*=)/i,lookbehind:!0}})}(Prism)},534:function(e,t){!function(e){var t=/(?:[\w-]+|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*")/.source;function n(e){return e.replace(/__/g,(function(){return t}))}e.languages.toml={comment:{pattern:/#.*/,greedy:!0},table:{pattern:RegExp(n(/(^[\t ]*\[\s*(?:\[\s*)?)__(?:\s*\.\s*__)*(?=\s*\])/.source),"m"),lookbehind:!0,greedy:!0,alias:"class-name"},key:{pattern:RegExp(n(/(^[\t ]*|[{,]\s*)__(?:\s*\.\s*__)*(?=\s*=)/.source),"m"),lookbehind:!0,greedy:!0,alias:"property"},string:{pattern:/"""(?:\\[\s\S]|[^\\])*?"""|'''[\s\S]*?'''|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},date:[{pattern:/\b\d{4}-\d{2}-\d{2}(?:[T\s]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?\b/i,alias:"number"},{pattern:/\b\d{2}:\d{2}:\d{2}(?:\.\d+)?\b/,alias:"number"}],number:/(?:\b0(?:x[\da-zA-Z]+(?:_[\da-zA-Z]+)*|o[0-7]+(?:_[0-7]+)*|b[10]+(?:_[10]+)*))\b|[-+]?\b\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?\b|[-+]?\b(?:inf|nan)\b/,boolean:/\b(?:false|true)\b/,punctuation:/[.,=[\]{}]/}}(Prism)},535:function(e,t){!function(e){e.languages.kotlin=e.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,lookbehind:!0},function:[{pattern:/(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/,greedy:!0},{pattern:/(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/,lookbehind:!0,greedy:!0}],number:/\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete e.languages.kotlin["class-name"];var t={"interpolation-punctuation":{pattern:/^\$\{?|\}$/,alias:"punctuation"},expression:{pattern:/[\s\S]+/,inside:e.languages.kotlin}};e.languages.insertBefore("kotlin","string",{"string-literal":[{pattern:/"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/,alias:"multiline",inside:{interpolation:{pattern:/\$(?:[a-z_]\w*|\{[^{}]*\})/i,inside:t},string:/[\s\S]+/}},{pattern:/"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/,alias:"singleline",inside:{interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i,lookbehind:!0,inside:t},string:/[\s\S]+/}}],char:{pattern:/'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/,greedy:!0}}),delete e.languages.kotlin.string,e.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),e.languages.insertBefore("kotlin","function",{label:{pattern:/\b\w+@|@\w+\b/,alias:"symbol"}}),e.languages.kt=e.languages.kotlin,e.languages.kts=e.languages.kotlin}(Prism)},536:function(e,t){!function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,n=/(^|[^\w.])(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source,u={pattern:RegExp(n+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}};e.languages.java=e.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,lookbehind:!0,greedy:!0},"class-name":[u,{pattern:RegExp(n+/[A-Z]\w*(?=\s+\w+\s*[;,=()])/.source),lookbehind:!0,inside:u.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"},char:{pattern:/'(?:\\.|[^'\\\r\n]){1,6}'/,greedy:!0}}),e.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":u,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},namespace:{pattern:RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(//g,(function(){return t.source}))),lookbehind:!0,inside:{punctuation:/\./}}})}(Prism)},537:function(e,t){Prism.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},Prism.languages.python["string-interpolation"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python},538:function(e,t){!function(e){var t=/\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/,n=[{pattern:/\b(?:false|true)\b/i,alias:"boolean"},{pattern:/(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,greedy:!0,lookbehind:!0},{pattern:/(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,greedy:!0,lookbehind:!0},/\b(?:null)\b/i,/\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/],u=/\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i,r=/|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,a=/[{}\[\](),:;]/;e.languages.php={delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"},comment:t,variable:/\$+(?:\w+\b|(?=\{))/,package:{pattern:/(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,lookbehind:!0,inside:{punctuation:/\\/}},"class-name-definition":{pattern:/(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,lookbehind:!0,alias:"class-name"},"function-definition":{pattern:/(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,lookbehind:!0,alias:"function"},keyword:[{pattern:/(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i,alias:"type-casting",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string|void)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i,alias:"type-declaration",greedy:!0},{pattern:/(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i,alias:"type-declaration",greedy:!0,lookbehind:!0},{pattern:/\b(?:parent|self|static)(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(\byield\s+)from\b/i,lookbehind:!0},/\bclass\b/i,{pattern:/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|new|or|parent|print|private|protected|public|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i,lookbehind:!0}],"argument-name":{pattern:/([(,]\s+)\b[a-z_]\w*(?=\s*:(?!:))/i,lookbehind:!0},"class-name":[{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/(\|\s*)\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,greedy:!0},{pattern:/(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,alias:"class-name-fully-qualified",greedy:!0,inside:{punctuation:/\\/}},{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*\$)/i,alias:"type-declaration",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-declaration"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,alias:["class-name-fully-qualified","static-context"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-hint"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:["class-name-fully-qualified","return-type"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,function:{pattern:/(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,lookbehind:!0,inside:{punctuation:/\\/}},property:{pattern:/(->\s*)\w+/,lookbehind:!0},number:u,operator:r,punctuation:a};var d={pattern:/\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,lookbehind:!0,inside:e.languages.php},o=[{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,alias:"nowdoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:d}},{pattern:/`(?:\\[\s\S]|[^\\`])*`/,alias:"backtick-quoted-string",greedy:!0},{pattern:/'(?:\\[\s\S]|[^\\'])*'/,alias:"single-quoted-string",greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,alias:"double-quoted-string",greedy:!0,inside:{interpolation:d}}];e.languages.insertBefore("php","variable",{string:o,attribute:{pattern:/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,greedy:!0,inside:{"attribute-content":{pattern:/^(#\[)[\s\S]+(?=\]$)/,lookbehind:!0,inside:{comment:t,string:o,"attribute-class-name":[{pattern:/([^:]|^)\b[a-z_]\w*(?!\\)\b/i,alias:"class-name",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\?\b[a-z_]\w*)+/i,alias:["class-name","class-name-fully-qualified"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,number:u,operator:r,punctuation:a}},delimiter:{pattern:/^#\[|\]$/,alias:"punctuation"}}}}),e.hooks.add("before-tokenize",(function(t){if(/<\?/.test(t.code)){e.languages["markup-templating"].buildPlaceholders(t,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g)}})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"php")}))}(Prism)},539:function(e,t){!function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,u="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",r=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*/.source.replace(//g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),a=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function d(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<>/g,(function(){return u})).replace(/<>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<>/g,(function(){return u}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)<>(?=\s*:\s)/.source.replace(/<>/g,(function(){return u})).replace(/<>/g,(function(){return"(?:"+r+"|"+a+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:d(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:d(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:d(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:d(a),lookbehind:!0,greedy:!0},number:{pattern:d(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(Prism)},540:function(e,t){e.exports={plain:{color:"#bfc7d5",backgroundColor:"#292d3e"},styles:[{types:["comment"],style:{color:"rgb(105, 112, 152)",fontStyle:"italic"}},{types:["string"],style:{color:"rgb(195, 232, 141)"}},{types:["number"],style:{color:"rgb(247, 140, 108)"}},{types:["builtin","char","constant","function"],style:{color:"rgb(130, 170, 255)"}},{types:["punctuation","selector"],style:{color:"rgb(199, 146, 234)"}},{types:["variable"],style:{color:"rgb(191, 199, 213)"}},{types:["class-name","attr-name"],style:{color:"rgb(255, 203, 107)"}},{types:["tag"],style:{color:"rgb(255, 85, 114)"}},{types:["operator"],style:{color:"rgb(137, 221, 255)"}},{types:["boolean"],style:{color:"rgb(255, 88, 116)"}},{types:["keyword"],style:{fontStyle:"italic"}},{types:["doctype"],style:{color:"rgb(199, 146, 234)",fontStyle:"italic"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)"}},{types:["url"],style:{color:"rgb(221, 221, 221)"}}]}},541:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.canUseDOM=void 0;var u,r=n(562);var a=((u=r)&&u.__esModule?u:{default:u}).default,d=a.canUseDOM?window.HTMLElement:{};t.canUseDOM=a.canUseDOM;t.default=d},542:function(e,t,n){"use strict";var u=n(28),r=n(57);e.exports=function(e,t,n){t in e?u.f(e,t,r(0,n)):e[t]=n}},543:function(e,t,n){"use strict";var u=n(28).f,r=n(89),a=n(82),d=n(30),o=n(80),i=n(81),c=n(61),l=n(88),f=n(94),s=n(10),p=n(488).fastKey,m=n(489),h=s?"_s":"size",b=function(e,t){var n,u=p(t);if("F"!==u)return e._i[u];for(n=e._f;n;n=n.n)if(n.k==t)return n};e.exports={getConstructor:function(e,t,n,c){var l=e((function(e,u){o(e,l,t,"_i"),e._t=t,e._i=r(null),e._f=void 0,e._l=void 0,e[h]=0,null!=u&&i(u,n,e[c],e)}));return a(l.prototype,{clear:function(){for(var e=m(this,t),n=e._i,u=e._f;u;u=u.n)u.r=!0,u.p&&(u.p=u.p.n=void 0),delete n[u.i];e._f=e._l=void 0,e[h]=0},delete:function(e){var n=m(this,t),u=b(n,e);if(u){var r=u.n,a=u.p;delete n._i[u.i],u.r=!0,a&&(a.n=r),r&&(r.p=a),n._f==u&&(n._f=r),n._l==u&&(n._l=a),n[h]--}return!!u},forEach:function(e){m(this,t);for(var n,u=d(e,arguments.length>1?arguments[1]:void 0,3);n=n?n.n:this._f;)for(u(n.v,n.k,this);n&&n.r;)n=n.p},has:function(e){return!!b(m(this,t),e)}}),s&&u(l.prototype,"size",{get:function(){return m(this,t)[h]}}),l},def:function(e,t,n){var u,r,a=b(e,t);return a?a.v=n:(e._l=a={i:r=p(t,!0),k:t,v:n,p:u=e._l,n:void 0,r:!1},e._f||(e._f=a),u&&(u.n=a),e[h]++,"F"!==r&&(e._i[r]=a)),e},getEntry:b,setStrong:function(e,t,n){c(e,t,(function(e,n){this._t=m(e,t),this._k=n,this._l=void 0}),(function(){for(var e=this._k,t=this._l;t&&t.r;)t=t.p;return this._t&&(this._l=t=t?t.n:this._t._f)?l(0,"keys"==e?t.k:"values"==e?t.v:[t.k,t.v]):(this._t=void 0,l(1))}),n?"entries":"values",!n,!0),f(t)}}},544:function(e,t,n){"use strict";var u=n(5),r=n(12),a=n(16),d=n(82),o=n(488),i=n(81),c=n(80),l=n(13),f=n(14),s=n(83),p=n(41),m=n(545);e.exports=function(e,t,n,h,b,v){var g=u[e],y=g,_=b?"set":"add",E=y&&y.prototype,w={},D=function(e){var t=E[e];a(E,e,"delete"==e||"has"==e?function(e){return!(v&&!l(e))&&t.call(this,0===e?0:e)}:"get"==e?function(e){return v&&!l(e)?void 0:t.call(this,0===e?0:e)}:"add"==e?function(e){return t.call(this,0===e?0:e),this}:function(e,n){return t.call(this,0===e?0:e,n),this})};if("function"==typeof y&&(v||E.forEach&&!f((function(){(new y).entries().next()})))){var k=new y,x=k[_](v?{}:-0,1)!=k,S=f((function(){k.has(1)})),C=s((function(e){new y(e)})),O=!v&&f((function(){for(var e=new y,t=5;t--;)e[_](t,t);return!e.has(-0)}));C||((y=t((function(t,n){c(t,y,e);var u=m(new g,t,y);return null!=n&&i(n,b,u[_],u),u}))).prototype=E,E.constructor=y),(S||O)&&(D("delete"),D("has"),b&&D("get")),(O||x)&&D(_),v&&E.clear&&delete E.clear}else y=h.getConstructor(t,e,b,_),d(y.prototype,n),o.NEED=!0;return p(y,e),w[e]=y,r(r.G+r.W+r.F*(y!=g),w),v||h.setStrong(y,e,b),y}},545:function(e,t,n){var u=n(13),r=n(546).set;e.exports=function(e,t,n){var a,d=t.constructor;return d!==n&&"function"==typeof d&&(a=d.prototype)!==n.prototype&&u(a)&&r&&r(e,a),e}},546:function(e,t,n){var u=n(13),r=n(8),a=function(e,t){if(r(e),!u(t)&&null!==t)throw TypeError(t+": can't set as prototype!")};e.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(e,t,u){try{(u=n(30)(Function.call,n(547).f(Object.prototype,"__proto__").set,2))(e,[]),t=!(e instanceof Array)}catch(r){t=!0}return function(e,n){return a(e,n),t?e.__proto__=n:u(e,n),e}}({},!1):void 0),check:a}},547:function(e,t,n){var u=n(62),r=n(57),a=n(33),d=n(87),o=n(31),i=n(86),c=Object.getOwnPropertyDescriptor;t.f=n(10)?c:function(e,t){if(e=a(e),t=d(t,!0),i)try{return c(e,t)}catch(n){}if(o(e,t))return r(!u.f.call(e,t),e[t])}},548:function(e,t,n){"use strict";var u=n(12),r=n(32),a=n(27),d=n(14),o=[].sort,i=[1,2,3];u(u.P+u.F*(d((function(){i.sort(void 0)}))||!d((function(){i.sort(null)}))||!n(549)(o)),"Array",{sort:function(e){return void 0===e?o.call(a(this)):o.call(a(this),r(e))}})},549:function(e,t,n){"use strict";var u=n(14);e.exports=function(e,t){return!!e&&u((function(){t?e.call(null,(function(){}),1):e.call(null)}))}},558:function(e,t,n){"use strict";n(486),n(79),n(487),n(548),n(29),n(22),n(21),n(85),n(439);var u=n(1),r=(n(443),n(444),n(77),n(425),n(0)),a=n.n(r),d=n(478),o=n.n(d);n(150);var i=function(e){var t=e.humanize,n=e.icon,u=e.values,r=e.currentState,d=e.setState;if(0==u.size)return null;var i=Array.from(u);return a.a.createElement(a.a.Fragment,null,i.map((function(e,u){var i="string"==typeof e&&t?o()(e):e;return a.a.createElement("label",{key:u},a.a.createElement("input",{type:"checkbox",onChange:function(t){var n=new Set(r);t.currentTarget.checked?n.add(e):n.delete(e),d(n)},checked:r.has(e)}),i&&a.a.createElement(a.a.Fragment,null,n?a.a.createElement("i",{className:"feather icon-"+n}):""," ",i))})))},c=n(500),l=n(429),f=n(427),s=(n(437),n(448)),p=n.n(s),m=n(420),h=n.n(m),b=n(501),v=n.n(b),g=n(433);n(151);function y(e){var t=e.delivery_guarantee,n=e.description,u=e.event_types,r=e.function_category,d=(e.logo_path,e.name),o=e.pathTemplate,i=e.status,c=e.title,l=e.type,s=o;s||("source"==l&&(s="/docs/reference/sources//"),"transform"==l&&(s="/docs/reference/transforms//"),"sink"==l&&(s="/docs/reference/sinks//"));var p=s.replace("",d);return a.a.createElement(f.a,{to:p,className:"qovery-component",title:n},a.a.createElement("div",{className:"qovery-component--header"},a.a.createElement("div",{className:"qovery-component--name"},c)),a.a.createElement("div",{className:"qovery-component--badges"},"beta"==i?a.a.createElement("span",{className:"badge badge--warning",title:"This component is in beta and is not recommended for production environments"},a.a.createElement("i",{className:"feather icon-alert-triangle"})):a.a.createElement("span",{className:"badge badge--primary",title:"This component has passed reliability standards that make it production ready"},a.a.createElement("i",{className:"feather icon-award"})),"best_effort"==t?a.a.createElement("span",{className:"badge badge--warning",title:"This component makes a best-effort delivery guarantee, and in rare cases can lose data"},a.a.createElement("i",{className:"feather icon-shield-off"})):a.a.createElement("span",{className:"badge badge--primary",title:"This component offers an at-least-once delivery guarantee"},a.a.createElement("i",{className:"feather icon-shield"})),u.includes("log")?a.a.createElement("span",{className:"badge badge--primary",title:"This component works with log event types"},"log"):"",u.includes("metric")?a.a.createElement("span",{className:"badge badge--primary",title:"This component works with metric event types"},"metric"):"",a.a.createElement("span",{className:"badge badge--primary"},r)))}function _(e){var t=e.components,n=e.headingLevel,r=e.pathTemplate,d=e.titles,o=t.filter((function(e){return"source"==e.type})),i=t.filter((function(e){return"transform"==e.type})),f=t.filter((function(e){return"sink"==e.type})),s="h"+(n||3);return t.length>0?a.a.createElement(a.a.Fragment,null,o.length>0?a.a.createElement(a.a.Fragment,null,d&&a.a.createElement(s,null,o.length," Sources"),a.a.createElement("div",{className:"qovery-components--grid"},o.map((function(e,t){return a.a.createElement(y,Object(u.a)({key:t,pathTemplate:r},e))})))):"",i.length>0?a.a.createElement(a.a.Fragment,null,d&&a.a.createElement(s,null,i.length," Transforms"),a.a.createElement("div",{className:"qovery-components--grid"},i.map((function(e,t){return a.a.createElement(y,Object(u.a)({key:t,pathTemplate:r},e))})))):"",f.length>0?a.a.createElement(a.a.Fragment,null,d&&a.a.createElement(s,null,f.length," Sinks"),a.a.createElement("div",{className:"qovery-components--grid"},f.map((function(e,t){return a.a.createElement(y,Object(u.a)({key:t,pathTemplate:r},e))})))):"",a.a.createElement("hr",null),a.a.createElement(l.a,{to:"https://github.com/qovery/documentation/issues/new?labels=type%3A+new+feature",target:"_blank",rightIcon:"plus-circle"},"Request a new component")):a.a.createElement(c.a,{text:"no components found"})}t.a=function(e){var t=Object(g.a)().siteConfig.customFields.metadata,n=t.sources,u=t.transforms,d=t.sinks,o=e.titles||null==e.titles,c=1==e.filterColumn,l=e.pathTemplate,s=e.location?v.a.parse(e.location.search,{ignoreQueryPrefix:!0}):{},m=[];(e.sources||null==e.sources)&&(m=m.concat(Object.values(n))),(e.transforms||null==e.transforms)&&(m=m.concat(Object.values(u))),(e.sinks||null==e.sinks)&&(m=m.concat(Object.values(d))),m=m.sort((function(e,t){return e.name>t.name?1:-1}));var b=Object(r.useState)("true"==s["at-least-once"]),y=b[0],E=b[1],w=Object(r.useState)(new Set(s["event-types"]||e.eventTypes)),D=w[0],k=w[1],x=Object(r.useState)(new Set(s.functions)),S=x[0],C=x[1],O=Object(r.useState)(new Set(s["operating-systems"])),I=O[0],A=O[1],j=Object(r.useState)("true"==s["prod-ready"]),N=j[0],F=j[1],T=Object(r.useState)(new Set(s.providers)),P=T[0],M=T[1],R=Object(r.useState)(s.search),L=R[0],B=R[1];L&&(m=m.filter((function(e){return(e.name.toLowerCase()+" "+e.type.toLowerCase()).includes(L.toLowerCase())}))),y&&(m=m.filter((function(e){return"at_least_once"==e.delivery_guarantee}))),D.size>0&&(m=m.filter((function(e){return Array.from(D).some((function(t){return e.event_types.includes(t)}))}))),S.size>0&&(m=m.filter((function(e){return S.has(e.function_category)}))),I.size>0&&(m=m.filter((function(e){return Array.from(I).every((function(t){return e.operating_systems.includes(t)}))}))),N&&(m=m.filter((function(e){return"prod-ready"==e.status}))),P.size>0&&(m=m.filter((function(e){return Array.from(P).every((function(t){return e.service_providers&&e.service_providers.includes(t)}))}))),e.exceptNames&&e.exceptNames.length>0&&(m=m.filter((function(t){return!e.exceptNames.includes(t.name)}))),e.exceptFunctions&&e.exceptFunctions.length>0&&(m=m.filter((function(t){return!e.exceptFunctions.includes(t.function_category)})));var z=D.size>0?D:new Set(p()(m).map((function(e){return e.event_types})).flatten().uniq().compact().sort().value()),U=new Set(p()(m).map((function(e){return e.operating_systems})).flatten().uniq().compact().sort().value()),W=new Set(p()(m).map((function(e){return e.service_providers})).flatten().uniq().compact().sort().value()),H=new Set(p()(m).filter((function(e){return"source"==e.type})).map((function(e){return e.function_category})).uniq().compact().sort().value()),$=new Set(p()(m).filter((function(e){return"transform"==e.type})).map((function(e){return e.function_category})).uniq().compact().sort().value()),q=new Set(p()(m).filter((function(e){return"sink"==e.type})).map((function(e){return e.function_category})).uniq().compact().sort().value());return a.a.createElement("div",{className:h()("qovery-components",{"qovery-components--cols":c})},a.a.createElement("div",{className:"filters"},a.a.createElement("div",{className:"search"},a.a.createElement("input",{className:"input--text input--lg",type:"text",onChange:function(e){return B(e.currentTarget.value)},placeholder:"\ud83d\udd0d Search..."})),a.a.createElement("div",{className:"filter"},a.a.createElement("div",{className:"filter--label"},a.a.createElement(f.a,{to:"/docs/getting-started/data-model/",title:"Learn more about Qovery's event types"},"Event types ",a.a.createElement("i",{className:"feather icon-info"}))),a.a.createElement("div",{className:"filter--choices"},a.a.createElement(i,{label:"Event Types",icon:"database",values:z,humanize:!0,currentState:D,setState:k}))),a.a.createElement("div",{className:"filter"},a.a.createElement("div",{className:"filter--label"},a.a.createElement(f.a,{to:"/docs/getting-started/whats-next/",title:"Learn more about Qovery's guarantees"},"Guarantees ",a.a.createElement("i",{className:"feather icon-info"}))),a.a.createElement("div",{className:"filter--choices"},a.a.createElement("label",{title:"Show only components that offer an at-least-once delivery guarantee."},a.a.createElement("input",{type:"checkbox",onChange:function(e){return E(e.currentTarget.checked)},checked:y}),a.a.createElement("i",{className:"feather icon-shield"})," At-least-once"),a.a.createElement("label",{title:"Show only production ready components."},a.a.createElement("input",{type:"checkbox",onChange:function(e){return F(e.currentTarget.checked)},checked:N}),a.a.createElement("i",{className:"feather icon-award"})," Prod-ready"))),H.size>0&&a.a.createElement("div",{className:"filter"},a.a.createElement("div",{className:"filter--label"},"Source Functions"),a.a.createElement("div",{className:"filter--choices"},a.a.createElement(i,{label:"Functions",icon:"settings",values:H,humanize:!0,currentState:S,setState:C}))),$.size>0&&a.a.createElement("div",{className:"filter"},a.a.createElement("div",{className:"filter--label"},"Transform Functions"),a.a.createElement("div",{className:"filter--choices"},a.a.createElement(i,{label:"Functions",icon:"settings",values:$,humanize:!0,currentState:S,setState:C}))),q.size>0&&a.a.createElement("div",{className:"filter"},a.a.createElement("div",{className:"filter--label"},"Sink Functions"),a.a.createElement("div",{className:"filter--choices"},a.a.createElement(i,{label:"Functions",icon:"settings",values:q,humanize:!0,currentState:S,setState:C}))),W.size>0&&a.a.createElement("div",{className:"filter"},a.a.createElement("div",{className:"filter--label"},"Providers"),a.a.createElement("div",{className:"filter--choices"},a.a.createElement(i,{label:"Providers",icon:"cloud",values:W,currentState:P,setState:M}))),U.size>0&&a.a.createElement("div",{className:"filter"},a.a.createElement("div",{className:"filter--label"},a.a.createElement(f.a,{to:"/docs/setup/installation/operating-systems/",title:"Learn more about Qovery's operating systems"},"Operating Systems")),a.a.createElement("div",{className:"filter--choices"},a.a.createElement(i,{label:"Operating Systems",icon:"cpu",values:U,currentState:I,setState:A})))),a.a.createElement("div",{className:"qovery-components--results"},a.a.createElement(_,{components:m,headingLevel:e.headingLevel,pathTemplate:l,titles:o})))}},560:function(e,t,n){"use strict";n.d(t,"b",(function(){return d}));var u=n(53),r={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","at-rule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]},a=n(0),d={Prism:u.a,theme:r};function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(){return(i=Object.assign||function(e){for(var t=1;t0&&e[n-1]===t?e:e.concat(t)},s=function(e,t){var n=e.plain,u=Object.create(null),r=e.styles.reduce((function(e,n){var u=n.languages,r=n.style;return u&&!u.includes(t)||n.types.forEach((function(t){var n=i({},e[t],r);e[t]=n})),e}),u);return r.root=n,r.plain=i({},n,{backgroundColor:null}),r};function p(e,t){var n={};for(var u in e)Object.prototype.hasOwnProperty.call(e,u)&&-1===t.indexOf(u)&&(n[u]=e[u]);return n}var m=function(e){function t(){for(var t=this,n=[],u=arguments.length;u--;)n[u]=arguments[u];e.apply(this,n),o(this,"getThemeDict",(function(e){if(void 0!==t.themeDict&&e.theme===t.prevTheme&&e.language===t.prevLanguage)return t.themeDict;t.prevTheme=e.theme,t.prevLanguage=e.language;var n=e.theme?s(e.theme,e.language):void 0;return t.themeDict=n})),o(this,"getLineProps",(function(e){var n=e.key,u=e.className,r=e.style,a=i({},p(e,["key","className","style","line"]),{className:"token-line",style:void 0,key:void 0}),d=t.getThemeDict(t.props);return void 0!==d&&(a.style=d.plain),void 0!==r&&(a.style=void 0!==a.style?i({},a.style,r):r),void 0!==n&&(a.key=n),u&&(a.className+=" "+u),a})),o(this,"getStyleForToken",(function(e){var n=e.types,u=e.empty,r=n.length,a=t.getThemeDict(t.props);if(void 0!==a){if(1===r&&"plain"===n[0])return u?{display:"inline-block"}:void 0;if(1===r&&!u)return a[n[0]];var d=u?{display:"inline-block"}:{},o=n.map((function(e){return a[e]}));return Object.assign.apply(Object,[d].concat(o))}})),o(this,"getTokenProps",(function(e){var n=e.key,u=e.className,r=e.style,a=e.token,d=i({},p(e,["key","className","style","token"]),{className:"token "+a.types.join(" "),children:a.content,style:t.getStyleForToken(a),key:void 0});return void 0!==r&&(d.style=void 0!==d.style?i({},d.style,r):r),void 0!==n&&(d.key=n),u&&(d.className+=" "+u),d}))}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.render=function(){var e=this.props,t=e.Prism,n=e.language,u=e.code,r=e.children,a=this.getThemeDict(this.props),d=t.languages[n];return r({tokens:function(e){for(var t=[[]],n=[e],u=[0],r=[e.length],a=0,d=0,o=[],i=[o];d>-1;){for(;(a=u[d]++)0?p:["plain"],s=m):(p=f(p,m.type),m.alias&&(p=f(p,m.alias)),s=m.content),"string"==typeof s){var h=s.split(c),b=h.length;o.push({types:p,content:h[0]});for(var v=1;v=0)&&a(e,!n)}e.exports=t.default},565:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.assertNodeList=i,t.setElement=function(e){var t=e;if("string"==typeof t&&d.canUseDOM){var n=document.querySelectorAll(t);i(n,t),t="length"in n?n[0]:n}return o=t||o},t.validateElement=c,t.hide=function(e){c(e)&&(e||o).setAttribute("aria-hidden","true")},t.show=function(e){c(e)&&(e||o).removeAttribute("aria-hidden")},t.documentNotReadyOrSSRTesting=function(){o=null},t.resetForTesting=function(){o=null};var u,r=n(590),a=(u=r)&&u.__esModule?u:{default:u},d=n(541);var o=null;function i(e,t){if(!e||!e.length)throw new Error("react-modal: No elements were found for selector "+t+".")}function c(e){return!(!e&&!o)||((0,a.default)(!1,["react-modal: App element is not defined.","Please use `Modal.setAppElement(el)` or set `appElement={el}`.","This is needed so screen readers don't see main content","when modal is opened. It is not recommended, but you can opt-out","by setting `ariaHideApp={false}`."].join(" ")),!1)}},566:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u=new function e(){var t=this;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.register=function(e){-1===t.openInstances.indexOf(e)&&(t.openInstances.push(e),t.emit("register"))},this.deregister=function(e){var n=t.openInstances.indexOf(e);-1!==n&&(t.openInstances.splice(n,1),t.emit("deregister"))},this.subscribe=function(e){t.subscribers.push(e)},this.emit=function(e){t.subscribers.forEach((function(n){return n(e,t.openInstances.slice())}))},this.openInstances=[],this.subscribers=[]};t.default=u,e.exports=t.default},585:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u,r=n(586),a=(u=r)&&u.__esModule?u:{default:u};t.default=a.default,e.exports=t.default},586:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.bodyOpenClassName=t.portalClassName=void 0;var u=Object.assign||function(e){for(var t=1;t0&&0===(g-=1)&&f.show(t),n.props.shouldFocusAfterRender&&(n.props.shouldReturnFocusAfterClose?(c.returnFocus(),c.teardownScopedFocus()):c.popWithoutFocus()),n.props.onAfterClose&&n.props.onAfterClose(),m.default.deregister(n)},n.open=function(){n.beforeOpen(),n.state.afterOpen&&n.state.beforeClose?(clearTimeout(n.closeTimer),n.setState({beforeClose:!1})):(n.props.shouldFocusAfterRender&&(c.setupScopedFocus(n.node),c.markForFocusLater()),n.setState({isOpen:!0},(function(){n.setState({afterOpen:!0}),n.props.isOpen&&n.props.onAfterOpen&&n.props.onAfterOpen({overlayEl:n.overlay,contentEl:n.content})})))},n.close=function(){n.props.closeTimeoutMS>0?n.closeWithTimeout():n.closeWithoutTimeout()},n.focusContent=function(){return n.content&&!n.contentHasFocus()&&n.content.focus()},n.closeWithTimeout=function(){var e=Date.now()+n.props.closeTimeoutMS;n.setState({beforeClose:!0,closesAt:e},(function(){n.closeTimer=setTimeout(n.closeWithoutTimeout,n.state.closesAt-Date.now())}))},n.closeWithoutTimeout=function(){n.setState({beforeClose:!1,isOpen:!1,afterOpen:!1,closesAt:null},n.afterClose)},n.handleKeyDown=function(e){9===e.keyCode&&(0,l.default)(n.content,e),n.props.shouldCloseOnEsc&&27===e.keyCode&&(e.stopPropagation(),n.requestClose(e))},n.handleOverlayOnClick=function(e){null===n.shouldClose&&(n.shouldClose=!0),n.shouldClose&&n.props.shouldCloseOnOverlayClick&&(n.ownerHandlesClose()?n.requestClose(e):n.focusContent()),n.shouldClose=null},n.handleContentOnMouseUp=function(){n.shouldClose=!1},n.handleOverlayOnMouseDown=function(e){n.props.shouldCloseOnOverlayClick||e.target!=n.overlay||e.preventDefault()},n.handleContentOnClick=function(){n.shouldClose=!1},n.handleContentOnMouseDown=function(){n.shouldClose=!1},n.requestClose=function(e){return n.ownerHandlesClose()&&n.props.onRequestClose(e)},n.ownerHandlesClose=function(){return n.props.onRequestClose},n.shouldBeClosed=function(){return!n.state.isOpen&&!n.state.beforeClose},n.contentHasFocus=function(){return document.activeElement===n.content||n.content.contains(document.activeElement)},n.buildClassName=function(e,t){var u="object"===(void 0===t?"undefined":r(t))?t:{base:v[e],afterOpen:v[e]+"--after-open",beforeClose:v[e]+"--before-close"},a=u.base;return n.state.afterOpen&&(a=a+" "+u.afterOpen),n.state.beforeClose&&(a=a+" "+u.beforeClose),"string"==typeof t&&t?a+" "+t:a},n.attributesFromObject=function(e,t){return Object.keys(t).reduce((function(n,u){return n[e+"-"+u]=t[u],n}),{})},n.state={afterOpen:!1,beforeClose:!1},n.shouldClose=null,n.moveFromContentToOverlay=null,n}return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}(t,e),a(t,[{key:"componentDidMount",value:function(){this.props.isOpen&&this.open()}},{key:"componentDidUpdate",value:function(e,t){this.props.isOpen&&!e.isOpen?this.open():!this.props.isOpen&&e.isOpen&&this.close(),this.props.shouldFocusAfterRender&&this.state.isOpen&&!t.isOpen&&this.focusContent()}},{key:"componentWillUnmount",value:function(){this.state.isOpen&&this.afterClose(),clearTimeout(this.closeTimer)}},{key:"beforeOpen",value:function(){var e=this.props,t=e.appElement,n=e.ariaHideApp,u=e.htmlOpenClassName,r=e.bodyOpenClassName;r&&s.add(document.body,r),u&&s.add(document.getElementsByTagName("html")[0],u),n&&(g+=1,f.hide(t)),m.default.register(this)}},{key:"render",value:function(){var e=this.props,t=e.id,n=e.className,r=e.overlayClassName,a=e.defaultStyles,d=n?{}:a.content,i=r?{}:a.overlay;return this.shouldBeClosed()?null:o.default.createElement("div",{ref:this.setOverlayRef,className:this.buildClassName("overlay",r),style:u({},i,this.props.style.overlay),onClick:this.handleOverlayOnClick,onMouseDown:this.handleOverlayOnMouseDown},o.default.createElement("div",u({id:t,ref:this.setContentRef,style:u({},d,this.props.style.content),className:this.buildClassName("content",n),tabIndex:"-1",onKeyDown:this.handleKeyDown,onMouseDown:this.handleContentOnMouseDown,onMouseUp:this.handleContentOnMouseUp,onClick:this.handleContentOnClick,role:this.props.role,"aria-label":this.props.contentLabel},this.attributesFromObject("aria",this.props.aria||{}),this.attributesFromObject("data",this.props.data||{}),{"data-testid":this.props.testId}),this.props.children))}}]),t}(d.Component);y.defaultProps={style:{overlay:{},content:{}},defaultStyles:{}},y.propTypes={isOpen:i.default.bool.isRequired,defaultStyles:i.default.shape({content:i.default.object,overlay:i.default.object}),style:i.default.shape({content:i.default.object,overlay:i.default.object}),className:i.default.oneOfType([i.default.string,i.default.object]),overlayClassName:i.default.oneOfType([i.default.string,i.default.object]),bodyOpenClassName:i.default.string,htmlOpenClassName:i.default.string,ariaHideApp:i.default.bool,appElement:i.default.instanceOf(p.default),onAfterOpen:i.default.func,onAfterClose:i.default.func,onRequestClose:i.default.func,closeTimeoutMS:i.default.number,shouldFocusAfterRender:i.default.bool,shouldCloseOnOverlayClick:i.default.bool,shouldReturnFocusAfterClose:i.default.bool,role:i.default.string,contentLabel:i.default.string,aria:i.default.object,data:i.default.object,children:i.default.node,shouldCloseOnEsc:i.default.bool,overlayRef:i.default.func,contentRef:i.default.func,id:i.default.string,testId:i.default.string},t.default=y,e.exports=t.default},588:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.handleBlur=c,t.handleFocus=l,t.markForFocusLater=function(){d.push(document.activeElement)},t.returnFocus=function(){var e=null;try{return void(0!==d.length&&(e=d.pop()).focus())}catch(t){console.warn(["You tried to return focus to",e,"but it is not in the DOM anymore"].join(" "))}},t.popWithoutFocus=function(){d.length>0&&d.pop()},t.setupScopedFocus=function(e){o=e,window.addEventListener?(window.addEventListener("blur",c,!1),document.addEventListener("focus",l,!0)):(window.attachEvent("onBlur",c),document.attachEvent("onFocus",l))},t.teardownScopedFocus=function(){o=null,window.addEventListener?(window.removeEventListener("blur",c),document.removeEventListener("focus",l)):(window.detachEvent("onBlur",c),document.detachEvent("onFocus",l))};var u,r=n(564),a=(u=r)&&u.__esModule?u:{default:u};var d=[],o=null,i=!1;function c(){i=!0}function l(){if(i){if(i=!1,!o)return;setTimeout((function(){o.contains(document.activeElement)||((0,a.default)(o)[0]||o).focus()}),0)}}},589:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){var n=(0,a.default)(e);if(!n.length)return void t.preventDefault();var u=void 0,r=t.shiftKey,d=n[0],o=n[n.length-1];if(e===document.activeElement){if(!r)return;u=o}o!==document.activeElement||r||(u=d);d===document.activeElement&&r&&(u=o);if(u)return t.preventDefault(),void u.focus();var i=/(\bChrome\b|\bSafari\b)\//.exec(navigator.userAgent);if(null==i||"Chrome"==i[1]||null!=/\biPod\b|\biPad\b/g.exec(navigator.userAgent))return;var c=n.indexOf(document.activeElement);c>-1&&(c+=r?-1:1);if(void 0===(u=n[c]))return t.preventDefault(),void(u=r?o:d).focus();t.preventDefault(),u.focus()};var u,r=n(564),a=(u=r)&&u.__esModule?u:{default:u};e.exports=t.default},590:function(e,t,n){"use strict";var u=function(){};e.exports=u},591:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.dumpClassLists=function(){0};var u={},r={};t.add=function(e,t){return n=e.classList,a="html"==e.nodeName.toLowerCase()?u:r,void t.split(" ").forEach((function(e){!function(e,t){e[t]||(e[t]=0),e[t]+=1}(a,e),n.add(e)}));var n,a},t.remove=function(e,t){return n=e.classList,a="html"==e.nodeName.toLowerCase()?u:r,void t.split(" ").forEach((function(e){!function(e,t){e[t]&&(e[t]-=1)}(a,e),0===a[e]&&n.remove(e)}));var n,a}},592:function(e,t,n){"use strict";var u,r=n(566),a=(u=r)&&u.__esModule?u:{default:u};var d=void 0,o=void 0,i=[];function c(){0!==i.length&&i[i.length-1].focusContent()}a.default.subscribe((function(e,t){d&&o||((d=document.createElement("div")).setAttribute("data-react-modal-body-trap",""),d.style.position="absolute",d.style.opacity="0",d.setAttribute("tabindex","0"),d.addEventListener("focus",c),(o=d.cloneNode()).addEventListener("focus",c)),(i=t).length>0?(document.body.firstChild!==d&&document.body.insertBefore(d,document.body.firstChild),document.body.lastChild!==o&&document.body.appendChild(o)):(d.parentElement&&d.parentElement.removeChild(d),o.parentElement&&o.parentElement.removeChild(o))}))},593:function(e,t,n){"use strict";function u(){var e=this.constructor.getDerivedStateFromProps(this.props,this.state);null!=e&&this.setState(e)}function r(e){this.setState(function(t){var n=this.constructor.getDerivedStateFromProps(e,t);return null!=n?n:null}.bind(this))}function a(e,t){try{var n=this.props,u=this.state;this.props=e,this.state=t,this.__reactInternalSnapshotFlag=!0,this.__reactInternalSnapshot=this.getSnapshotBeforeUpdate(n,u)}finally{this.props=n,this.state=u}}function d(e){var t=e.prototype;if(!t||!t.isReactComponent)throw new Error("Can only polyfill class components");if("function"!=typeof e.getDerivedStateFromProps&&"function"!=typeof t.getSnapshotBeforeUpdate)return e;var n=null,d=null,o=null;if("function"==typeof t.componentWillMount?n="componentWillMount":"function"==typeof t.UNSAFE_componentWillMount&&(n="UNSAFE_componentWillMount"),"function"==typeof t.componentWillReceiveProps?d="componentWillReceiveProps":"function"==typeof t.UNSAFE_componentWillReceiveProps&&(d="UNSAFE_componentWillReceiveProps"),"function"==typeof t.componentWillUpdate?o="componentWillUpdate":"function"==typeof t.UNSAFE_componentWillUpdate&&(o="UNSAFE_componentWillUpdate"),null!==n||null!==d||null!==o){var i=e.displayName||e.name,c="function"==typeof e.getDerivedStateFromProps?"getDerivedStateFromProps()":"getSnapshotBeforeUpdate()";throw Error("Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n"+i+" uses "+c+" but also contains the following legacy lifecycles:"+(null!==n?"\n "+n:"")+(null!==d?"\n "+d:"")+(null!==o?"\n "+o:"")+"\n\nThe above lifecycles should be removed. Learn more about this warning here:\nhttps://fb.me/react-async-component-lifecycle-hooks")}if("function"==typeof e.getDerivedStateFromProps&&(t.componentWillMount=u,t.componentWillReceiveProps=r),"function"==typeof t.getSnapshotBeforeUpdate){if("function"!=typeof t.componentDidUpdate)throw new Error("Cannot polyfill getSnapshotBeforeUpdate() for components that do not define componentDidUpdate() on the prototype");t.componentWillUpdate=a;var l=t.componentDidUpdate;t.componentDidUpdate=function(e,t,n){var u=this.__reactInternalSnapshotFlag?this.__reactInternalSnapshot:n;l.call(this,e,t,u)}}return e}n.r(t),n.d(t,"polyfill",(function(){return d})),u.__suppressDeprecationWarning=!0,r.__suppressDeprecationWarning=!0,a.__suppressDeprecationWarning=!0},594:function(e,t,n){var u;!function(r){"use strict";var a,d,o,i=(a=/d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZWN]|"[^"]*"|'[^']*'/g,d=/\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,o=/[^-+\dA-Z]/g,function(e,t,n,u){if(1!==arguments.length||"string"!==s(e)||/\d/.test(e)||(t=e,e=void 0),(e=e||new Date)instanceof Date||(e=new Date(e)),isNaN(e))throw TypeError("Invalid date");var r=(t=String(i.masks[t]||t||i.masks.default)).slice(0,4);"UTC:"!==r&&"GMT:"!==r||(t=t.slice(4),n=!0,"GMT:"===r&&(u=!0));var p=n?"getUTC":"get",m=e[p+"Date"](),h=e[p+"Day"](),b=e[p+"Month"](),v=e[p+"FullYear"](),g=e[p+"Hours"](),y=e[p+"Minutes"](),_=e[p+"Seconds"](),E=e[p+"Milliseconds"](),w=n?0:e.getTimezoneOffset(),D=l(e),k=f(e),x={d:m,dd:c(m),ddd:i.i18n.dayNames[h],dddd:i.i18n.dayNames[h+7],m:b+1,mm:c(b+1),mmm:i.i18n.monthNames[b],mmmm:i.i18n.monthNames[b+12],yy:String(v).slice(2),yyyy:v,h:g%12||12,hh:c(g%12||12),H:g,HH:c(g),M:y,MM:c(y),s:_,ss:c(_),l:c(E,3),L:c(Math.round(E/10)),t:g<12?i.i18n.timeNames[0]:i.i18n.timeNames[1],tt:g<12?i.i18n.timeNames[2]:i.i18n.timeNames[3],T:g<12?i.i18n.timeNames[4]:i.i18n.timeNames[5],TT:g<12?i.i18n.timeNames[6]:i.i18n.timeNames[7],Z:u?"GMT":n?"UTC":(String(e).match(d)||[""]).pop().replace(o,""),o:(w>0?"-":"+")+c(100*Math.floor(Math.abs(w)/60)+Math.abs(w)%60,4),S:["th","st","nd","rd"][m%10>3?0:(m%100-m%10!=10)*m%10],W:D,N:k};return t.replace(a,(function(e){return e in x?x[e]:e.slice(1,e.length-1)}))});function c(e,t){for(e=String(e),t=t||2;e.length/":G?V="/guides/integrate/sources/"+G.name+"//":H&&(V="/guides/integrate/sinks//");var K=H?"/guides/integrate/sources//"+H.name+"/":"/guides/integrate/sources//",Z=Object(u.useState)(!1),J=Z[0],Y=Z[1],Q=Object(u.useState)(!1),X=Q[0],ee=Q[1];return Object(O.a)("contents__link","contents__link--active",100),r.a.createElement(l.a,{title:v,description:v+", in minutes, for free"},J&&r.a.createElement(p.a,{className:"modal",onRequestClose:function(){return Y(!1)},overlayClassName:"modal-overlay",isOpen:null!==J,contentLabel:"Minimal Modal Example"},r.a.createElement("header",null,r.a.createElement("h1",null,"Where do you receive your data from?")),r.a.createElement(_.a,{exceptFunctions:["test"],exceptNames:[G&&G.name,"docker","qovery"],eventTypes:H&&H.event_types,pathTemplate:K,titles:!1,sources:!0,transforms:!1,sinks:!1})),X&&r.a.createElement(p.a,{className:"modal",onRequestClose:function(){return ee(!1)},overlayClassName:"modal-overlay",isOpen:null!==X,contentLabel:"Minimal Modal Example"},r.a.createElement("header",null,r.a.createElement("h1",null,"Where do you want to send your data?")),r.a.createElement(_.a,{exceptFunctions:["test"],exceptNames:[H&&H.name,"qovery"],eventTypes:G&&G.event_types,pathTemplate:V,titles:!1,sources:!1,transforms:!1,sinks:!0})),r.a.createElement("header",{className:"hero domain-bg domain-bg--"+M},r.a.createElement("div",{className:"container"},(z||G||H)&&r.a.createElement("div",{className:"component-icons"},z&&r.a.createElement("div",{className:"icon panel"},z.logo_path?r.a.createElement(g.a,{src:z.logo_path,alt:z.title+" Logo"}):r.a.createElement("i",{className:"feather icon-server"})),G&&!z&&r.a.createElement("div",{className:"icon panel link",title:"Change your source",onClick:function(e){return Y(!0)}},G.logo_path?r.a.createElement(g.a,{src:G.logo_path,alt:G.title+" Logo"}):r.a.createElement("i",{className:"feather icon-server"})),!G&&!z&&r.a.createElement("div",{className:"icon panel link",title:"Select a source",onClick:function(e){return Y(!0)}},r.a.createElement("i",{className:"feather icon-plus"})),H&&r.a.createElement("div",{className:"icon panel link",title:"Change your destination",onClick:function(e){return ee(!0)}},H.logo_path?r.a.createElement(g.a,{src:H.logo_path,alt:H.title+" Logo"}):r.a.createElement("i",{className:"feather icon-database"})),!H&&r.a.createElement("div",{className:"icon panel link",title:"Select a destination",onClick:function(e){return ee(!0)}},r.a.createElement("i",{className:"feather icon-plus"}))),!z&&!G&&!H&&r.a.createElement("div",{className:"hero--category"},r.a.createElement(f.a,{to:E[0].permalink+"/"},E[0].name)),r.a.createElement("h1",{className:C.a.header},v),r.a.createElement("div",{className:"hero--subtitle"},n.description),r.a.createElement(y.a,{colorProfile:"guides",tags:D}))),r.a.createElement("main",{className:d()("container","container--l",C.a.container)},r.a.createElement("aside",{className:C.a.sidebar},r.a.createElement("section",{className:C.a.avatar},r.a.createElement(i,{bio:!0,github:c,size:"lg",rel:"author",subTitle:!1,vertical:!0})),r.a.createElement("section",{className:d()("table-of-contents",C.a.tableOfContents)},r.a.createElement("div",{className:"section"},r.a.createElement("div",{className:"title"},"Stats"),r.a.createElement("div",{className:"text--secondary text--bold"},r.a.createElement("i",{className:"feather icon-book"})," ",w),r.a.createElement("div",{className:"text--secondary text--bold"},r.a.createElement("i",{className:"feather icon-clock"})," Updated ",r.a.createElement("time",{pubdate:"pubdate",dateTime:s},k()(R,"mmm dS, yyyy")))),t.rightToc.length>0&&r.a.createElement("div",{className:"section"},r.a.createElement("div",{className:"title"},"Contents"),r.a.createElement(I,{headings:t.rightToc})))),r.a.createElement("div",{className:C.a.article},r.a.createElement("article",null,r.a.createElement("div",{className:"markdown"},r.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"anchor",id:"overview"}),r.a.createElement(h.a,{components:m.a},r.a.createElement(t,null)))),!n.hide_pagination&&r.a.createElement(b.a,{previous:a.prevItem,next:a.nextItem,className:C.a.paginator}))))}},424:function(e,t,n){"use strict";n(426);var u=n(0),r=n.n(u),a=n(423),d=n.n(a);n(132);t.a=function(e){var t=e.children,n=e.classNames,u=e.fill,a=e.icon,o=e.type,i=null;switch(o){case"danger":i="alert-triangle";break;case"success":i="check-circle";break;case"warning":i="alert-triangle";break;default:i="info"}return r.a.createElement("div",{className:d()(n,"alert","alert--"+o,{"alert--fill":u,"alert--icon":!1!==a}),role:"alert"},!1!==a&&r.a.createElement("i",{className:d()("feather","icon-"+(a||i))}),t)}},428:function(e,t,n){var u=n(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||n(10)&&u(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},431:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(430),d=n(423),o=n.n(d);n(133);t.a=function(e){var t=e.children,n=e.className,u=e.badge,d=e.leftIcon,i=e.rightIcon,c=e.size,l=e.target,f=e.to,s=o()("jump-to","jump-to--"+c,n),p=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},d&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+d})),r.a.createElement("div",{className:"jump-to--main"},u?r.a.createElement("span",{className:"badge badge--primary badge--right"},u):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(i||"chevron-right")+" arrow"}))));return l?r.a.createElement("a",{href:f,target:l,className:s},p):r.a.createElement(a.a,{to:f,className:s},p)}},437:function(e,t,n){"use strict";var u=n(1),r=(n(442),n(439),n(52),n(29),n(22),n(21),n(0)),a=n.n(r),d=n(449),o=n(423),i=n.n(o),c=n(433),l=n.n(c),f=n(448),s=37,p=39;function m(e){var t=e.block,n=e.centered,u=e.changeSelectedValue,r=e.className,d=e.handleKeydown,o=e.style,c=e.values,l=e.selectedValue,f=e.tabRefs;return a.a.createElement("div",{className:n?"tabs--centered":null},a.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:i()("tabs",r,{"tabs--block":t}),style:o},c.map((function(e){var t=e.value,n=e.label;return a.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":l===t,className:i()("tab-item",{"tab-item--active":l===t}),key:t,ref:function(e){return f.push(e)},onKeyDown:function(e){return d(f,e.target,e)},onFocus:function(){return u(t)},onClick:function(){return u(t)}},n)}))))}function h(e){var t=e.placeholder,n=e.selectedValue,u=e.changeSelectedValue,r=e.size,o=e.values,i=o;if(i[0].group){var c=_.groupBy(i,"group");i=Object.keys(c).map((function(e){return{label:e,options:c[e]}}))}return a.a.createElement(d.a,{className:"react-select-container react-select--"+r,classNamePrefix:"react-select",options:i,isClearable:n,placeholder:t,value:o.find((function(e){return e.value==n})),onChange:function(e){return u(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,d=e.groupId,o=e.label,i=e.placeholder,c=e.select,b=e.size,v=(e.style,e.values),g=e.urlKey,y=Object(f.a)(),_=y.tabGroupChoices,E=y.setTabGroupChoices,w=Object(r.useState)(n),D=w[0],k=w[1];if(null!=d){var x=_[d];null!=x&&x!==D&&k(x)}var S=function(e){k(e),null!=d&&E(d,e)},C=[],O=function(e,t,n){switch(n.keyCode){case p:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case s:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(r.useEffect)((function(){if("undefined"!=typeof window&&window.location&&g){var e=l.a.parse(window.location.search);e[g]&&k(e[g])}}),[]),a.a.createElement(a.a.Fragment,null,a.a.createElement("div",{className:"margin-bottom--"+(b||"md")},o&&a.a.createElement("div",{className:"margin-vert--sm"},o),v.length>1&&(c?a.a.createElement(h,Object(u.a)({changeSelectedValue:S,handleKeydown:O,placeholder:i,selectedValue:D,size:b,tabRefs:C},e)):a.a.createElement(m,Object(u.a)({changeSelectedValue:S,handleKeydown:O,selectedValue:D,tabRefs:C},e)))),r.Children.toArray(t).filter((function(e){return e.props.value===D}))[0])}},441:function(e,t,n){"use strict";var u=n(0),r=n(485);t.a=function(){return Object(u.useContext)(r.a)}},444:function(e,t,n){"use strict";var u=n(0),r=n.n(u);t.a=function(e){return r.a.createElement(r.a.Fragment,null,e.children)}},445:function(e,t,n){"use strict";n(457);var u=n(0),r=n.n(u),a=n(458),d=n(443),o=n(1),i=(n(446),n(447),n(459),n(430)),c=n(460),l=n(440),f=n.n(l),s=n(461),p=n.n(s),m=n(436),h=n(423),b=n.n(h),v=n(135),g=n.n(v),y=function(){return r.a.createElement("span",{className:b()(g.a.toggle,g.a.moon)})},_=function(){return r.a.createElement("span",{className:b()(g.a.toggle,g.a.sun)})},E=function(e){var t=Object(m.a)().isClient;return r.a.createElement(p.a,Object(o.a)({disabled:!t,icons:{checked:r.a.createElement(y,null),unchecked:r.a.createElement(_,null)}},e))};function w(){var e=Object(m.a)().siteConfig,t=(void 0===e?{}:e).customFields.metadata.latest_post,n=Date.parse(t.date),u=new Date,r=Math.abs(u-n),a=Math.ceil(r/864e5),d=null;return"undefined"!=typeof window&&(d=new Date(parseInt(window.localStorage.getItem("blogViewedAt")||"0"))),a<30&&(!d||d0&&r.a.createElement("div",{className:"row footer__links"},r.a.createElement("div",{className:"col col--5 footer__col"},r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement(f.a,{className:"navbar__logo",src:p,alt:"Qovery",width:"150",height:"auto"})),r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),r.a.createElement("div",null,r.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},r.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},r.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},r.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},r.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),i.map((function(e,t){return r.a.createElement("div",{key:t,className:"col footer__col"},null!=e.title?r.a.createElement("h4",{className:"footer__title"},e.title):null,null!=e.items&&Array.isArray(e.items)&&e.items.length>0?r.a.createElement("ul",{className:"footer__items"},e.items.map((function(e,t){return e.html?r.a.createElement("li",{key:t,className:"footer__item",dangerouslySetInnerHTML:{__html:e.html}}):r.a.createElement("li",{key:e.href||e.to,className:"footer__item"},r.a.createElement(M,e))}))):null)}))),(l||d)&&r.a.createElement("div",{className:"text--center"},l&&l.src&&r.a.createElement("div",{className:"margin-bottom--sm"},l.href?r.a.createElement("a",{href:l.href,target:"_blank",rel:"noopener noreferrer",className:P.a.footerLogoLink},r.a.createElement(R,{alt:l.alt,url:s})):r.a.createElement(R,{alt:l.alt,url:s})),r.a.createElement("small",null,d),r.a.createElement("br",null))))},B=n(462),z=n(463),U=n(3);n(138);t.a=function(e){var t=Object(m.a)().siteConfig,n=void 0===t?{}:t,u=n.favicon,o=(n.tagline,n.title),i=n.themeConfig.image,c=n.url,l=e.children,f=e.title,s=e.noFooter,p=e.description,h=e.image,b=e.keywords,v=(e.permalink,e.version),g=f?f+" | "+o:o,y=h||i,_=c+Object(k.a)(y),E=Object(k.a)(u),w=Object(U.h)(),D=w?"https://docs.qovery.com"+(w.pathname.endsWith("/")?w.pathname:w.pathname+"/"):null;return r.a.createElement(z.a,null,r.a.createElement(B.a,null,r.a.createElement(d.a,null,r.a.createElement("html",{lang:"en"}),r.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),g&&r.a.createElement("title",null,g),g&&r.a.createElement("meta",{property:"og:title",content:g}),u&&r.a.createElement("link",{rel:"shortcut icon",href:E}),p&&r.a.createElement("meta",{name:"description",content:p}),p&&r.a.createElement("meta",{property:"og:description",content:p}),v&&r.a.createElement("meta",{name:"docsearch:version",content:v}),b&&b.length&&r.a.createElement("meta",{name:"keywords",content:b.join(",")}),y&&r.a.createElement("meta",{property:"og:image",content:_}),y&&r.a.createElement("meta",{property:"twitter:image",content:_}),y&&r.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+g}),D&&r.a.createElement("meta",{property:"og:url",content:D}),r.a.createElement("meta",{name:"twitter:card",content:"summary"}),D&&r.a.createElement("link",{rel:"canonical",href:D})),r.a.createElement(a.a,null),r.a.createElement(N,null),r.a.createElement("div",{className:"main-wrapper"},l),!s&&r.a.createElement(L,null)))}},450:function(e,t,n){"use strict";var u=n(9),r=n(0),a=n.n(r),d=n(423),o=n.n(d),i=n(436),c=(n(139),n(140)),l=n.n(c);t.a=function(e){return function(t){var n,r=t.id,d=Object(u.a)(t,["id"]),c=Object(i.a)().siteConfig,f=(c=void 0===c?{}:c).themeConfig,s=(f=void 0===f?{}:f).navbar,p=(s=void 0===s?{}:s).hideOnScroll,m=void 0!==p&&p;return r?a.a.createElement(e,d,a.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:o()("anchor",(n={},n[l.a.enhancedAnchor]=!m,n)),id:r}),a.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+r,title:"Direct link to heading"},"#"),d.children):a.a.createElement(e,d)}}},451:function(e,t,n){(function(e,u){var r;(function(){var a="Expected a function",d="__lodash_placeholder__",o=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],i="[object Arguments]",c="[object Array]",l="[object Boolean]",f="[object Date]",s="[object Error]",p="[object Function]",m="[object GeneratorFunction]",h="[object Map]",b="[object Number]",v="[object Object]",g="[object RegExp]",y="[object Set]",_="[object String]",E="[object Symbol]",w="[object WeakMap]",D="[object ArrayBuffer]",k="[object DataView]",x="[object Float32Array]",S="[object Float64Array]",C="[object Int8Array]",O="[object Int16Array]",I="[object Int32Array]",A="[object Uint8Array]",j="[object Uint16Array]",N="[object Uint32Array]",F=/\b__p \+= '';/g,T=/\b(__p \+=) '' \+/g,P=/(__e\(.*?\)|\b__t\)) \+\n'';/g,M=/&(?:amp|lt|gt|quot|#39);/g,R=/[&<>"']/g,L=RegExp(M.source),B=RegExp(R.source),z=/<%-([\s\S]+?)%>/g,U=/<%([\s\S]+?)%>/g,W=/<%=([\s\S]+?)%>/g,H=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,$=/^\w*$/,q=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,G=/[\\^$.*+?()[\]{}|]/g,V=RegExp(G.source),K=/^\s+|\s+$/g,Z=/^\s+/,J=/\s+$/,Y=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Q=/\{\n\/\* \[wrapped with (.+)\] \*/,X=/,? & /,ee=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,te=/\\(\\)?/g,ne=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,ue=/\w*$/,re=/^[-+]0x[0-9a-f]+$/i,ae=/^0b[01]+$/i,de=/^\[object .+?Constructor\]$/,oe=/^0o[0-7]+$/i,ie=/^(?:0|[1-9]\d*)$/,ce=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,le=/($^)/,fe=/['\n\r\u2028\u2029\\]/g,se="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",pe="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",me="[\\ud800-\\udfff]",he="["+pe+"]",be="["+se+"]",ve="\\d+",ge="[\\u2700-\\u27bf]",ye="[a-z\\xdf-\\xf6\\xf8-\\xff]",_e="[^\\ud800-\\udfff"+pe+ve+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",Ee="\\ud83c[\\udffb-\\udfff]",we="[^\\ud800-\\udfff]",De="(?:\\ud83c[\\udde6-\\uddff]){2}",ke="[\\ud800-\\udbff][\\udc00-\\udfff]",xe="[A-Z\\xc0-\\xd6\\xd8-\\xde]",Se="(?:"+ye+"|"+_e+")",Ce="(?:"+xe+"|"+_e+")",Oe="(?:"+be+"|"+Ee+")"+"?",Ie="[\\ufe0e\\ufe0f]?"+Oe+("(?:\\u200d(?:"+[we,De,ke].join("|")+")[\\ufe0e\\ufe0f]?"+Oe+")*"),Ae="(?:"+[ge,De,ke].join("|")+")"+Ie,je="(?:"+[we+be+"?",be,De,ke,me].join("|")+")",Ne=RegExp("['\u2019]","g"),Fe=RegExp(be,"g"),Te=RegExp(Ee+"(?="+Ee+")|"+je+Ie,"g"),Pe=RegExp([xe+"?"+ye+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?="+[he,xe,"$"].join("|")+")",Ce+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?="+[he,xe+Se,"$"].join("|")+")",xe+"?"+Se+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?",xe+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",ve,Ae].join("|"),"g"),Me=RegExp("[\\u200d\\ud800-\\udfff"+se+"\\ufe0e\\ufe0f]"),Re=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Le=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Be=-1,ze={};ze[x]=ze[S]=ze[C]=ze[O]=ze[I]=ze[A]=ze["[object Uint8ClampedArray]"]=ze[j]=ze[N]=!0,ze[i]=ze[c]=ze[D]=ze[l]=ze[k]=ze[f]=ze[s]=ze[p]=ze[h]=ze[b]=ze[v]=ze[g]=ze[y]=ze[_]=ze[w]=!1;var Ue={};Ue[i]=Ue[c]=Ue[D]=Ue[k]=Ue[l]=Ue[f]=Ue[x]=Ue[S]=Ue[C]=Ue[O]=Ue[I]=Ue[h]=Ue[b]=Ue[v]=Ue[g]=Ue[y]=Ue[_]=Ue[E]=Ue[A]=Ue["[object Uint8ClampedArray]"]=Ue[j]=Ue[N]=!0,Ue[s]=Ue[p]=Ue[w]=!1;var We={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},He=parseFloat,$e=parseInt,qe="object"==typeof e&&e&&e.Object===Object&&e,Ge="object"==typeof self&&self&&self.Object===Object&&self,Ve=qe||Ge||Function("return this")(),Ke=t&&!t.nodeType&&t,Ze=Ke&&"object"==typeof u&&u&&!u.nodeType&&u,Je=Ze&&Ze.exports===Ke,Ye=Je&&qe.process,Qe=function(){try{var e=Ze&&Ze.require&&Ze.require("util").types;return e||Ye&&Ye.binding&&Ye.binding("util")}catch(t){}}(),Xe=Qe&&Qe.isArrayBuffer,et=Qe&&Qe.isDate,tt=Qe&&Qe.isMap,nt=Qe&&Qe.isRegExp,ut=Qe&&Qe.isSet,rt=Qe&&Qe.isTypedArray;function at(e,t,n){switch(n.length){case 0:return e.call(t);case 1:return e.call(t,n[0]);case 2:return e.call(t,n[0],n[1]);case 3:return e.call(t,n[0],n[1],n[2])}return e.apply(t,n)}function dt(e,t,n,u){for(var r=-1,a=null==e?0:e.length;++r-1}function st(e,t,n){for(var u=-1,r=null==e?0:e.length;++u-1;);return n}function Tt(e,t){for(var n=e.length;n--&&Et(t,e[n],0)>-1;);return n}function Pt(e,t){for(var n=e.length,u=0;n--;)e[n]===t&&++u;return u}var Mt=St({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),Rt=St({"&":"&","<":"<",">":">",'"':""","'":"'"});function Lt(e){return"\\"+We[e]}function Bt(e){return Me.test(e)}function zt(e){var t=-1,n=Array(e.size);return e.forEach((function(e,u){n[++t]=[u,e]})),n}function Ut(e,t){return function(n){return e(t(n))}}function Wt(e,t){for(var n=-1,u=e.length,r=0,a=[];++n",""":'"',"'":"'"});var Kt=function e(t){var n,u=(t=null==t?Ve:Kt.defaults(Ve.Object(),t,Kt.pick(Ve,Le))).Array,r=t.Date,se=t.Error,pe=t.Function,me=t.Math,he=t.Object,be=t.RegExp,ve=t.String,ge=t.TypeError,ye=u.prototype,_e=pe.prototype,Ee=he.prototype,we=t["__core-js_shared__"],De=_e.toString,ke=Ee.hasOwnProperty,xe=0,Se=(n=/[^.]+$/.exec(we&&we.keys&&we.keys.IE_PROTO||""))?"Symbol(src)_1."+n:"",Ce=Ee.toString,Oe=De.call(he),Ie=Ve._,Ae=be("^"+De.call(ke).replace(G,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),je=Je?t.Buffer:void 0,Te=t.Symbol,Me=t.Uint8Array,We=je?je.allocUnsafe:void 0,qe=Ut(he.getPrototypeOf,he),Ge=he.create,Ke=Ee.propertyIsEnumerable,Ze=ye.splice,Ye=Te?Te.isConcatSpreadable:void 0,Qe=Te?Te.iterator:void 0,gt=Te?Te.toStringTag:void 0,St=function(){try{var e=Xr(he,"defineProperty");return e({},"",{}),e}catch(t){}}(),Zt=t.clearTimeout!==Ve.clearTimeout&&t.clearTimeout,Jt=r&&r.now!==Ve.Date.now&&r.now,Yt=t.setTimeout!==Ve.setTimeout&&t.setTimeout,Qt=me.ceil,Xt=me.floor,en=he.getOwnPropertySymbols,tn=je?je.isBuffer:void 0,nn=t.isFinite,un=ye.join,rn=Ut(he.keys,he),an=me.max,dn=me.min,on=r.now,cn=t.parseInt,ln=me.random,fn=ye.reverse,sn=Xr(t,"DataView"),pn=Xr(t,"Map"),mn=Xr(t,"Promise"),hn=Xr(t,"Set"),bn=Xr(t,"WeakMap"),vn=Xr(he,"create"),gn=bn&&new bn,yn={},_n=Sa(sn),En=Sa(pn),wn=Sa(mn),Dn=Sa(hn),kn=Sa(bn),xn=Te?Te.prototype:void 0,Sn=xn?xn.valueOf:void 0,Cn=xn?xn.toString:void 0;function On(e){if(Hd(e)&&!Nd(e)&&!(e instanceof Nn)){if(e instanceof jn)return e;if(ke.call(e,"__wrapped__"))return Ca(e)}return new jn(e)}var In=function(){function e(){}return function(t){if(!Wd(t))return{};if(Ge)return Ge(t);e.prototype=t;var n=new e;return e.prototype=void 0,n}}();function An(){}function jn(e,t){this.__wrapped__=e,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=void 0}function Nn(e){this.__wrapped__=e,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Fn(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t=t?e:t)),e}function Jn(e,t,n,u,r,a){var d,o=1&t,c=2&t,s=4&t;if(n&&(d=r?n(e,u,r,a):n(e)),void 0!==d)return d;if(!Wd(e))return e;var w=Nd(e);if(w){if(d=function(e){var t=e.length,n=new e.constructor(t);t&&"string"==typeof e[0]&&ke.call(e,"index")&&(n.index=e.index,n.input=e.input);return n}(e),!o)return vr(e,d)}else{var F=na(e),T=F==p||F==m;if(Md(e))return fr(e,o);if(F==v||F==i||T&&!r){if(d=c||T?{}:ra(e),!o)return c?function(e,t){return gr(e,ta(e),t)}(e,function(e,t){return e&&gr(t,Eo(t),e)}(d,e)):function(e,t){return gr(e,ea(e),t)}(e,Gn(d,e))}else{if(!Ue[F])return r?e:{};d=function(e,t,n){var u=e.constructor;switch(t){case D:return sr(e);case l:case f:return new u(+e);case k:return function(e,t){var n=t?sr(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.byteLength)}(e,n);case x:case S:case C:case O:case I:case A:case"[object Uint8ClampedArray]":case j:case N:return pr(e,n);case h:return new u;case b:case _:return new u(e);case g:return function(e){var t=new e.constructor(e.source,ue.exec(e));return t.lastIndex=e.lastIndex,t}(e);case y:return new u;case E:return r=e,Sn?he(Sn.call(r)):{}}var r}(e,F,o)}}a||(a=new Rn);var P=a.get(e);if(P)return P;a.set(e,d),Kd(e)?e.forEach((function(u){d.add(Jn(u,t,n,u,e,a))})):$d(e)&&e.forEach((function(u,r){d.set(r,Jn(u,t,n,r,e,a))}));var M=w?void 0:(s?c?Gr:qr:c?Eo:_o)(e);return ot(M||e,(function(u,r){M&&(u=e[r=u]),Hn(d,r,Jn(u,t,n,r,e,a))})),d}function Yn(e,t,n){var u=n.length;if(null==e)return!u;for(e=he(e);u--;){var r=n[u],a=t[r],d=e[r];if(void 0===d&&!(r in e)||!a(d))return!1}return!0}function Qn(e,t,n){if("function"!=typeof e)throw new ge(a);return ya((function(){e.apply(void 0,n)}),t)}function Xn(e,t,n,u){var r=-1,a=ft,d=!0,o=e.length,i=[],c=t.length;if(!o)return i;n&&(t=pt(t,At(n))),u?(a=st,d=!1):t.length>=200&&(a=Nt,d=!1,t=new Mn(t));e:for(;++r-1},Tn.prototype.set=function(e,t){var n=this.__data__,u=$n(n,e);return u<0?(++this.size,n.push([e,t])):n[u][1]=t,this},Pn.prototype.clear=function(){this.size=0,this.__data__={hash:new Fn,map:new(pn||Tn),string:new Fn}},Pn.prototype.delete=function(e){var t=Yr(this,e).delete(e);return this.size-=t?1:0,t},Pn.prototype.get=function(e){return Yr(this,e).get(e)},Pn.prototype.has=function(e){return Yr(this,e).has(e)},Pn.prototype.set=function(e,t){var n=Yr(this,e),u=n.size;return n.set(e,t),this.size+=n.size==u?0:1,this},Mn.prototype.add=Mn.prototype.push=function(e){return this.__data__.set(e,"__lodash_hash_undefined__"),this},Mn.prototype.has=function(e){return this.__data__.has(e)},Rn.prototype.clear=function(){this.__data__=new Tn,this.size=0},Rn.prototype.delete=function(e){var t=this.__data__,n=t.delete(e);return this.size=t.size,n},Rn.prototype.get=function(e){return this.__data__.get(e)},Rn.prototype.has=function(e){return this.__data__.has(e)},Rn.prototype.set=function(e,t){var n=this.__data__;if(n instanceof Tn){var u=n.__data__;if(!pn||u.length<199)return u.push([e,t]),this.size=++n.size,this;n=this.__data__=new Pn(u)}return n.set(e,t),this.size=n.size,this};var eu=Er(iu),tu=Er(cu,!0);function nu(e,t){var n=!0;return eu(e,(function(e,u,r){return n=!!t(e,u,r)})),n}function uu(e,t,n){for(var u=-1,r=e.length;++u0&&n(o)?t>1?au(o,t-1,n,u,r):mt(r,o):u||(r[r.length]=o)}return r}var du=wr(),ou=wr(!0);function iu(e,t){return e&&du(e,t,_o)}function cu(e,t){return e&&ou(e,t,_o)}function lu(e,t){return lt(t,(function(t){return Bd(e[t])}))}function fu(e,t){for(var n=0,u=(t=or(t,e)).length;null!=e&&nt}function hu(e,t){return null!=e&&ke.call(e,t)}function bu(e,t){return null!=e&&t in he(e)}function vu(e,t,n){for(var r=n?st:ft,a=e[0].length,d=e.length,o=d,i=u(d),c=1/0,l=[];o--;){var f=e[o];o&&t&&(f=pt(f,At(t))),c=dn(f.length,c),i[o]=!n&&(t||a>=120&&f.length>=120)?new Mn(o&&f):void 0}f=e[0];var s=-1,p=i[0];e:for(;++s=o)return i;var c=n[u];return i*("desc"==c?-1:1)}}return e.index-t.index}(e,t,n)}))}function Fu(e,t,n){for(var u=-1,r=t.length,a={};++u-1;)o!==e&&Ze.call(o,i,1),Ze.call(e,i,1);return e}function Pu(e,t){for(var n=e?t.length:0,u=n-1;n--;){var r=t[n];if(n==u||r!==a){var a=r;da(r)?Ze.call(e,r,1):Xu(e,r)}}return e}function Mu(e,t){return e+Xt(ln()*(t-e+1))}function Ru(e,t){var n="";if(!e||t<1||t>9007199254740991)return n;do{t%2&&(n+=e),(t=Xt(t/2))&&(e+=e)}while(t);return n}function Lu(e,t){return _a(ma(e,t,Go),e+"")}function Bu(e){return Bn(Io(e))}function zu(e,t){var n=Io(e);return Da(n,Zn(t,0,n.length))}function Uu(e,t,n,u){if(!Wd(e))return e;for(var r=-1,a=(t=or(t,e)).length,d=a-1,o=e;null!=o&&++ra?0:a+t),(n=n>a?a:n)<0&&(n+=a),a=t>n?0:n-t>>>0,t>>>=0;for(var d=u(a);++r>>1,d=e[a];null!==d&&!Jd(d)&&(n?d<=t:d=200){var c=t?null:Rr(e);if(c)return Ht(c);d=!1,r=Nt,i=new Mn}else i=t?[]:o;e:for(;++u=u?e:qu(e,t,n)}var lr=Zt||function(e){return Ve.clearTimeout(e)};function fr(e,t){if(t)return e.slice();var n=e.length,u=We?We(n):new e.constructor(n);return e.copy(u),u}function sr(e){var t=new e.constructor(e.byteLength);return new Me(t).set(new Me(e)),t}function pr(e,t){var n=t?sr(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.length)}function mr(e,t){if(e!==t){var n=void 0!==e,u=null===e,r=e==e,a=Jd(e),d=void 0!==t,o=null===t,i=t==t,c=Jd(t);if(!o&&!c&&!a&&e>t||a&&d&&i&&!o&&!c||u&&d&&i||!n&&i||!r)return 1;if(!u&&!a&&!c&&e1?n[r-1]:void 0,d=r>2?n[2]:void 0;for(a=e.length>3&&"function"==typeof a?(r--,a):void 0,d&&oa(n[0],n[1],d)&&(a=r<3?void 0:a,r=1),t=he(t);++u-1?r[a?t[d]:d]:void 0}}function Cr(e){return $r((function(t){var n=t.length,u=n,r=jn.prototype.thru;for(e&&t.reverse();u--;){var d=t[u];if("function"!=typeof d)throw new ge(a);if(r&&!o&&"wrapper"==Kr(d))var o=new jn([],!0)}for(u=o?u:n;++u1&&y.reverse(),f&&co))return!1;var c=a.get(e);if(c&&a.get(t))return c==t;var l=-1,f=!0,s=2&n?new Mn:void 0;for(a.set(e,t),a.set(t,e);++l-1&&e%1==0&&e1?"& ":"")+t[u],t=t.join(n>2?", ":" "),e.replace(Y,"{\n/* [wrapped with "+t+"] */\n")}(u,function(e,t){return ot(o,(function(n){var u="_."+n[0];t&n[1]&&!ft(e,u)&&e.push(u)})),e.sort()}(function(e){var t=e.match(Q);return t?t[1].split(X):[]}(u),n)))}function wa(e){var t=0,n=0;return function(){var u=on(),r=16-(u-n);if(n=u,r>0){if(++t>=800)return arguments[0]}else t=0;return e.apply(void 0,arguments)}}function Da(e,t){var n=-1,u=e.length,r=u-1;for(t=void 0===t?u:t;++n1?e[t-1]:void 0;return n="function"==typeof n?(e.pop(),n):void 0,Va(e,n)}));function ed(e){var t=On(e);return t.__chain__=!0,t}function td(e,t){return t(e)}var nd=$r((function(e){var t=e.length,n=t?e[0]:0,u=this.__wrapped__,r=function(t){return Kn(t,e)};return!(t>1||this.__actions__.length)&&u instanceof Nn&&da(n)?((u=u.slice(n,+n+(t?1:0))).__actions__.push({func:td,args:[r],thisArg:void 0}),new jn(u,this.__chain__).thru((function(e){return t&&!e.length&&e.push(void 0),e}))):this.thru(r)}));var ud=yr((function(e,t,n){ke.call(e,n)?++e[n]:Vn(e,n,1)}));var rd=Sr(ja),ad=Sr(Na);function dd(e,t){return(Nd(e)?ot:eu)(e,Jr(t,3))}function od(e,t){return(Nd(e)?it:tu)(e,Jr(t,3))}var id=yr((function(e,t,n){ke.call(e,n)?e[n].push(t):Vn(e,n,[t])}));var cd=Lu((function(e,t,n){var r=-1,a="function"==typeof t,d=Td(e)?u(e.length):[];return eu(e,(function(e){d[++r]=a?at(t,e,n):gu(e,t,n)})),d})),ld=yr((function(e,t,n){Vn(e,n,t)}));function fd(e,t){return(Nd(e)?pt:Cu)(e,Jr(t,3))}var sd=yr((function(e,t,n){e[n?0:1].push(t)}),(function(){return[[],[]]}));var pd=Lu((function(e,t){if(null==e)return[];var n=t.length;return n>1&&oa(e,t[0],t[1])?t=[]:n>2&&oa(t[0],t[1],t[2])&&(t=[t[0]]),Nu(e,au(t,1),[])})),md=Jt||function(){return Ve.Date.now()};function hd(e,t,n){return t=n?void 0:t,Br(e,128,void 0,void 0,void 0,void 0,t=e&&null==t?e.length:t)}function bd(e,t){var n;if("function"!=typeof t)throw new ge(a);return e=no(e),function(){return--e>0&&(n=t.apply(this,arguments)),e<=1&&(t=void 0),n}}var vd=Lu((function(e,t,n){var u=1;if(n.length){var r=Wt(n,Zr(vd));u|=32}return Br(e,u,t,n,r)})),gd=Lu((function(e,t,n){var u=3;if(n.length){var r=Wt(n,Zr(gd));u|=32}return Br(t,u,e,n,r)}));function yd(e,t,n){var u,r,d,o,i,c,l=0,f=!1,s=!1,p=!0;if("function"!=typeof e)throw new ge(a);function m(t){var n=u,a=r;return u=r=void 0,l=t,o=e.apply(a,n)}function h(e){return l=e,i=ya(v,t),f?m(e):o}function b(e){var n=e-c;return void 0===c||n>=t||n<0||s&&e-l>=d}function v(){var e=md();if(b(e))return g(e);i=ya(v,function(e){var n=t-(e-c);return s?dn(n,d-(e-l)):n}(e))}function g(e){return i=void 0,p&&u?m(e):(u=r=void 0,o)}function y(){var e=md(),n=b(e);if(u=arguments,r=this,c=e,n){if(void 0===i)return h(c);if(s)return lr(i),i=ya(v,t),m(c)}return void 0===i&&(i=ya(v,t)),o}return t=ro(t)||0,Wd(n)&&(f=!!n.leading,d=(s="maxWait"in n)?an(ro(n.maxWait)||0,t):d,p="trailing"in n?!!n.trailing:p),y.cancel=function(){void 0!==i&&lr(i),l=0,u=c=r=i=void 0},y.flush=function(){return void 0===i?o:g(md())},y}var _d=Lu((function(e,t){return Qn(e,1,t)})),Ed=Lu((function(e,t,n){return Qn(e,ro(t)||0,n)}));function wd(e,t){if("function"!=typeof e||null!=t&&"function"!=typeof t)throw new ge(a);var n=function(){var u=arguments,r=t?t.apply(this,u):u[0],a=n.cache;if(a.has(r))return a.get(r);var d=e.apply(this,u);return n.cache=a.set(r,d)||a,d};return n.cache=new(wd.Cache||Pn),n}function Dd(e){if("function"!=typeof e)throw new ge(a);return function(){var t=arguments;switch(t.length){case 0:return!e.call(this);case 1:return!e.call(this,t[0]);case 2:return!e.call(this,t[0],t[1]);case 3:return!e.call(this,t[0],t[1],t[2])}return!e.apply(this,t)}}wd.Cache=Pn;var kd=ir((function(e,t){var n=(t=1==t.length&&Nd(t[0])?pt(t[0],At(Jr())):pt(au(t,1),At(Jr()))).length;return Lu((function(u){for(var r=-1,a=dn(u.length,n);++r=t})),jd=yu(function(){return arguments}())?yu:function(e){return Hd(e)&&ke.call(e,"callee")&&!Ke.call(e,"callee")},Nd=u.isArray,Fd=Xe?At(Xe):function(e){return Hd(e)&&pu(e)==D};function Td(e){return null!=e&&Ud(e.length)&&!Bd(e)}function Pd(e){return Hd(e)&&Td(e)}var Md=tn||ai,Rd=et?At(et):function(e){return Hd(e)&&pu(e)==f};function Ld(e){if(!Hd(e))return!1;var t=pu(e);return t==s||"[object DOMException]"==t||"string"==typeof e.message&&"string"==typeof e.name&&!Gd(e)}function Bd(e){if(!Wd(e))return!1;var t=pu(e);return t==p||t==m||"[object AsyncFunction]"==t||"[object Proxy]"==t}function zd(e){return"number"==typeof e&&e==no(e)}function Ud(e){return"number"==typeof e&&e>-1&&e%1==0&&e<=9007199254740991}function Wd(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}function Hd(e){return null!=e&&"object"==typeof e}var $d=tt?At(tt):function(e){return Hd(e)&&na(e)==h};function qd(e){return"number"==typeof e||Hd(e)&&pu(e)==b}function Gd(e){if(!Hd(e)||pu(e)!=v)return!1;var t=qe(e);if(null===t)return!0;var n=ke.call(t,"constructor")&&t.constructor;return"function"==typeof n&&n instanceof n&&De.call(n)==Oe}var Vd=nt?At(nt):function(e){return Hd(e)&&pu(e)==g};var Kd=ut?At(ut):function(e){return Hd(e)&&na(e)==y};function Zd(e){return"string"==typeof e||!Nd(e)&&Hd(e)&&pu(e)==_}function Jd(e){return"symbol"==typeof e||Hd(e)&&pu(e)==E}var Yd=rt?At(rt):function(e){return Hd(e)&&Ud(e.length)&&!!ze[pu(e)]};var Qd=Tr(Su),Xd=Tr((function(e,t){return e<=t}));function eo(e){if(!e)return[];if(Td(e))return Zd(e)?Gt(e):vr(e);if(Qe&&e[Qe])return function(e){for(var t,n=[];!(t=e.next()).done;)n.push(t.value);return n}(e[Qe]());var t=na(e);return(t==h?zt:t==y?Ht:Io)(e)}function to(e){return e?(e=ro(e))===1/0||e===-1/0?17976931348623157e292*(e<0?-1:1):e==e?e:0:0===e?e:0}function no(e){var t=to(e),n=t%1;return t==t?n?t-n:t:0}function uo(e){return e?Zn(no(e),0,4294967295):0}function ro(e){if("number"==typeof e)return e;if(Jd(e))return NaN;if(Wd(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=Wd(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(K,"");var n=ae.test(e);return n||oe.test(e)?$e(e.slice(2),n?2:8):re.test(e)?NaN:+e}function ao(e){return gr(e,Eo(e))}function oo(e){return null==e?"":Yu(e)}var io=_r((function(e,t){if(fa(t)||Td(t))gr(t,_o(t),e);else for(var n in t)ke.call(t,n)&&Hn(e,n,t[n])})),co=_r((function(e,t){gr(t,Eo(t),e)})),lo=_r((function(e,t,n,u){gr(t,Eo(t),e,u)})),fo=_r((function(e,t,n,u){gr(t,_o(t),e,u)})),so=$r(Kn);var po=Lu((function(e,t){e=he(e);var n=-1,u=t.length,r=u>2?t[2]:void 0;for(r&&oa(t[0],t[1],r)&&(u=1);++n1),t})),gr(e,Gr(e),n),u&&(n=Jn(n,7,Wr));for(var r=t.length;r--;)Xu(n,t[r]);return n}));var xo=$r((function(e,t){return null==e?{}:function(e,t){return Fu(e,t,(function(t,n){return bo(e,n)}))}(e,t)}));function So(e,t){if(null==e)return{};var n=pt(Gr(e),(function(e){return[e]}));return t=Jr(t),Fu(e,n,(function(e,n){return t(e,n[0])}))}var Co=Lr(_o),Oo=Lr(Eo);function Io(e){return null==e?[]:jt(e,_o(e))}var Ao=kr((function(e,t,n){return t=t.toLowerCase(),e+(n?jo(t):t)}));function jo(e){return Bo(oo(e).toLowerCase())}function No(e){return(e=oo(e))&&e.replace(ce,Mt).replace(Fe,"")}var Fo=kr((function(e,t,n){return e+(n?"-":"")+t.toLowerCase()})),To=kr((function(e,t,n){return e+(n?" ":"")+t.toLowerCase()})),Po=Dr("toLowerCase");var Mo=kr((function(e,t,n){return e+(n?"_":"")+t.toLowerCase()}));var Ro=kr((function(e,t,n){return e+(n?" ":"")+Bo(t)}));var Lo=kr((function(e,t,n){return e+(n?" ":"")+t.toUpperCase()})),Bo=Dr("toUpperCase");function zo(e,t,n){return e=oo(e),void 0===(t=n?void 0:t)?function(e){return Re.test(e)}(e)?function(e){return e.match(Pe)||[]}(e):function(e){return e.match(ee)||[]}(e):e.match(t)||[]}var Uo=Lu((function(e,t){try{return at(e,void 0,t)}catch(n){return Ld(n)?n:new se(n)}})),Wo=$r((function(e,t){return ot(t,(function(t){t=xa(t),Vn(e,t,vd(e[t],e))})),e}));function Ho(e){return function(){return e}}var $o=Cr(),qo=Cr(!0);function Go(e){return e}function Vo(e){return Du("function"==typeof e?e:Jn(e,1))}var Ko=Lu((function(e,t){return function(n){return gu(n,e,t)}})),Zo=Lu((function(e,t){return function(n){return gu(e,n,t)}}));function Jo(e,t,n){var u=_o(t),r=lu(t,u);null!=n||Wd(t)&&(r.length||!u.length)||(n=t,t=e,e=this,r=lu(t,_o(t)));var a=!(Wd(n)&&"chain"in n&&!n.chain),d=Bd(e);return ot(r,(function(n){var u=t[n];e[n]=u,d&&(e.prototype[n]=function(){var t=this.__chain__;if(a||t){var n=e(this.__wrapped__),r=n.__actions__=vr(this.__actions__);return r.push({func:u,args:arguments,thisArg:e}),n.__chain__=t,n}return u.apply(e,mt([this.value()],arguments))})})),e}function Yo(){}var Qo=jr(pt),Xo=jr(ct),ei=jr(vt);function ti(e){return ia(e)?xt(xa(e)):function(e){return function(t){return fu(t,e)}}(e)}var ni=Fr(),ui=Fr(!0);function ri(){return[]}function ai(){return!1}var di=Ar((function(e,t){return e+t}),0),oi=Mr("ceil"),ii=Ar((function(e,t){return e/t}),1),ci=Mr("floor");var li,fi=Ar((function(e,t){return e*t}),1),si=Mr("round"),pi=Ar((function(e,t){return e-t}),0);return On.after=function(e,t){if("function"!=typeof t)throw new ge(a);return e=no(e),function(){if(--e<1)return t.apply(this,arguments)}},On.ary=hd,On.assign=io,On.assignIn=co,On.assignInWith=lo,On.assignWith=fo,On.at=so,On.before=bd,On.bind=vd,On.bindAll=Wo,On.bindKey=gd,On.castArray=function(){if(!arguments.length)return[];var e=arguments[0];return Nd(e)?e:[e]},On.chain=ed,On.chunk=function(e,t,n){t=(n?oa(e,t,n):void 0===t)?1:an(no(t),0);var r=null==e?0:e.length;if(!r||t<1)return[];for(var a=0,d=0,o=u(Qt(r/t));ar?0:r+n),(u=void 0===u||u>r?r:no(u))<0&&(u+=r),u=n>u?0:uo(u);n>>0)?(e=oo(e))&&("string"==typeof t||null!=t&&!Vd(t))&&!(t=Yu(t))&&Bt(e)?cr(Gt(e),0,n):e.split(t,n):[]},On.spread=function(e,t){if("function"!=typeof e)throw new ge(a);return t=null==t?0:an(no(t),0),Lu((function(n){var u=n[t],r=cr(n,0,t);return u&&mt(r,u),at(e,this,r)}))},On.tail=function(e){var t=null==e?0:e.length;return t?qu(e,1,t):[]},On.take=function(e,t,n){return e&&e.length?qu(e,0,(t=n||void 0===t?1:no(t))<0?0:t):[]},On.takeRight=function(e,t,n){var u=null==e?0:e.length;return u?qu(e,(t=u-(t=n||void 0===t?1:no(t)))<0?0:t,u):[]},On.takeRightWhile=function(e,t){return e&&e.length?tr(e,Jr(t,3),!1,!0):[]},On.takeWhile=function(e,t){return e&&e.length?tr(e,Jr(t,3)):[]},On.tap=function(e,t){return t(e),e},On.throttle=function(e,t,n){var u=!0,r=!0;if("function"!=typeof e)throw new ge(a);return Wd(n)&&(u="leading"in n?!!n.leading:u,r="trailing"in n?!!n.trailing:r),yd(e,t,{leading:u,maxWait:t,trailing:r})},On.thru=td,On.toArray=eo,On.toPairs=Co,On.toPairsIn=Oo,On.toPath=function(e){return Nd(e)?pt(e,xa):Jd(e)?[e]:vr(ka(oo(e)))},On.toPlainObject=ao,On.transform=function(e,t,n){var u=Nd(e),r=u||Md(e)||Yd(e);if(t=Jr(t,4),null==n){var a=e&&e.constructor;n=r?u?new a:[]:Wd(e)&&Bd(a)?In(qe(e)):{}}return(r?ot:iu)(e,(function(e,u,r){return t(n,e,u,r)})),n},On.unary=function(e){return hd(e,1)},On.union=Ha,On.unionBy=$a,On.unionWith=qa,On.uniq=function(e){return e&&e.length?Qu(e):[]},On.uniqBy=function(e,t){return e&&e.length?Qu(e,Jr(t,2)):[]},On.uniqWith=function(e,t){return t="function"==typeof t?t:void 0,e&&e.length?Qu(e,void 0,t):[]},On.unset=function(e,t){return null==e||Xu(e,t)},On.unzip=Ga,On.unzipWith=Va,On.update=function(e,t,n){return null==e?e:er(e,t,dr(n))},On.updateWith=function(e,t,n,u){return u="function"==typeof u?u:void 0,null==e?e:er(e,t,dr(n),u)},On.values=Io,On.valuesIn=function(e){return null==e?[]:jt(e,Eo(e))},On.without=Ka,On.words=zo,On.wrap=function(e,t){return xd(dr(t),e)},On.xor=Za,On.xorBy=Ja,On.xorWith=Ya,On.zip=Qa,On.zipObject=function(e,t){return rr(e||[],t||[],Hn)},On.zipObjectDeep=function(e,t){return rr(e||[],t||[],Uu)},On.zipWith=Xa,On.entries=Co,On.entriesIn=Oo,On.extend=co,On.extendWith=lo,Jo(On,On),On.add=di,On.attempt=Uo,On.camelCase=Ao,On.capitalize=jo,On.ceil=oi,On.clamp=function(e,t,n){return void 0===n&&(n=t,t=void 0),void 0!==n&&(n=(n=ro(n))==n?n:0),void 0!==t&&(t=(t=ro(t))==t?t:0),Zn(ro(e),t,n)},On.clone=function(e){return Jn(e,4)},On.cloneDeep=function(e){return Jn(e,5)},On.cloneDeepWith=function(e,t){return Jn(e,5,t="function"==typeof t?t:void 0)},On.cloneWith=function(e,t){return Jn(e,4,t="function"==typeof t?t:void 0)},On.conformsTo=function(e,t){return null==t||Yn(e,t,_o(t))},On.deburr=No,On.defaultTo=function(e,t){return null==e||e!=e?t:e},On.divide=ii,On.endsWith=function(e,t,n){e=oo(e),t=Yu(t);var u=e.length,r=n=void 0===n?u:Zn(no(n),0,u);return(n-=t.length)>=0&&e.slice(n,r)==t},On.eq=Od,On.escape=function(e){return(e=oo(e))&&B.test(e)?e.replace(R,Rt):e},On.escapeRegExp=function(e){return(e=oo(e))&&V.test(e)?e.replace(G,"\\$&"):e},On.every=function(e,t,n){var u=Nd(e)?ct:nu;return n&&oa(e,t,n)&&(t=void 0),u(e,Jr(t,3))},On.find=rd,On.findIndex=ja,On.findKey=function(e,t){return yt(e,Jr(t,3),iu)},On.findLast=ad,On.findLastIndex=Na,On.findLastKey=function(e,t){return yt(e,Jr(t,3),cu)},On.floor=ci,On.forEach=dd,On.forEachRight=od,On.forIn=function(e,t){return null==e?e:du(e,Jr(t,3),Eo)},On.forInRight=function(e,t){return null==e?e:ou(e,Jr(t,3),Eo)},On.forOwn=function(e,t){return e&&iu(e,Jr(t,3))},On.forOwnRight=function(e,t){return e&&cu(e,Jr(t,3))},On.get=ho,On.gt=Id,On.gte=Ad,On.has=function(e,t){return null!=e&&ua(e,t,hu)},On.hasIn=bo,On.head=Ta,On.identity=Go,On.includes=function(e,t,n,u){e=Td(e)?e:Io(e),n=n&&!u?no(n):0;var r=e.length;return n<0&&(n=an(r+n,0)),Zd(e)?n<=r&&e.indexOf(t,n)>-1:!!r&&Et(e,t,n)>-1},On.indexOf=function(e,t,n){var u=null==e?0:e.length;if(!u)return-1;var r=null==n?0:no(n);return r<0&&(r=an(u+r,0)),Et(e,t,r)},On.inRange=function(e,t,n){return t=to(t),void 0===n?(n=t,t=0):n=to(n),function(e,t,n){return e>=dn(t,n)&&e=-9007199254740991&&e<=9007199254740991},On.isSet=Kd,On.isString=Zd,On.isSymbol=Jd,On.isTypedArray=Yd,On.isUndefined=function(e){return void 0===e},On.isWeakMap=function(e){return Hd(e)&&na(e)==w},On.isWeakSet=function(e){return Hd(e)&&"[object WeakSet]"==pu(e)},On.join=function(e,t){return null==e?"":un.call(e,t)},On.kebabCase=Fo,On.last=La,On.lastIndexOf=function(e,t,n){var u=null==e?0:e.length;if(!u)return-1;var r=u;return void 0!==n&&(r=(r=no(n))<0?an(u+r,0):dn(r,u-1)),t==t?function(e,t,n){for(var u=n+1;u--;)if(e[u]===t)return u;return u}(e,t,r):_t(e,Dt,r,!0)},On.lowerCase=To,On.lowerFirst=Po,On.lt=Qd,On.lte=Xd,On.max=function(e){return e&&e.length?uu(e,Go,mu):void 0},On.maxBy=function(e,t){return e&&e.length?uu(e,Jr(t,2),mu):void 0},On.mean=function(e){return kt(e,Go)},On.meanBy=function(e,t){return kt(e,Jr(t,2))},On.min=function(e){return e&&e.length?uu(e,Go,Su):void 0},On.minBy=function(e,t){return e&&e.length?uu(e,Jr(t,2),Su):void 0},On.stubArray=ri,On.stubFalse=ai,On.stubObject=function(){return{}},On.stubString=function(){return""},On.stubTrue=function(){return!0},On.multiply=fi,On.nth=function(e,t){return e&&e.length?ju(e,no(t)):void 0},On.noConflict=function(){return Ve._===this&&(Ve._=Ie),this},On.noop=Yo,On.now=md,On.pad=function(e,t,n){e=oo(e);var u=(t=no(t))?qt(e):0;if(!t||u>=t)return e;var r=(t-u)/2;return Nr(Xt(r),n)+e+Nr(Qt(r),n)},On.padEnd=function(e,t,n){e=oo(e);var u=(t=no(t))?qt(e):0;return t&&ut){var u=e;e=t,t=u}if(n||e%1||t%1){var r=ln();return dn(e+r*(t-e+He("1e-"+((r+"").length-1))),t)}return Mu(e,t)},On.reduce=function(e,t,n){var u=Nd(e)?ht:Ct,r=arguments.length<3;return u(e,Jr(t,4),n,r,eu)},On.reduceRight=function(e,t,n){var u=Nd(e)?bt:Ct,r=arguments.length<3;return u(e,Jr(t,4),n,r,tu)},On.repeat=function(e,t,n){return t=(n?oa(e,t,n):void 0===t)?1:no(t),Ru(oo(e),t)},On.replace=function(){var e=arguments,t=oo(e[0]);return e.length<3?t:t.replace(e[1],e[2])},On.result=function(e,t,n){var u=-1,r=(t=or(t,e)).length;for(r||(r=1,e=void 0);++u9007199254740991)return[];var n=4294967295,u=dn(e,4294967295);e-=4294967295;for(var r=It(u,t=Jr(t));++n=a)return e;var o=n-qt(u);if(o<1)return u;var i=d?cr(d,0,o).join(""):e.slice(0,o);if(void 0===r)return i+u;if(d&&(o+=i.length-o),Vd(r)){if(e.slice(o).search(r)){var c,l=i;for(r.global||(r=be(r.source,oo(ue.exec(r))+"g")),r.lastIndex=0;c=r.exec(l);)var f=c.index;i=i.slice(0,void 0===f?o:f)}}else if(e.indexOf(Yu(r),o)!=o){var s=i.lastIndexOf(r);s>-1&&(i=i.slice(0,s))}return i+u},On.unescape=function(e){return(e=oo(e))&&L.test(e)?e.replace(M,Vt):e},On.uniqueId=function(e){var t=++xe;return oo(e)+t},On.upperCase=Lo,On.upperFirst=Bo,On.each=dd,On.eachRight=od,On.first=Ta,Jo(On,(li={},iu(On,(function(e,t){ke.call(On.prototype,t)||(li[t]=e)})),li),{chain:!1}),On.VERSION="4.17.15",ot(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(e){On[e].placeholder=On})),ot(["drop","take"],(function(e,t){Nn.prototype[e]=function(n){n=void 0===n?1:an(no(n),0);var u=this.__filtered__&&!t?new Nn(this):this.clone();return u.__filtered__?u.__takeCount__=dn(n,u.__takeCount__):u.__views__.push({size:dn(n,4294967295),type:e+(u.__dir__<0?"Right":"")}),u},Nn.prototype[e+"Right"]=function(t){return this.reverse()[e](t).reverse()}})),ot(["filter","map","takeWhile"],(function(e,t){var n=t+1,u=1==n||3==n;Nn.prototype[e]=function(e){var t=this.clone();return t.__iteratees__.push({iteratee:Jr(e,3),type:n}),t.__filtered__=t.__filtered__||u,t}})),ot(["head","last"],(function(e,t){var n="take"+(t?"Right":"");Nn.prototype[e]=function(){return this[n](1).value()[0]}})),ot(["initial","tail"],(function(e,t){var n="drop"+(t?"":"Right");Nn.prototype[e]=function(){return this.__filtered__?new Nn(this):this[n](1)}})),Nn.prototype.compact=function(){return this.filter(Go)},Nn.prototype.find=function(e){return this.filter(e).head()},Nn.prototype.findLast=function(e){return this.reverse().find(e)},Nn.prototype.invokeMap=Lu((function(e,t){return"function"==typeof e?new Nn(this):this.map((function(n){return gu(n,e,t)}))})),Nn.prototype.reject=function(e){return this.filter(Dd(Jr(e)))},Nn.prototype.slice=function(e,t){e=no(e);var n=this;return n.__filtered__&&(e>0||t<0)?new Nn(n):(e<0?n=n.takeRight(-e):e&&(n=n.drop(e)),void 0!==t&&(n=(t=no(t))<0?n.dropRight(-t):n.take(t-e)),n)},Nn.prototype.takeRightWhile=function(e){return this.reverse().takeWhile(e).reverse()},Nn.prototype.toArray=function(){return this.take(4294967295)},iu(Nn.prototype,(function(e,t){var n=/^(?:filter|find|map|reject)|While$/.test(t),u=/^(?:head|last)$/.test(t),r=On[u?"take"+("last"==t?"Right":""):t],a=u||/^find/.test(t);r&&(On.prototype[t]=function(){var t=this.__wrapped__,d=u?[1]:arguments,o=t instanceof Nn,i=d[0],c=o||Nd(t),l=function(e){var t=r.apply(On,mt([e],d));return u&&f?t[0]:t};c&&n&&"function"==typeof i&&1!=i.length&&(o=c=!1);var f=this.__chain__,s=!!this.__actions__.length,p=a&&!f,m=o&&!s;if(!a&&c){t=m?t:new Nn(this);var h=e.apply(t,d);return h.__actions__.push({func:td,args:[l],thisArg:void 0}),new jn(h,f)}return p&&m?e.apply(this,d):(h=this.thru(l),p?u?h.value()[0]:h.value():h)})})),ot(["pop","push","shift","sort","splice","unshift"],(function(e){var t=ye[e],n=/^(?:push|sort|unshift)$/.test(e)?"tap":"thru",u=/^(?:pop|shift)$/.test(e);On.prototype[e]=function(){var e=arguments;if(u&&!this.__chain__){var r=this.value();return t.apply(Nd(r)?r:[],e)}return this[n]((function(n){return t.apply(Nd(n)?n:[],e)}))}})),iu(Nn.prototype,(function(e,t){var n=On[t];if(n){var u=n.name+"";ke.call(yn,u)||(yn[u]=[]),yn[u].push({name:t,func:n})}})),yn[Or(void 0,2).name]=[{name:"wrapper",func:void 0}],Nn.prototype.clone=function(){var e=new Nn(this.__wrapped__);return e.__actions__=vr(this.__actions__),e.__dir__=this.__dir__,e.__filtered__=this.__filtered__,e.__iteratees__=vr(this.__iteratees__),e.__takeCount__=this.__takeCount__,e.__views__=vr(this.__views__),e},Nn.prototype.reverse=function(){if(this.__filtered__){var e=new Nn(this);e.__dir__=-1,e.__filtered__=!0}else(e=this.clone()).__dir__*=-1;return e},Nn.prototype.value=function(){var e=this.__wrapped__.value(),t=this.__dir__,n=Nd(e),u=t<0,r=n?e.length:0,a=function(e,t,n){var u=-1,r=n.length;for(;++u=this.__values__.length;return{done:e,value:e?void 0:this.__values__[this.__index__++]}},On.prototype.plant=function(e){for(var t,n=this;n instanceof An;){var u=Ca(n);u.__index__=0,u.__values__=void 0,t?r.__wrapped__=u:t=u;var r=u;n=n.__wrapped__}return r.__wrapped__=e,t},On.prototype.reverse=function(){var e=this.__wrapped__;if(e instanceof Nn){var t=e;return this.__actions__.length&&(t=new Nn(this)),(t=t.reverse()).__actions__.push({func:td,args:[Wa],thisArg:void 0}),new jn(t,this.__chain__)}return this.thru(Wa)},On.prototype.toJSON=On.prototype.valueOf=On.prototype.value=function(){return nr(this.__wrapped__,this.__actions__)},On.prototype.first=On.prototype.head,Qe&&(On.prototype[Qe]=function(){return this}),On}();Ve._=Kt,void 0===(r=function(){return Kt}.call(t,n,t,u))||(u.exports=r)}).call(this)}).call(this,n(76),n(456)(e))},452:function(e,t,n){"use strict";var u=n(0);t.a=function(e){void 0===e&&(e=!0),Object(u.useEffect)((function(){return document.body.style.overflow=e?"hidden":"visible",function(){document.body.style.overflow="visible"}}),[e])}},453:function(e,t,n){"use strict";var u=n(436),r=n(441),a=n(438),d=n(432);t.a=function(){var e=Object(u.a)().siteConfig,t=(e=void 0===e?{}:e).baseUrl,n=e.themeConfig.navbar,o=(n=void 0===n?{}:n).logo,i=void 0===o?{}:o,c=Object(r.a)().isDarkTheme,l=i.href||t,f={};i.target?f={target:i.target}:Object(d.a)(l)||(f={rel:"noopener noreferrer",target:"_blank"});var s=i.srcDark&&c?i.srcDark:i.src;return{logoLink:l,logoLinkProps:f,logoImageUrl:Object(a.a)(s),logoAlt:i.alt}}},455:function(e,t,n){"use strict";n.d(t,"a",(function(){return a}));n(77),n(473),n(439),n(78);var u=n(475),r=n.n(u);function a(e,t){var n=new r.a;return e.map((function(e){var u=e;return"string"==typeof e&&(u={label:e,permalink:"/blog/tags/"+n.slug(e)}),function(e,t){var n=e.label.split(": ",2),u=n[0],r=n[1],a="primary";switch(t){case"blog":case"guides":a=function(e){switch(e){case"domain":return"blue";case"type":return"pink";default:return"primary"}}(u)}return{category:u,count:e.count,label:e.label,permalink:e.permalink,style:a,value:r}}(u,t)}))}},456:function(e,t){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),e.webpackPolyfill=1),e}},457:function(e,t,n){"use strict";var u=n(12),r=n(26),a=n(517),d="".endsWith;u(u.P+u.F*n(518)("endsWith"),"String",{endsWith:function(e){var t=a(this,e,"endsWith"),n=arguments.length>1?arguments[1]:void 0,u=r(t.length),o=void 0===n?u:Math.min(r(n),u),i=String(e);return d?d.call(t,i,o):t.slice(o-i.length,o)===i}})},458:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(436),d=n(145),o=n.n(d);t.a=function(){var e=Object(a.a)().siteConfig,t=(e=void 0===e?{}:e).themeConfig.announcementBar,n=void 0===t?{}:t,d=n.id,i=n.content,c=n.backgroundColor,l=n.textColor,f=Object(u.useState)(!0),s=f[0],p=f[1];return Object(u.useEffect)((function(){var e=localStorage.getItem("docusaurus.announcement.id"),t=d!==e;localStorage.setItem("docusaurus.announcement.id",d),t&&localStorage.setItem("docusaurus.announcement.dismiss",!1),(t||"false"===localStorage.getItem("docusaurus.announcement.dismiss"))&&p(!1)}),[]),!i||s?null:r.a.createElement("div",{className:o.a.announcementBar,style:{backgroundColor:c,color:l},role:"banner"},r.a.createElement("div",{className:o.a.announcementBarContent,dangerouslySetInnerHTML:{__html:i}}),r.a.createElement("button",{type:"button",className:o.a.announcementBarClose,onClick:function(){localStorage.setItem("docusaurus.announcement.dismiss",!0),p(!0)},"aria-label":"Close"},r.a.createElement("span",{"aria-hidden":"true"},"\xd7")))}},459:function(e,t,n){"use strict";var u=n(0);u.PureComponent},460:function(e,t,n){"use strict";n(58),n(29),n(22),n(21),n(79);var u=n(0),r=n.n(u),a=n(423),d=n.n(a),o=n(436),i=n(472);n(146);t.a=function(e){var t=Object(u.useState)(!1),a=t[0],c=t[1],l=Object(u.useRef)(null),f=Object(o.a)().siteConfig,s=(void 0===f?{}:f).themeConfig.algolia,p=Object(i.c)();var m=function(e){void 0===e&&(e=!0),a||Promise.all([n.e(269).then(n.t.bind(null,570,7)),n.e(176).then(n.t.bind(null,583,7))]).then((function(t){var n=t[0].default;c(!0),window.docsearch=n,function(e){window.docsearch({appId:s.appId,apiKey:s.apiKey,indexName:s.indexName,inputSelector:"#search_input_react",algoliaOptions:s.algoliaOptions,handleSelected:function(e,t,n){var u=document.createElement("a");u.href=n.url;var r="#__docusaurus"===u.hash?""+u.pathname:""+u.pathname+u.hash;p.push(r)}}),e&&l.current.focus()}(e)}))},h=Object(u.useCallback)((function(){m(),a&&l.current.focus(),e.handleSearchBarToggle(!e.isSearchBarExpanded)}),[e.isSearchBarExpanded]),b=Object(u.useCallback)((function(){e.handleSearchBarToggle(!e.isSearchBarExpanded)}),[e.isSearchBarExpanded]),v=Object(u.useCallback)((function(e){var t="mouseover"!==e.type;m(t)}));return r.a.createElement("div",{className:"navbar__search",key:"search-box"},r.a.createElement("span",{"aria-label":"expand searchbar",role:"button",className:d()("search-icon",{"search-icon-hidden":e.isSearchBarExpanded}),onClick:h,onKeyDown:h,tabIndex:0}),r.a.createElement("input",{id:"search_input_react",type:"search",placeholder:"Search","aria-label":"Search",className:d()("navbar__search-input",{"search-bar-expanded":e.isSearchBarExpanded},{"search-bar":!e.isSearchBarExpanded}),onMouseOver:v,onFocus:v,onBlur:b,ref:l}))}},461:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u=Object.assign||function(e){for(var t=1;tthis.startX&&(this.setState({checked:!0}),this.startX=t,this.activated=tn?this.previouslyChecked!==this.state.checked&&(this.setState({checked:!1}),this.previouslyChecked=this.state.checked,t.click()):this.startX-4=0||Object.prototype.hasOwnProperty.call(e,u)&&(n[u]=e[u]);return n}(t,["className","icons"])),a=(0,o.default)("react-toggle",{"react-toggle--checked":this.state.checked,"react-toggle--focus":this.state.hasFocus,"react-toggle--disabled":this.props.disabled},n);return d.default.createElement("div",{className:a,onClick:this.handleClick,onTouchStart:this.handleTouchStart,onTouchMove:this.handleTouchMove,onTouchEnd:this.handleTouchEnd},d.default.createElement("div",{className:"react-toggle-track"},d.default.createElement("div",{className:"react-toggle-track-check"},this.getIcon("checked")),d.default.createElement("div",{className:"react-toggle-track-x"},this.getIcon("unchecked"))),d.default.createElement("div",{className:"react-toggle-thumb"}),d.default.createElement("input",u({},r,{ref:function(t){e.input=t},onFocus:this.handleFocus,onBlur:this.handleBlur,className:"react-toggle-screenreader-only",type:"checkbox"})))}}]),t}(a.PureComponent);t.default=p,p.displayName="Toggle",p.defaultProps={icons:{checked:d.default.createElement(c.default,null),unchecked:d.default.createElement(l.default,null)}},p.propTypes={checked:i.default.bool,disabled:i.default.bool,defaultChecked:i.default.bool,onChange:i.default.func,onFocus:i.default.func,onBlur:i.default.func,className:i.default.string,name:i.default.string,value:i.default.string,id:i.default.string,"aria-labelledby":i.default.string,"aria-label":i.default.string,icons:i.default.oneOfType([i.default.bool,i.default.shape({checked:i.default.node,unchecked:i.default.node})])}},462:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=(n(84),n(473),function(){var e=Object(u.useState)({}),t=e[0],n=e[1],r=Object(u.useCallback)((function(e,t){try{localStorage.setItem("docusaurus.tab."+e,t)}catch(n){console.error(n)}}),[]);return Object(u.useEffect)((function(){try{for(var e={},t=0;t=f?d(!1):e+n1&&"boolean"!=typeof t)throw new a('"allowMissing" argument must be a boolean');if(null===w(/^%?[^%]*%?$/,e))throw new u("`%` may not be present anywhere but at the beginning and end of the intrinsic name");var n=x(e),r=n.length>0?n[0]:"",d=S("%"+r+"%",t),i=d.name,c=d.value,l=!1,f=d.alias;f&&(r=f[0],y(n,g([0,1],f)));for(var s=1,p=!0;s=n.length){var D=o(c,h);c=(p=!!D)&&"get"in D&&!("originalValue"in D.get)?D.get:c[h]}else p=v(c,h),c=c[h];p&&!l&&(m[i]=c)}}return c}},470:function(e,t,n){"use strict";var u=n(509);e.exports=Function.prototype.bind||u},471:function(e,t,n){"use strict";var u=String.prototype.replace,r=/%20/g,a="RFC1738",d="RFC3986";e.exports={default:d,formatters:{RFC1738:function(e){return u.call(e,r,"+")},RFC3986:function(e){return String(e)}},RFC1738:a,RFC3986:d}},472:function(e,t,n){"use strict";var u=n(39);n.d(t,"a",(function(){return u.c})),n.d(t,"b",(function(){return u.d})),n.d(t,"c",(function(){return u.e})),n.d(t,"d",(function(){return u.f}))},474:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(430),d=n(423),o=n.n(d);t.a=function(e){var t=e.count,n=e.label,u=e.permalink,d=e.style,i=e.value,c=e.valueOnly;return r.a.createElement(a.a,{to:u+"/",className:o()("badge","badge--rounded","badge--"+d)},c?i:n,t&&r.a.createElement(r.a.Fragment,null," (",t,")"))}},475:function(e,t,n){var u=n(476);e.exports=o;var r=Object.hasOwnProperty,a=/\s/g,d=/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~\u2019]/g;function o(){if(!(this instanceof o))return new o;this.reset()}function i(e,t){return"string"!=typeof e?"":(t||(e=e.toLowerCase()),e.trim().replace(d,"").replace(u(),"").replace(a,"-"))}o.prototype.slug=function(e,t){for(var n=i(e,!0===t),u=n;r.call(this.occurrences,n);)this.occurrences[u]++,n=u+"-"+this.occurrences[u];return this.occurrences[n]=0,n},o.prototype.reset=function(){this.occurrences=Object.create(null)},o.slug=i},476:function(e,t){e.exports=function(){return/[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD79\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED0\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3]|\uD83E[\uDD10-\uDD18\uDD80-\uDD84\uDDC0]|\uD83C\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uD83C\uDDFE\uD83C[\uDDEA\uDDF9]|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDFC\uD83C[\uDDEB\uDDF8]|\uD83C\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uD83C\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF8\uDDFE\uDDFF]|\uD83C\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uD83C\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uD83C\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uD83C\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uD83C\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uD83C\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uD83C\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uD83C\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uD83C\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uD83C\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uD83C\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uD83C\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uD83C\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uD83C\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uD83C\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uD83C\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|[#\*0-9]\u20E3/g}},478:function(e,t,n){"use strict";var u=n(471),r=Object.prototype.hasOwnProperty,a=Array.isArray,d=function(){for(var e=[],t=0;t<256;++t)e.push("%"+((t<16?"0":"")+t.toString(16)).toUpperCase());return e}(),o=function(e,t){for(var n=t&&t.plainObjects?Object.create(null):{},u=0;u1;){var t=e.pop(),n=t.obj[t.prop];if(a(n)){for(var u=[],r=0;r=48&&l<=57||l>=65&&l<=90||l>=97&&l<=122||a===u.RFC1738&&(40===l||41===l)?i+=o.charAt(c):l<128?i+=d[l]:l<2048?i+=d[192|l>>6]+d[128|63&l]:l<55296||l>=57344?i+=d[224|l>>12]+d[128|l>>6&63]+d[128|63&l]:(c+=1,l=65536+((1023&l)<<10|1023&o.charCodeAt(c)),i+=d[240|l>>18]+d[128|l>>12&63]+d[128|l>>6&63]+d[128|63&l])}return i},isBuffer:function(e){return!(!e||"object"!=typeof e)&&!!(e.constructor&&e.constructor.isBuffer&&e.constructor.isBuffer(e))},isRegExp:function(e){return"[object RegExp]"===Object.prototype.toString.call(e)},maybeMap:function(e,t){if(a(e)){for(var n=[],u=0;u{if("string"!=typeof e)throw new TypeError("Expected a string");return e=(e=(e=u(e)).toLowerCase().replace(/[_-]+/g," ").replace(/\s{2,}/g," ").trim()).charAt(0).toUpperCase()+e.slice(1)};e.exports=r,e.exports.default=r},485:function(e,t,n){"use strict";var u=n(0),r=n.n(u).a.createContext({isDarkTheme:!1,setLightTheme:function(){},setDarkTheme:function(){}});t.a=r},487:function(e,t,n){"use strict";(function(e){var u=n(1),r=(n(446),n(447),n(78),n(77),n(530),n(0)),a=n.n(r),d=n(531),o=n.n(d),i=n(563),c=n(53),l=n(423),f=n.n(l),s=n(543),p=n.n(s),m=n(532),h=n.n(m),b=n(436),v=n(441),g=n(148),y=n.n(g);(void 0!==e?e:window).Prism=c.a,n(533),n(534),n(535),n(536),n(90),n(537),n(538),n(539),n(540),n(541),n(542);var _=/{([\d,-]+)}/,E=/title=".*"/;t.a=function(e){var t=e.children,n=e.className,d=e.metastring,c=Object(b.a)().siteConfig.themeConfig.prism,l=void 0===c?{}:c,s=Object(r.useState)(!1),m=s[0],g=s[1],w=Object(r.useState)(!1),D=w[0],k=w[1];Object(r.useEffect)((function(){k(!0)}),[]);var x=Object(r.useRef)(null),S=Object(r.useRef)(null),C=[],O="",I=Object(v.a)().isDarkTheme,A=l.theme||p.a,j=l.darkTheme||A,N=I?j:A;if(d&&_.test(d)){var F=d.match(_)[1];C=h.a.parse(F).filter((function(e){return e>0}))}d&&E.test(d)&&(O=d.match(E)[0].split("title=")[1].replace(/"+/g,"")),Object(r.useEffect)((function(){var e;return S.current&&(e=new o.a(S.current,{target:function(){return x.current}})),function(){e&&e.destroy()}}),[S.current,x.current]);var T=n&&n.replace(/language-/,"");!T&&l.defaultLanguage&&(T=l.defaultLanguage);var P=function(){window.getSelection().empty(),g(!0),setTimeout((function(){return g(!1)}),2e3)};return a.a.createElement(i.a,Object(u.a)({},i.b,{key:D,theme:N,code:t.trim(),language:T}),(function(e){var t,n,r=e.className,d=e.style,o=e.tokens,i=e.getLineProps,c=e.getTokenProps;return a.a.createElement(a.a.Fragment,null,O&&a.a.createElement("div",{style:d,className:y.a.codeBlockTitle},O),a.a.createElement("div",{className:y.a.codeBlockContent},a.a.createElement("button",{ref:S,type:"button","aria-label":"Copy code to clipboard",className:f()(y.a.copyButton,(t={},t[y.a.copyButtonWithTitle]=O,t)),onClick:P},m?"Copied":"Copy"),a.a.createElement("pre",{className:f()(r,y.a.codeBlock,(n={},n[y.a.codeBlockWithTitle]=O,n))},a.a.createElement("div",{ref:x,className:y.a.codeBlockLines,style:d},o.map((function(e,t){1===e.length&&""===e[0].content&&(e[0].content="\n");var n=i({line:e,key:t});return C.includes(t+1)&&(n.className=n.className+" docusaurus-highlight-code-line"),a.a.createElement("div",Object(u.a)({key:t},n),e.map((function(e,t){return a.a.createElement("span",Object(u.a)({key:t},c({token:e,key:t})))})))}))))))}))}}).call(this,n(76))},488:function(e,t,n){"use strict";var u=n(0),r=n.n(u);n(424),n(144);t.a=function(e){var t=e.children,n=Object(u.useState)(!1),a=n[0],d=n[1];return a?r.a.createElement("div",{className:"code-explanation code-explanation--expanded"},t,r.a.createElement("div",{className:"code-explanation--toggle",onClick:function(){return d(!a)}},r.a.createElement("i",{className:"feather icon-arrow-up-circle"})," hide")):r.a.createElement("div",{className:"code-explanation code-explanation--collapsed"},r.a.createElement("div",{className:"code-explanation--toggle",onClick:function(){return d(!a)}},r.a.createElement("i",{className:"feather icon-info"})," explain this command"))}},489:function(e,t,n){"use strict";var u=n(30),r=n(12),a=n(27),d=n(91),o=n(92),i=n(26),c=n(545),l=n(93);r(r.S+r.F*!n(83)((function(e){Array.from(e)})),"Array",{from:function(e){var t,n,r,f,s=a(e),p="function"==typeof this?this:Array,m=arguments.length,h=m>1?arguments[1]:void 0,b=void 0!==h,v=0,g=l(s);if(b&&(h=u(h,m>2?arguments[2]:void 0,2)),null==g||p==Array&&o(g))for(n=new p(t=i(s.length));t>v;v++)c(n,v,b?h(s[v],v):s[v]);else for(f=g.call(s),n=new p;!(r=f.next()).done;v++)c(n,v,b?d(f,h,[r.value,v],!0):r.value);return n.length=v,n}})},490:function(e,t,n){"use strict";var u=n(546),r=n(492);e.exports=n(547)("Set",(function(e){return function(){return e(this,arguments.length>0?arguments[0]:void 0)}}),{add:function(e){return u.def(r(this,"Set"),e=0===e?0:e,e)}},u)},491:function(e,t,n){var u=n(40)("meta"),r=n(13),a=n(31),d=n(28).f,o=0,i=Object.isExtensible||function(){return!0},c=!n(14)((function(){return i(Object.preventExtensions({}))})),l=function(e){d(e,u,{value:{i:"O"+ ++o,w:{}}})},f=e.exports={KEY:u,NEED:!1,fastKey:function(e,t){if(!r(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!a(e,u)){if(!i(e))return"F";if(!t)return"E";l(e)}return e[u].i},getWeak:function(e,t){if(!a(e,u)){if(!i(e))return!0;if(!t)return!1;l(e)}return e[u].w},onFreeze:function(e){return c&&f.NEED&&i(e)&&!a(e,u)&&l(e),e}}},492:function(e,t,n){var u=n(13);e.exports=function(e,t){if(!u(e)||e._t!==t)throw TypeError("Incompatible receiver, "+t+" required!");return e}},493:function(e,t,n){"use strict";const u=n(494);e.exports=(e,t)=>{if("string"!=typeof e)throw new TypeError("Expected a string");t=void 0===t?"_":t;const n=u("([\\p{Ll}\\d])(\\p{Lu})","g"),r=u("(\\p{Lu}+)(\\p{Lu}[\\p{Ll}\\d]+)","g");return e.replace(n,`$1${t}$2`).replace(r,`$1${t}$2`).toLowerCase()}},494:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u=f(n(495)),r=f(n(496)),a=f(n(497)),d=f(n(498)),o=f(n(499)),i=f(n(500)),c=f(n(501)),l=f(n(502));function f(e){return e&&e.__esModule?e:{default:e}}(0,r.default)(u.default),(0,a.default)(u.default),(0,d.default)(u.default),(0,o.default)(u.default),(0,i.default)(u.default),(0,c.default)(u.default),(0,l.default)(u.default),t.default=u.default,e.exports=t.default},495:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u={astral:!1},r={exec:RegExp.prototype.exec,test:RegExp.prototype.test,match:String.prototype.match,replace:String.prototype.replace,split:String.prototype.split},a={},d={},o={},i=[],c={default:/\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|\(\?(?:[:=!]|<[=!])|[?*+]\?|{\d+(?:,\d*)?}\??|[\s\S]/,class:/\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|[\s\S]/},l=/\$(?:{([\w$]+)}|<([\w$]+)>|(\d\d?|[\s\S]))/g,f=void 0===r.exec.call(/()??/,"")[1],s=void 0!==/x/.flags,p={}.toString;function m(e){var t=!0;try{new RegExp("",e)}catch(n){t=!1}return t}var h=m("u"),b=m("y"),v={g:!0,i:!0,m:!0,u:h,y:b};function g(e,t,n,u,r){var a=void 0;if(e.xregexp={captureNames:t},r)return e;if(e.__proto__)e.__proto__=j.prototype;else for(a in j.prototype)e[a]=j.prototype[a];return e.xregexp.source=n,e.xregexp.flags=u?u.split("").sort().join(""):u,e}function y(e){return r.replace.call(e,/([\s\S])(?=[\s\S]*\1)/g,"")}function _(e,t){if(!j.isRegExp(e))throw new TypeError("Type RegExp expected");var n=e.xregexp||{},u=function(e){return s?e.flags:r.exec.call(/\/([a-z]*)$/i,RegExp.prototype.toString.call(e))[1]}(e),a="",d="",o=null,i=null;return(t=t||{}).removeG&&(d+="g"),t.removeY&&(d+="y"),d&&(u=r.replace.call(u,new RegExp("["+d+"]+","g"),"")),t.addG&&(a+="g"),t.addY&&(a+="y"),a&&(u=y(u+a)),t.isInternalOnly||(void 0!==n.source&&(o=n.source),null!=n.flags&&(i=a?y(n.flags+a):n.flags)),e=g(new RegExp(t.source||e.source,u),function(e){return!(!e.xregexp||!e.xregexp.captureNames)}(e)?n.captureNames.slice(0):null,o,i,t.isInternalOnly)}function E(e){return parseInt(e,16)}function w(e,t,n){return"("===e.input[e.index-1]||")"===e.input[e.index+e[0].length]||function(e,t,n){return r.test.call(-1!==n.indexOf("x")?/^(?:\s|#[^#\n]*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/:/^(?:\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/,e.slice(t))}(e.input,e.index+e[0].length,n)?"":"(?:)"}function D(e){return parseInt(e,10).toString(16)}function k(e,t){return p.call(e)==="[object "+t+"]"}function x(e){for(;e.length<4;)e="0"+e;return e}function S(e){var t={};return k(e,"String")?(j.forEach(e,/[^\s,]+/,(function(e){t[e]=!0})),t):e}function C(e){if(!/^[\w$]$/.test(e))throw new Error("Flag must be a single character A-Za-z0-9_$");v[e]=!0}function O(e,t,n,u,r){for(var a=i.length,d=e[n],o=null,c=void 0,l=void 0;a--;)if(!((l=i[a]).leadChar&&l.leadChar!==d||l.scope!==u&&"all"!==l.scope||l.flag&&-1===t.indexOf(l.flag))&&(c=j.exec(e,l.regex,n,"sticky"))){o={matchLength:c[0].length,output:l.handler.call(r,c,u,t),reparse:l.reparse};break}return o}function I(e){u.astral=e}function A(e){if(null==e)throw new TypeError("Cannot convert null or undefined to object");return e}function j(e,t){if(j.isRegExp(e)){if(void 0!==t)throw new TypeError("Cannot supply flags when copying a RegExp");return _(e)}if(e=void 0===e?"":String(e),t=void 0===t?"":String(t),j.isInstalled("astral")&&-1===t.indexOf("A")&&(t+="A"),o[e]||(o[e]={}),!o[e][t]){for(var n={hasNamedCapture:!1,captureNames:[]},u="default",a="",d=0,i=void 0,l=function(e,t){var n=void 0;if(y(t)!==t)throw new SyntaxError("Invalid duplicate regex flag "+t);for(e=r.replace.call(e,/^\(\?([\w$]+)\)/,(function(e,n){if(r.test.call(/[gy]/,n))throw new SyntaxError("Cannot use flag g or y in mode modifier "+e);return t=y(t+n),""})),n=0;n"}else if(n)return"\\"+(+n+d);return e}if(!k(e,"Array")||!e.length)throw new TypeError("Must provide a nonempty array of patterns to merge");for(var c=/(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*\]/g,l=[],f=void 0,s=0;s1&&-1!==n.indexOf("")){var u=_(this,{removeG:!0,isInternalOnly:!0});r.replace.call(String(e).slice(n.index),u,(function(){for(var e=arguments.length,t=Array(e),u=0;un.index&&(this.lastIndex=n.index)}return this.global||(this.lastIndex=t),n},a.test=function(e){return!!a.exec.call(this,e)},a.match=function(e){if(j.isRegExp(e)){if(e.global){var t=r.match.apply(this,arguments);return e.lastIndex=0,t}}else e=new RegExp(e);return a.exec.call(e,A(this))},a.replace=function(e,t){var n=j.isRegExp(e),u=void 0,a=void 0,d=void 0;return n?(e.xregexp&&(a=e.xregexp.captureNames),u=e.lastIndex):e+="",d=k(t,"Function")?r.replace.call(String(this),e,(function(){for(var u=arguments.length,r=Array(u),d=0;dn.length-3)throw new SyntaxError("Backreference to undefined group "+e);return n[r]||""}throw new SyntaxError("Invalid token "+e)}})),n&&(e.global?e.lastIndex=0:e.lastIndex=u),d},a.split=function(e,t){if(!j.isRegExp(e))return r.split.apply(this,arguments);var n=String(this),u=[],a=e.lastIndex,d=0,o=void 0;return t=(void 0===t?-1:t)>>>0,j.forEach(n,e,(function(e){e.index+e[0].length>d&&(u.push(n.slice(d,e.index)),e.length>1&&e.indext?u.slice(0,t):u},j.addToken(/\\([ABCE-RTUVXYZaeg-mopqyz]|c(?![A-Za-z])|u(?![\dA-Fa-f]{4}|{[\dA-Fa-f]+})|x(?![\dA-Fa-f]{2}))/,(function(e,t){if("B"===e[1]&&"default"===t)return e[0];throw new SyntaxError("Invalid escape "+e[0])}),{scope:"all",leadChar:"\\"}),j.addToken(/\\u{([\dA-Fa-f]+)}/,(function(e,t,n){var u=E(e[1]);if(u>1114111)throw new SyntaxError("Invalid Unicode code point "+e[0]);if(u<=65535)return"\\u"+x(D(u));if(h&&-1!==n.indexOf("u"))return e[0];throw new SyntaxError("Cannot use Unicode code point above \\u{FFFF} without flag u")}),{scope:"all",leadChar:"\\"}),j.addToken(/\[(\^?)\]/,(function(e){return e[1]?"[\\s\\S]":"\\b\\B"}),{leadChar:"["}),j.addToken(/\(\?#[^)]*\)/,w,{leadChar:"("}),j.addToken(/\s+|#[^\n]*\n?/,w,{flag:"x"}),j.addToken(/\./,(function(){return"[\\s\\S]"}),{flag:"s",leadChar:"."}),j.addToken(/\\k<([\w$]+)>/,(function(e){var t=isNaN(e[1])?this.captureNames.indexOf(e[1])+1:+e[1],n=e.index+e[0].length;if(!t||t>this.captureNames.length)throw new SyntaxError("Backreference to undefined group "+e[0]);return"\\"+t+(n===e.input.length||isNaN(e.input[n])?"":"(?:)")}),{leadChar:"\\"}),j.addToken(/\\(\d+)/,(function(e,t){if(!("default"===t&&/^[1-9]/.test(e[1])&&+e[1]<=this.captureNames.length)&&"0"!==e[1])throw new SyntaxError("Cannot use octal escape or backreference to undefined group "+e[0]);return e[0]}),{scope:"all",leadChar:"\\"}),j.addToken(/\(\?P?<([\w$]+)>/,(function(e){if(!isNaN(e[1]))throw new SyntaxError("Cannot use integer as capture name "+e[0]);if("length"===e[1]||"__proto__"===e[1])throw new SyntaxError("Cannot use reserved word as capture name "+e[0]);if(-1!==this.captureNames.indexOf(e[1]))throw new SyntaxError("Cannot use same name for multiple groups "+e[0]);return this.captureNames.push(e[1]),this.hasNamedCapture=!0,"("}),{leadChar:"("}),j.addToken(/\((?!\?)/,(function(e,t,n){return-1!==n.indexOf("n")?"(?:":(this.captureNames.push(null),"(")}),{optionalFlags:"n",leadChar:"("}),t.default=j,e.exports=t.default},496:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){var t=/(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*\]/g,n=e.union([/\({{([\w$]+)}}\)|{{([\w$]+)}}/,t],"g",{conjunction:"or"});function u(e){var t=/^(?:\(\?:\))*\^/,n=/\$(?:\(\?:\))*$/;return t.test(e)&&n.test(e)&&n.test(e.replace(/\\[\s\S]/g,""))?e.replace(t,"").replace(n,""):e}function r(t,n){var u=n?"x":"";return e.isRegExp(t)?t.xregexp&&t.xregexp.captureNames?t:e(t.source,u):e(t,u)}function a(t){return t instanceof RegExp?t:e.escape(t)}function d(e,t,n){return e["subpattern"+n]=t,e}function o(e,t,n){return e+(t1?u-1:0),i=1;i"):i="(?:",h=m,""+i+l[d].pattern.replace(t,(function(e,t,n){if(t){if(o=l[d].names[m-h],++m,o)return"(?<"+o+">"}else if(n)return c=+n-1,l[d].names[c]?"\\k<"+l[d].names[c]+">":"\\"+(+n+h);return e}))+")"}if(r){if(o=g[b],v[++b]=++m,o)return"(?<"+o+">"}else if(a)return g[c=+a-1]?"\\k<"+g[c]+">":"\\"+v[+a];return e}));return e(y,o)}},e.exports=t.default},497:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){function t(e,t,n,u){return{name:e,value:t,start:n,end:u}}e.matchRecursive=function(n,u,r,a,d){d=d||{};var o=-1!==(a=a||"").indexOf("g"),i=-1!==a.indexOf("y"),c=a.replace(/y/g,""),l=d.escapeChar,f=d.valueNames,s=[],p=0,m=0,h=0,b=0,v=void 0,g=void 0,y=void 0,_=void 0,E=void 0;if(u=e(u,c),r=e(r,c),l){if(l.length>1)throw new Error("Cannot use more than one escape character");l=e.escape(l),E=new RegExp("(?:"+l+"[\\S\\s]|(?:(?!"+e.union([u,r],"",{conjunction:"or"}).source+")[^"+l+"])+)+",a.replace(/[^imu]+/g,""))}for(;;){if(l&&(h+=(e.exec(n,E,h,"sticky")||[""])[0].length),y=e.exec(n,u,h),_=e.exec(n,r,h),y&&_&&(y.index<=_.index?_=null:y=null),y||_)h=(m=(y||_).index)+(y||_)[0].length;else if(!p)break;if(i&&!p&&m>b)break;if(y)p||(v=m,g=h),++p;else{if(!_||!p)throw new Error("Unbalanced delimiter found in string");if(!--p&&(f?(f[0]&&v>b&&s.push(t(f[0],n.slice(b,v),b,v)),f[1]&&s.push(t(f[1],n.slice(v,g),v,g)),f[2]&&s.push(t(f[2],n.slice(g,m),g,m)),f[3]&&s.push(t(f[3],n.slice(m,h),m,h))):s.push(n.slice(g,m)),b=h,!o))break}m===h&&++h}return o&&!i&&f&&f[0]&&n.length>b&&s.push(t(f[0],n.slice(b),b,n.length)),s}},e.exports=t.default},498:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){var t={},n=e._dec,u=e._hex,r=e._pad4;function a(e){return e.replace(/[- _]+/g,"").toLowerCase()}function d(e){var t=/^\\[xu](.+)/.exec(e);return t?n(t[1]):e.charCodeAt("\\"===e[0]?1:0)}function o(n){var a,o,i;return t[n]["b!"]||(t[n]["b!"]=(a=t[n].bmp,o="",i=-1,e.forEach(a,/(\\x..|\\u....|\\?[\s\S])(?:-(\\x..|\\u....|\\?[\s\S]))?/,(function(e){var t=d(e[1]);t>i+1&&(o+="\\u"+r(u(i+1)),t>i+2&&(o+="-\\u"+r(u(t-1)))),i=d(e[2]||e[1])})),i<65535&&(o+="\\u"+r(u(i+1)),i<65534&&(o+="-\\uFFFF")),o))}function i(e,n){var u=n?"a!":"a=";return t[e][u]||(t[e][u]=function(e,n){var u=t[e],r="";return u.bmp&&!u.isBmpLast&&(r="["+u.bmp+"]"+(u.astral?"|":"")),u.astral&&(r+=u.astral),u.isBmpLast&&u.bmp&&(r+=(u.astral?"|":"")+"["+u.bmp+"]"),n?"(?:(?!"+r+")(?:[\ud800-\udbff][\udc00-\udfff]|[\0-\uffff]))":"(?:"+r+")"}(e,n))}e.addToken(/\\([pP])(?:{(\^?)([^}]*)}|([A-Za-z]))/,(function(e,n,u){var r="P"===e[1]||!!e[2],d=-1!==u.indexOf("A"),c=a(e[4]||e[3]),l=t[c];if("P"===e[1]&&e[2])throw new SyntaxError("Invalid double negation "+e[0]);if(!t.hasOwnProperty(c))throw new SyntaxError("Unknown Unicode token "+e[0]);if(l.inverseOf){if(c=a(l.inverseOf),!t.hasOwnProperty(c))throw new ReferenceError("Unicode token missing data "+e[0]+" -> "+l.inverseOf);l=t[c],r=!r}if(!l.bmp&&!d)throw new SyntaxError("Astral mode required for Unicode token "+e[0]);if(d){if("class"===n)throw new SyntaxError("Astral mode does not support Unicode tokens within character classes");return i(c,r)}return"class"===n?r?o(c):l.bmp:(r?"[^":"[")+l.bmp+"]"}),{scope:"all",optionalFlags:"A",leadChar:"\\"}),e.addUnicodeData=function(n){for(var u=void 0,r=0;r\\x5E`\\x7C~\xa2-\xa6\xa8\xa9\xac\xae-\xb1\xb4\xb8\xd7\xf7\u02c2-\u02c5\u02d2-\u02df\u02e5-\u02eb\u02ed\u02ef-\u02ff\u0375\u0384\u0385\u03f6\u0482\u058d-\u058f\u0606-\u0608\u060b\u060e\u060f\u06de\u06e9\u06fd\u06fe\u07f6\u09f2\u09f3\u09fa\u09fb\u0af1\u0b70\u0bf3-\u0bfa\u0c7f\u0d4f\u0d79\u0e3f\u0f01-\u0f03\u0f13\u0f15-\u0f17\u0f1a-\u0f1f\u0f34\u0f36\u0f38\u0fbe-\u0fc5\u0fc7-\u0fcc\u0fce\u0fcf\u0fd5-\u0fd8\u109e\u109f\u1390-\u1399\u17db\u1940\u19de-\u19ff\u1b61-\u1b6a\u1b74-\u1b7c\u1fbd\u1fbf-\u1fc1\u1fcd-\u1fcf\u1fdd-\u1fdf\u1fed-\u1fef\u1ffd\u1ffe\u2044\u2052\u207a-\u207c\u208a-\u208c\u20a0-\u20be\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116-\u2118\u211e-\u2123\u2125\u2127\u2129\u212e\u213a\u213b\u2140-\u2144\u214a-\u214d\u214f\u218a\u218b\u2190-\u2307\u230c-\u2328\u232b-\u23fe\u2400-\u2426\u2440-\u244a\u249c-\u24e9\u2500-\u2767\u2794-\u27c4\u27c7-\u27e5\u27f0-\u2982\u2999-\u29d7\u29dc-\u29fb\u29fe-\u2b73\u2b76-\u2b95\u2b98-\u2bb9\u2bbd-\u2bc8\u2bca-\u2bd1\u2bec-\u2bef\u2ce5-\u2cea\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u2ff0-\u2ffb\u3004\u3012\u3013\u3020\u3036\u3037\u303e\u303f\u309b\u309c\u3190\u3191\u3196-\u319f\u31c0-\u31e3\u3200-\u321e\u322a-\u3247\u3250\u3260-\u327f\u328a-\u32b0\u32c0-\u32fe\u3300-\u33ff\u4dc0-\u4dff\ua490-\ua4c6\ua700-\ua716\ua720\ua721\ua789\ua78a\ua828-\ua82b\ua836-\ua839\uaa77-\uaa79\uab5b\ufb29\ufbb2-\ufbc1\ufdfc\ufdfd\ufe62\ufe64-\ufe66\ufe69\uff04\uff0b\uff1c-\uff1e\uff3e\uff40\uff5c\uff5e\uffe0-\uffe6\uffe8-\uffee\ufffc\ufffd",astral:"\ud800[\udd37-\udd3f\udd79-\udd89\udd8c-\udd8e\udd90-\udd9b\udda0\uddd0-\uddfc]|\ud802[\udc77\udc78\udec8]|\ud805\udf3f|\ud81a[\udf3c-\udf3f\udf45]|\ud82f\udc9c|\ud834[\udc00-\udcf5\udd00-\udd26\udd29-\udd64\udd6a-\udd6c\udd83\udd84\udd8c-\udda9\uddae-\udde8\ude00-\ude41\ude45\udf00-\udf56]|\ud835[\udec1\udedb\udefb\udf15\udf35\udf4f\udf6f\udf89\udfa9\udfc3]|\ud836[\udc00-\uddff\ude37-\ude3a\ude6d-\ude74\ude76-\ude83\ude85\ude86]|\ud83b[\udef0\udef1]|\ud83c[\udc00-\udc2b\udc30-\udc93\udca0-\udcae\udcb1-\udcbf\udcc1-\udccf\udcd1-\udcf5\udd10-\udd2e\udd30-\udd6b\udd70-\uddac\udde6-\ude02\ude10-\ude3b\ude40-\ude48\ude50\ude51\udf00-\udfff]|\ud83d[\udc00-\uded2\udee0-\udeec\udef0-\udef6\udf00-\udf73\udf80-\udfd4]|\ud83e[\udc00-\udc0b\udc10-\udc47\udc50-\udc59\udc60-\udc87\udc90-\udcad\udd10-\udd1e\udd20-\udd27\udd30\udd33-\udd3e\udd40-\udd4b\udd50-\udd5e\udd80-\udd91\uddc0]"},{name:"Sc",alias:"Currency_Symbol",bmp:"\\x24\xa2-\xa5\u058f\u060b\u09f2\u09f3\u09fb\u0af1\u0bf9\u0e3f\u17db\u20a0-\u20be\ua838\ufdfc\ufe69\uff04\uffe0\uffe1\uffe5\uffe6"},{name:"Sk",alias:"Modifier_Symbol",bmp:"\\x5E`\xa8\xaf\xb4\xb8\u02c2-\u02c5\u02d2-\u02df\u02e5-\u02eb\u02ed\u02ef-\u02ff\u0375\u0384\u0385\u1fbd\u1fbf-\u1fc1\u1fcd-\u1fcf\u1fdd-\u1fdf\u1fed-\u1fef\u1ffd\u1ffe\u309b\u309c\ua700-\ua716\ua720\ua721\ua789\ua78a\uab5b\ufbb2-\ufbc1\uff3e\uff40\uffe3",astral:"\ud83c[\udffb-\udfff]"},{name:"Sm",alias:"Math_Symbol",bmp:"\\x2B<->\\x7C~\xac\xb1\xd7\xf7\u03f6\u0606-\u0608\u2044\u2052\u207a-\u207c\u208a-\u208c\u2118\u2140-\u2144\u214b\u2190-\u2194\u219a\u219b\u21a0\u21a3\u21a6\u21ae\u21ce\u21cf\u21d2\u21d4\u21f4-\u22ff\u2320\u2321\u237c\u239b-\u23b3\u23dc-\u23e1\u25b7\u25c1\u25f8-\u25ff\u266f\u27c0-\u27c4\u27c7-\u27e5\u27f0-\u27ff\u2900-\u2982\u2999-\u29d7\u29dc-\u29fb\u29fe-\u2aff\u2b30-\u2b44\u2b47-\u2b4c\ufb29\ufe62\ufe64-\ufe66\uff0b\uff1c-\uff1e\uff5c\uff5e\uffe2\uffe9-\uffec",astral:"\ud835[\udec1\udedb\udefb\udf15\udf35\udf4f\udf6f\udf89\udfa9\udfc3]|\ud83b[\udef0\udef1]"},{name:"So",alias:"Other_Symbol",bmp:"\xa6\xa9\xae\xb0\u0482\u058d\u058e\u060e\u060f\u06de\u06e9\u06fd\u06fe\u07f6\u09fa\u0b70\u0bf3-\u0bf8\u0bfa\u0c7f\u0d4f\u0d79\u0f01-\u0f03\u0f13\u0f15-\u0f17\u0f1a-\u0f1f\u0f34\u0f36\u0f38\u0fbe-\u0fc5\u0fc7-\u0fcc\u0fce\u0fcf\u0fd5-\u0fd8\u109e\u109f\u1390-\u1399\u1940\u19de-\u19ff\u1b61-\u1b6a\u1b74-\u1b7c\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116\u2117\u211e-\u2123\u2125\u2127\u2129\u212e\u213a\u213b\u214a\u214c\u214d\u214f\u218a\u218b\u2195-\u2199\u219c-\u219f\u21a1\u21a2\u21a4\u21a5\u21a7-\u21ad\u21af-\u21cd\u21d0\u21d1\u21d3\u21d5-\u21f3\u2300-\u2307\u230c-\u231f\u2322-\u2328\u232b-\u237b\u237d-\u239a\u23b4-\u23db\u23e2-\u23fe\u2400-\u2426\u2440-\u244a\u249c-\u24e9\u2500-\u25b6\u25b8-\u25c0\u25c2-\u25f7\u2600-\u266e\u2670-\u2767\u2794-\u27bf\u2800-\u28ff\u2b00-\u2b2f\u2b45\u2b46\u2b4d-\u2b73\u2b76-\u2b95\u2b98-\u2bb9\u2bbd-\u2bc8\u2bca-\u2bd1\u2bec-\u2bef\u2ce5-\u2cea\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u2ff0-\u2ffb\u3004\u3012\u3013\u3020\u3036\u3037\u303e\u303f\u3190\u3191\u3196-\u319f\u31c0-\u31e3\u3200-\u321e\u322a-\u3247\u3250\u3260-\u327f\u328a-\u32b0\u32c0-\u32fe\u3300-\u33ff\u4dc0-\u4dff\ua490-\ua4c6\ua828-\ua82b\ua836\ua837\ua839\uaa77-\uaa79\ufdfd\uffe4\uffe8\uffed\uffee\ufffc\ufffd",astral:"\ud800[\udd37-\udd3f\udd79-\udd89\udd8c-\udd8e\udd90-\udd9b\udda0\uddd0-\uddfc]|\ud802[\udc77\udc78\udec8]|\ud805\udf3f|\ud81a[\udf3c-\udf3f\udf45]|\ud82f\udc9c|\ud834[\udc00-\udcf5\udd00-\udd26\udd29-\udd64\udd6a-\udd6c\udd83\udd84\udd8c-\udda9\uddae-\udde8\ude00-\ude41\ude45\udf00-\udf56]|\ud836[\udc00-\uddff\ude37-\ude3a\ude6d-\ude74\ude76-\ude83\ude85\ude86]|\ud83c[\udc00-\udc2b\udc30-\udc93\udca0-\udcae\udcb1-\udcbf\udcc1-\udccf\udcd1-\udcf5\udd10-\udd2e\udd30-\udd6b\udd70-\uddac\udde6-\ude02\ude10-\ude3b\ude40-\ude48\ude50\ude51\udf00-\udffa]|\ud83d[\udc00-\uded2\udee0-\udeec\udef0-\udef6\udf00-\udf73\udf80-\udfd4]|\ud83e[\udc00-\udc0b\udc10-\udc47\udc50-\udc59\udc60-\udc87\udc90-\udcad\udd10-\udd1e\udd20-\udd27\udd30\udd33-\udd3e\udd40-\udd4b\udd50-\udd5e\udd80-\udd91\uddc0]"},{name:"Z",alias:"Separator",bmp:" \xa0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000"},{name:"Zl",alias:"Line_Separator",bmp:"\u2028"},{name:"Zp",alias:"Paragraph_Separator",bmp:"\u2029"},{name:"Zs",alias:"Space_Separator",bmp:" \xa0\u1680\u2000-\u200a\u202f\u205f\u3000"}])},e.exports=t.default},501:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){if(!e.addUnicodeData)throw new ReferenceError("Unicode Base must be loaded before Unicode Properties");var t=[{name:"ASCII",bmp:"\0-\x7f"},{name:"Alphabetic",bmp:"A-Za-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0345\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0561-\u0587\u05b0-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0657\u0659-\u065f\u066e-\u06d3\u06d5-\u06dc\u06e1-\u06e8\u06ed-\u06ef\u06fa-\u06fc\u06ff\u0710-\u073f\u074d-\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0817\u081a-\u082c\u0840-\u0858\u08a0-\u08b4\u08b6-\u08bd\u08d4-\u08df\u08e3-\u08e9\u08f0-\u093b\u093d-\u094c\u094e-\u0950\u0955-\u0963\u0971-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd-\u09c4\u09c7\u09c8\u09cb\u09cc\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09f0\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3e-\u0a42\u0a47\u0a48\u0a4b\u0a4c\u0a51\u0a59-\u0a5c\u0a5e\u0a70-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd-\u0ac5\u0ac7-\u0ac9\u0acb\u0acc\u0ad0\u0ae0-\u0ae3\u0af9\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d-\u0b44\u0b47\u0b48\u0b4b\u0b4c\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcc\u0bd0\u0bd7\u0c00-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4c\u0c55\u0c56\u0c58-\u0c5a\u0c60-\u0c63\u0c80-\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccc\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0cf1\u0cf2\u0d01-\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4c\u0d4e\u0d54-\u0d57\u0d5f-\u0d63\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e46\u0e4d\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ecd\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f71-\u0f81\u0f88-\u0f97\u0f99-\u0fbc\u1000-\u1036\u1038\u103b-\u103f\u1050-\u1062\u1065-\u1068\u106e-\u1086\u108e\u109c\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135f\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1713\u1720-\u1733\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17b3\u17b6-\u17c8\u17d7\u17dc\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191e\u1920-\u192b\u1930-\u1938\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a1b\u1a20-\u1a5e\u1a61-\u1a74\u1aa7\u1b00-\u1b33\u1b35-\u1b43\u1b45-\u1b4b\u1b80-\u1ba9\u1bac-\u1baf\u1bba-\u1be5\u1be7-\u1bf1\u1c00-\u1c35\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1d00-\u1dbf\u1de7-\u1df4\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u24b6-\u24e9\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fd5\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua674-\ua67b\ua67f-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7ae\ua7b0-\ua7b7\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua827\ua840-\ua873\ua880-\ua8c3\ua8c5\ua8f2-\ua8f7\ua8fb\ua8fd\ua90a-\ua92a\ua930-\ua952\ua960-\ua97c\ua980-\ua9b2\ua9b4-\ua9bf\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa36\uaa40-\uaa4d\uaa60-\uaa76\uaa7a\uaa7e-\uaabe\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf5\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab65\uab70-\uabea\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc",astral:"\ud800[\udc00-\udc0b\udc0d-\udc26\udc28-\udc3a\udc3c\udc3d\udc3f-\udc4d\udc50-\udc5d\udc80-\udcfa\udd40-\udd74\ude80-\ude9c\udea0-\uded0\udf00-\udf1f\udf30-\udf4a\udf50-\udf7a\udf80-\udf9d\udfa0-\udfc3\udfc8-\udfcf\udfd1-\udfd5]|\ud801[\udc00-\udc9d\udcb0-\udcd3\udcd8-\udcfb\udd00-\udd27\udd30-\udd63\ude00-\udf36\udf40-\udf55\udf60-\udf67]|\ud802[\udc00-\udc05\udc08\udc0a-\udc35\udc37\udc38\udc3c\udc3f-\udc55\udc60-\udc76\udc80-\udc9e\udce0-\udcf2\udcf4\udcf5\udd00-\udd15\udd20-\udd39\udd80-\uddb7\uddbe\uddbf\ude00-\ude03\ude05\ude06\ude0c-\ude13\ude15-\ude17\ude19-\ude33\ude60-\ude7c\ude80-\ude9c\udec0-\udec7\udec9-\udee4\udf00-\udf35\udf40-\udf55\udf60-\udf72\udf80-\udf91]|\ud803[\udc00-\udc48\udc80-\udcb2\udcc0-\udcf2]|\ud804[\udc00-\udc45\udc82-\udcb8\udcd0-\udce8\udd00-\udd32\udd50-\udd72\udd76\udd80-\uddbf\uddc1-\uddc4\uddda\udddc\ude00-\ude11\ude13-\ude34\ude37\ude3e\ude80-\ude86\ude88\ude8a-\ude8d\ude8f-\ude9d\ude9f-\udea8\udeb0-\udee8\udf00-\udf03\udf05-\udf0c\udf0f\udf10\udf13-\udf28\udf2a-\udf30\udf32\udf33\udf35-\udf39\udf3d-\udf44\udf47\udf48\udf4b\udf4c\udf50\udf57\udf5d-\udf63]|\ud805[\udc00-\udc41\udc43-\udc45\udc47-\udc4a\udc80-\udcc1\udcc4\udcc5\udcc7\udd80-\uddb5\uddb8-\uddbe\uddd8-\udddd\ude00-\ude3e\ude40\ude44\ude80-\udeb5\udf00-\udf19\udf1d-\udf2a]|\ud806[\udca0-\udcdf\udcff\udec0-\udef8]|\ud807[\udc00-\udc08\udc0a-\udc36\udc38-\udc3e\udc40\udc72-\udc8f\udc92-\udca7\udca9-\udcb6]|\ud808[\udc00-\udf99]|\ud809[\udc00-\udc6e\udc80-\udd43]|[\ud80c\ud81c-\ud820\ud840-\ud868\ud86a-\ud86c\ud86f-\ud872][\udc00-\udfff]|\ud80d[\udc00-\udc2e]|\ud811[\udc00-\ude46]|\ud81a[\udc00-\ude38\ude40-\ude5e\uded0-\udeed\udf00-\udf36\udf40-\udf43\udf63-\udf77\udf7d-\udf8f]|\ud81b[\udf00-\udf44\udf50-\udf7e\udf93-\udf9f\udfe0]|\ud821[\udc00-\udfec]|\ud822[\udc00-\udef2]|\ud82c[\udc00\udc01]|\ud82f[\udc00-\udc6a\udc70-\udc7c\udc80-\udc88\udc90-\udc99\udc9e]|\ud835[\udc00-\udc54\udc56-\udc9c\udc9e\udc9f\udca2\udca5\udca6\udca9-\udcac\udcae-\udcb9\udcbb\udcbd-\udcc3\udcc5-\udd05\udd07-\udd0a\udd0d-\udd14\udd16-\udd1c\udd1e-\udd39\udd3b-\udd3e\udd40-\udd44\udd46\udd4a-\udd50\udd52-\udea5\udea8-\udec0\udec2-\udeda\udedc-\udefa\udefc-\udf14\udf16-\udf34\udf36-\udf4e\udf50-\udf6e\udf70-\udf88\udf8a-\udfa8\udfaa-\udfc2\udfc4-\udfcb]|\ud838[\udc00-\udc06\udc08-\udc18\udc1b-\udc21\udc23\udc24\udc26-\udc2a]|\ud83a[\udc00-\udcc4\udd00-\udd43\udd47]|\ud83b[\ude00-\ude03\ude05-\ude1f\ude21\ude22\ude24\ude27\ude29-\ude32\ude34-\ude37\ude39\ude3b\ude42\ude47\ude49\ude4b\ude4d-\ude4f\ude51\ude52\ude54\ude57\ude59\ude5b\ude5d\ude5f\ude61\ude62\ude64\ude67-\ude6a\ude6c-\ude72\ude74-\ude77\ude79-\ude7c\ude7e\ude80-\ude89\ude8b-\ude9b\udea1-\udea3\udea5-\udea9\udeab-\udebb]|\ud83c[\udd30-\udd49\udd50-\udd69\udd70-\udd89]|\ud869[\udc00-\uded6\udf00-\udfff]|\ud86d[\udc00-\udf34\udf40-\udfff]|\ud86e[\udc00-\udc1d\udc20-\udfff]|\ud873[\udc00-\udea1]|\ud87e[\udc00-\ude1d]"},{name:"Any",isBmpLast:!0,bmp:"\0-\uffff",astral:"[\ud800-\udbff][\udc00-\udfff]"},{name:"Default_Ignorable_Code_Point",bmp:"\xad\u034f\u061c\u115f\u1160\u17b4\u17b5\u180b-\u180e\u200b-\u200f\u202a-\u202e\u2060-\u206f\u3164\ufe00-\ufe0f\ufeff\uffa0\ufff0-\ufff8",astral:"\ud82f[\udca0-\udca3]|\ud834[\udd73-\udd7a]|[\udb40-\udb43][\udc00-\udfff]"},{name:"Lowercase",bmp:"a-z\xaa\xb5\xba\xdf-\xf6\xf8-\xff\u0101\u0103\u0105\u0107\u0109\u010b\u010d\u010f\u0111\u0113\u0115\u0117\u0119\u011b\u011d\u011f\u0121\u0123\u0125\u0127\u0129\u012b\u012d\u012f\u0131\u0133\u0135\u0137\u0138\u013a\u013c\u013e\u0140\u0142\u0144\u0146\u0148\u0149\u014b\u014d\u014f\u0151\u0153\u0155\u0157\u0159\u015b\u015d\u015f\u0161\u0163\u0165\u0167\u0169\u016b\u016d\u016f\u0171\u0173\u0175\u0177\u017a\u017c\u017e-\u0180\u0183\u0185\u0188\u018c\u018d\u0192\u0195\u0199-\u019b\u019e\u01a1\u01a3\u01a5\u01a8\u01aa\u01ab\u01ad\u01b0\u01b4\u01b6\u01b9\u01ba\u01bd-\u01bf\u01c6\u01c9\u01cc\u01ce\u01d0\u01d2\u01d4\u01d6\u01d8\u01da\u01dc\u01dd\u01df\u01e1\u01e3\u01e5\u01e7\u01e9\u01eb\u01ed\u01ef\u01f0\u01f3\u01f5\u01f9\u01fb\u01fd\u01ff\u0201\u0203\u0205\u0207\u0209\u020b\u020d\u020f\u0211\u0213\u0215\u0217\u0219\u021b\u021d\u021f\u0221\u0223\u0225\u0227\u0229\u022b\u022d\u022f\u0231\u0233-\u0239\u023c\u023f\u0240\u0242\u0247\u0249\u024b\u024d\u024f-\u0293\u0295-\u02b8\u02c0\u02c1\u02e0-\u02e4\u0345\u0371\u0373\u0377\u037a-\u037d\u0390\u03ac-\u03ce\u03d0\u03d1\u03d5-\u03d7\u03d9\u03db\u03dd\u03df\u03e1\u03e3\u03e5\u03e7\u03e9\u03eb\u03ed\u03ef-\u03f3\u03f5\u03f8\u03fb\u03fc\u0430-\u045f\u0461\u0463\u0465\u0467\u0469\u046b\u046d\u046f\u0471\u0473\u0475\u0477\u0479\u047b\u047d\u047f\u0481\u048b\u048d\u048f\u0491\u0493\u0495\u0497\u0499\u049b\u049d\u049f\u04a1\u04a3\u04a5\u04a7\u04a9\u04ab\u04ad\u04af\u04b1\u04b3\u04b5\u04b7\u04b9\u04bb\u04bd\u04bf\u04c2\u04c4\u04c6\u04c8\u04ca\u04cc\u04ce\u04cf\u04d1\u04d3\u04d5\u04d7\u04d9\u04db\u04dd\u04df\u04e1\u04e3\u04e5\u04e7\u04e9\u04eb\u04ed\u04ef\u04f1\u04f3\u04f5\u04f7\u04f9\u04fb\u04fd\u04ff\u0501\u0503\u0505\u0507\u0509\u050b\u050d\u050f\u0511\u0513\u0515\u0517\u0519\u051b\u051d\u051f\u0521\u0523\u0525\u0527\u0529\u052b\u052d\u052f\u0561-\u0587\u13f8-\u13fd\u1c80-\u1c88\u1d00-\u1dbf\u1e01\u1e03\u1e05\u1e07\u1e09\u1e0b\u1e0d\u1e0f\u1e11\u1e13\u1e15\u1e17\u1e19\u1e1b\u1e1d\u1e1f\u1e21\u1e23\u1e25\u1e27\u1e29\u1e2b\u1e2d\u1e2f\u1e31\u1e33\u1e35\u1e37\u1e39\u1e3b\u1e3d\u1e3f\u1e41\u1e43\u1e45\u1e47\u1e49\u1e4b\u1e4d\u1e4f\u1e51\u1e53\u1e55\u1e57\u1e59\u1e5b\u1e5d\u1e5f\u1e61\u1e63\u1e65\u1e67\u1e69\u1e6b\u1e6d\u1e6f\u1e71\u1e73\u1e75\u1e77\u1e79\u1e7b\u1e7d\u1e7f\u1e81\u1e83\u1e85\u1e87\u1e89\u1e8b\u1e8d\u1e8f\u1e91\u1e93\u1e95-\u1e9d\u1e9f\u1ea1\u1ea3\u1ea5\u1ea7\u1ea9\u1eab\u1ead\u1eaf\u1eb1\u1eb3\u1eb5\u1eb7\u1eb9\u1ebb\u1ebd\u1ebf\u1ec1\u1ec3\u1ec5\u1ec7\u1ec9\u1ecb\u1ecd\u1ecf\u1ed1\u1ed3\u1ed5\u1ed7\u1ed9\u1edb\u1edd\u1edf\u1ee1\u1ee3\u1ee5\u1ee7\u1ee9\u1eeb\u1eed\u1eef\u1ef1\u1ef3\u1ef5\u1ef7\u1ef9\u1efb\u1efd\u1eff-\u1f07\u1f10-\u1f15\u1f20-\u1f27\u1f30-\u1f37\u1f40-\u1f45\u1f50-\u1f57\u1f60-\u1f67\u1f70-\u1f7d\u1f80-\u1f87\u1f90-\u1f97\u1fa0-\u1fa7\u1fb0-\u1fb4\u1fb6\u1fb7\u1fbe\u1fc2-\u1fc4\u1fc6\u1fc7\u1fd0-\u1fd3\u1fd6\u1fd7\u1fe0-\u1fe7\u1ff2-\u1ff4\u1ff6\u1ff7\u2071\u207f\u2090-\u209c\u210a\u210e\u210f\u2113\u212f\u2134\u2139\u213c\u213d\u2146-\u2149\u214e\u2170-\u217f\u2184\u24d0-\u24e9\u2c30-\u2c5e\u2c61\u2c65\u2c66\u2c68\u2c6a\u2c6c\u2c71\u2c73\u2c74\u2c76-\u2c7d\u2c81\u2c83\u2c85\u2c87\u2c89\u2c8b\u2c8d\u2c8f\u2c91\u2c93\u2c95\u2c97\u2c99\u2c9b\u2c9d\u2c9f\u2ca1\u2ca3\u2ca5\u2ca7\u2ca9\u2cab\u2cad\u2caf\u2cb1\u2cb3\u2cb5\u2cb7\u2cb9\u2cbb\u2cbd\u2cbf\u2cc1\u2cc3\u2cc5\u2cc7\u2cc9\u2ccb\u2ccd\u2ccf\u2cd1\u2cd3\u2cd5\u2cd7\u2cd9\u2cdb\u2cdd\u2cdf\u2ce1\u2ce3\u2ce4\u2cec\u2cee\u2cf3\u2d00-\u2d25\u2d27\u2d2d\ua641\ua643\ua645\ua647\ua649\ua64b\ua64d\ua64f\ua651\ua653\ua655\ua657\ua659\ua65b\ua65d\ua65f\ua661\ua663\ua665\ua667\ua669\ua66b\ua66d\ua681\ua683\ua685\ua687\ua689\ua68b\ua68d\ua68f\ua691\ua693\ua695\ua697\ua699\ua69b-\ua69d\ua723\ua725\ua727\ua729\ua72b\ua72d\ua72f-\ua731\ua733\ua735\ua737\ua739\ua73b\ua73d\ua73f\ua741\ua743\ua745\ua747\ua749\ua74b\ua74d\ua74f\ua751\ua753\ua755\ua757\ua759\ua75b\ua75d\ua75f\ua761\ua763\ua765\ua767\ua769\ua76b\ua76d\ua76f-\ua778\ua77a\ua77c\ua77f\ua781\ua783\ua785\ua787\ua78c\ua78e\ua791\ua793-\ua795\ua797\ua799\ua79b\ua79d\ua79f\ua7a1\ua7a3\ua7a5\ua7a7\ua7a9\ua7b5\ua7b7\ua7f8-\ua7fa\uab30-\uab5a\uab5c-\uab65\uab70-\uabbf\ufb00-\ufb06\ufb13-\ufb17\uff41-\uff5a",astral:"\ud801[\udc28-\udc4f\udcd8-\udcfb]|\ud803[\udcc0-\udcf2]|\ud806[\udcc0-\udcdf]|\ud835[\udc1a-\udc33\udc4e-\udc54\udc56-\udc67\udc82-\udc9b\udcb6-\udcb9\udcbb\udcbd-\udcc3\udcc5-\udccf\udcea-\udd03\udd1e-\udd37\udd52-\udd6b\udd86-\udd9f\uddba-\uddd3\uddee-\ude07\ude22-\ude3b\ude56-\ude6f\ude8a-\udea5\udec2-\udeda\udedc-\udee1\udefc-\udf14\udf16-\udf1b\udf36-\udf4e\udf50-\udf55\udf70-\udf88\udf8a-\udf8f\udfaa-\udfc2\udfc4-\udfc9\udfcb]|\ud83a[\udd22-\udd43]"},{name:"Noncharacter_Code_Point",bmp:"\ufdd0-\ufdef\ufffe\uffff",astral:"[\ud83f\ud87f\ud8bf\ud8ff\ud93f\ud97f\ud9bf\ud9ff\uda3f\uda7f\udabf\udaff\udb3f\udb7f\udbbf\udbff][\udffe\udfff]"},{name:"Uppercase",bmp:"A-Z\xc0-\xd6\xd8-\xde\u0100\u0102\u0104\u0106\u0108\u010a\u010c\u010e\u0110\u0112\u0114\u0116\u0118\u011a\u011c\u011e\u0120\u0122\u0124\u0126\u0128\u012a\u012c\u012e\u0130\u0132\u0134\u0136\u0139\u013b\u013d\u013f\u0141\u0143\u0145\u0147\u014a\u014c\u014e\u0150\u0152\u0154\u0156\u0158\u015a\u015c\u015e\u0160\u0162\u0164\u0166\u0168\u016a\u016c\u016e\u0170\u0172\u0174\u0176\u0178\u0179\u017b\u017d\u0181\u0182\u0184\u0186\u0187\u0189-\u018b\u018e-\u0191\u0193\u0194\u0196-\u0198\u019c\u019d\u019f\u01a0\u01a2\u01a4\u01a6\u01a7\u01a9\u01ac\u01ae\u01af\u01b1-\u01b3\u01b5\u01b7\u01b8\u01bc\u01c4\u01c7\u01ca\u01cd\u01cf\u01d1\u01d3\u01d5\u01d7\u01d9\u01db\u01de\u01e0\u01e2\u01e4\u01e6\u01e8\u01ea\u01ec\u01ee\u01f1\u01f4\u01f6-\u01f8\u01fa\u01fc\u01fe\u0200\u0202\u0204\u0206\u0208\u020a\u020c\u020e\u0210\u0212\u0214\u0216\u0218\u021a\u021c\u021e\u0220\u0222\u0224\u0226\u0228\u022a\u022c\u022e\u0230\u0232\u023a\u023b\u023d\u023e\u0241\u0243-\u0246\u0248\u024a\u024c\u024e\u0370\u0372\u0376\u037f\u0386\u0388-\u038a\u038c\u038e\u038f\u0391-\u03a1\u03a3-\u03ab\u03cf\u03d2-\u03d4\u03d8\u03da\u03dc\u03de\u03e0\u03e2\u03e4\u03e6\u03e8\u03ea\u03ec\u03ee\u03f4\u03f7\u03f9\u03fa\u03fd-\u042f\u0460\u0462\u0464\u0466\u0468\u046a\u046c\u046e\u0470\u0472\u0474\u0476\u0478\u047a\u047c\u047e\u0480\u048a\u048c\u048e\u0490\u0492\u0494\u0496\u0498\u049a\u049c\u049e\u04a0\u04a2\u04a4\u04a6\u04a8\u04aa\u04ac\u04ae\u04b0\u04b2\u04b4\u04b6\u04b8\u04ba\u04bc\u04be\u04c0\u04c1\u04c3\u04c5\u04c7\u04c9\u04cb\u04cd\u04d0\u04d2\u04d4\u04d6\u04d8\u04da\u04dc\u04de\u04e0\u04e2\u04e4\u04e6\u04e8\u04ea\u04ec\u04ee\u04f0\u04f2\u04f4\u04f6\u04f8\u04fa\u04fc\u04fe\u0500\u0502\u0504\u0506\u0508\u050a\u050c\u050e\u0510\u0512\u0514\u0516\u0518\u051a\u051c\u051e\u0520\u0522\u0524\u0526\u0528\u052a\u052c\u052e\u0531-\u0556\u10a0-\u10c5\u10c7\u10cd\u13a0-\u13f5\u1e00\u1e02\u1e04\u1e06\u1e08\u1e0a\u1e0c\u1e0e\u1e10\u1e12\u1e14\u1e16\u1e18\u1e1a\u1e1c\u1e1e\u1e20\u1e22\u1e24\u1e26\u1e28\u1e2a\u1e2c\u1e2e\u1e30\u1e32\u1e34\u1e36\u1e38\u1e3a\u1e3c\u1e3e\u1e40\u1e42\u1e44\u1e46\u1e48\u1e4a\u1e4c\u1e4e\u1e50\u1e52\u1e54\u1e56\u1e58\u1e5a\u1e5c\u1e5e\u1e60\u1e62\u1e64\u1e66\u1e68\u1e6a\u1e6c\u1e6e\u1e70\u1e72\u1e74\u1e76\u1e78\u1e7a\u1e7c\u1e7e\u1e80\u1e82\u1e84\u1e86\u1e88\u1e8a\u1e8c\u1e8e\u1e90\u1e92\u1e94\u1e9e\u1ea0\u1ea2\u1ea4\u1ea6\u1ea8\u1eaa\u1eac\u1eae\u1eb0\u1eb2\u1eb4\u1eb6\u1eb8\u1eba\u1ebc\u1ebe\u1ec0\u1ec2\u1ec4\u1ec6\u1ec8\u1eca\u1ecc\u1ece\u1ed0\u1ed2\u1ed4\u1ed6\u1ed8\u1eda\u1edc\u1ede\u1ee0\u1ee2\u1ee4\u1ee6\u1ee8\u1eea\u1eec\u1eee\u1ef0\u1ef2\u1ef4\u1ef6\u1ef8\u1efa\u1efc\u1efe\u1f08-\u1f0f\u1f18-\u1f1d\u1f28-\u1f2f\u1f38-\u1f3f\u1f48-\u1f4d\u1f59\u1f5b\u1f5d\u1f5f\u1f68-\u1f6f\u1fb8-\u1fbb\u1fc8-\u1fcb\u1fd8-\u1fdb\u1fe8-\u1fec\u1ff8-\u1ffb\u2102\u2107\u210b-\u210d\u2110-\u2112\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u2130-\u2133\u213e\u213f\u2145\u2160-\u216f\u2183\u24b6-\u24cf\u2c00-\u2c2e\u2c60\u2c62-\u2c64\u2c67\u2c69\u2c6b\u2c6d-\u2c70\u2c72\u2c75\u2c7e-\u2c80\u2c82\u2c84\u2c86\u2c88\u2c8a\u2c8c\u2c8e\u2c90\u2c92\u2c94\u2c96\u2c98\u2c9a\u2c9c\u2c9e\u2ca0\u2ca2\u2ca4\u2ca6\u2ca8\u2caa\u2cac\u2cae\u2cb0\u2cb2\u2cb4\u2cb6\u2cb8\u2cba\u2cbc\u2cbe\u2cc0\u2cc2\u2cc4\u2cc6\u2cc8\u2cca\u2ccc\u2cce\u2cd0\u2cd2\u2cd4\u2cd6\u2cd8\u2cda\u2cdc\u2cde\u2ce0\u2ce2\u2ceb\u2ced\u2cf2\ua640\ua642\ua644\ua646\ua648\ua64a\ua64c\ua64e\ua650\ua652\ua654\ua656\ua658\ua65a\ua65c\ua65e\ua660\ua662\ua664\ua666\ua668\ua66a\ua66c\ua680\ua682\ua684\ua686\ua688\ua68a\ua68c\ua68e\ua690\ua692\ua694\ua696\ua698\ua69a\ua722\ua724\ua726\ua728\ua72a\ua72c\ua72e\ua732\ua734\ua736\ua738\ua73a\ua73c\ua73e\ua740\ua742\ua744\ua746\ua748\ua74a\ua74c\ua74e\ua750\ua752\ua754\ua756\ua758\ua75a\ua75c\ua75e\ua760\ua762\ua764\ua766\ua768\ua76a\ua76c\ua76e\ua779\ua77b\ua77d\ua77e\ua780\ua782\ua784\ua786\ua78b\ua78d\ua790\ua792\ua796\ua798\ua79a\ua79c\ua79e\ua7a0\ua7a2\ua7a4\ua7a6\ua7a8\ua7aa-\ua7ae\ua7b0-\ua7b4\ua7b6\uff21-\uff3a",astral:"\ud801[\udc00-\udc27\udcb0-\udcd3]|\ud803[\udc80-\udcb2]|\ud806[\udca0-\udcbf]|\ud835[\udc00-\udc19\udc34-\udc4d\udc68-\udc81\udc9c\udc9e\udc9f\udca2\udca5\udca6\udca9-\udcac\udcae-\udcb5\udcd0-\udce9\udd04\udd05\udd07-\udd0a\udd0d-\udd14\udd16-\udd1c\udd38\udd39\udd3b-\udd3e\udd40-\udd44\udd46\udd4a-\udd50\udd6c-\udd85\udda0-\uddb9\uddd4-\udded\ude08-\ude21\ude3c-\ude55\ude70-\ude89\udea8-\udec0\udee2-\udefa\udf1c-\udf34\udf56-\udf6e\udf90-\udfa8\udfca]|\ud83a[\udd00-\udd21]|\ud83c[\udd30-\udd49\udd50-\udd69\udd70-\udd89]"},{name:"White_Space",bmp:"\t-\r \x85\xa0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000"}];t.push({name:"Assigned",inverseOf:"Cn"}),e.addUnicodeData(t)},e.exports=t.default},502:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){if(!e.addUnicodeData)throw new ReferenceError("Unicode Base must be loaded before Unicode Scripts");e.addUnicodeData([{name:"Adlam",astral:"\ud83a[\udd00-\udd4a\udd50-\udd59\udd5e\udd5f]"},{name:"Ahom",astral:"\ud805[\udf00-\udf19\udf1d-\udf2b\udf30-\udf3f]"},{name:"Anatolian_Hieroglyphs",astral:"\ud811[\udc00-\ude46]"},{name:"Arabic",bmp:"\u0600-\u0604\u0606-\u060b\u060d-\u061a\u061e\u0620-\u063f\u0641-\u064a\u0656-\u066f\u0671-\u06dc\u06de-\u06ff\u0750-\u077f\u08a0-\u08b4\u08b6-\u08bd\u08d4-\u08e1\u08e3-\u08ff\ufb50-\ufbc1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfd\ufe70-\ufe74\ufe76-\ufefc",astral:"\ud803[\ude60-\ude7e]|\ud83b[\ude00-\ude03\ude05-\ude1f\ude21\ude22\ude24\ude27\ude29-\ude32\ude34-\ude37\ude39\ude3b\ude42\ude47\ude49\ude4b\ude4d-\ude4f\ude51\ude52\ude54\ude57\ude59\ude5b\ude5d\ude5f\ude61\ude62\ude64\ude67-\ude6a\ude6c-\ude72\ude74-\ude77\ude79-\ude7c\ude7e\ude80-\ude89\ude8b-\ude9b\udea1-\udea3\udea5-\udea9\udeab-\udebb\udef0\udef1]"},{name:"Armenian",bmp:"\u0531-\u0556\u0559-\u055f\u0561-\u0587\u058a\u058d-\u058f\ufb13-\ufb17"},{name:"Avestan",astral:"\ud802[\udf00-\udf35\udf39-\udf3f]"},{name:"Balinese",bmp:"\u1b00-\u1b4b\u1b50-\u1b7c"},{name:"Bamum",bmp:"\ua6a0-\ua6f7",astral:"\ud81a[\udc00-\ude38]"},{name:"Bassa_Vah",astral:"\ud81a[\uded0-\udeed\udef0-\udef5]"},{name:"Batak",bmp:"\u1bc0-\u1bf3\u1bfc-\u1bff"},{name:"Bengali",bmp:"\u0980-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09fb"},{name:"Bhaiksuki",astral:"\ud807[\udc00-\udc08\udc0a-\udc36\udc38-\udc45\udc50-\udc6c]"},{name:"Bopomofo",bmp:"\u02ea\u02eb\u3105-\u312d\u31a0-\u31ba"},{name:"Brahmi",astral:"\ud804[\udc00-\udc4d\udc52-\udc6f\udc7f]"},{name:"Braille",bmp:"\u2800-\u28ff"},{name:"Buginese",bmp:"\u1a00-\u1a1b\u1a1e\u1a1f"},{name:"Buhid",bmp:"\u1740-\u1753"},{name:"Canadian_Aboriginal",bmp:"\u1400-\u167f\u18b0-\u18f5"},{name:"Carian",astral:"\ud800[\udea0-\uded0]"},{name:"Caucasian_Albanian",astral:"\ud801[\udd30-\udd63\udd6f]"},{name:"Chakma",astral:"\ud804[\udd00-\udd34\udd36-\udd43]"},{name:"Cham",bmp:"\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa5c-\uaa5f"},{name:"Cherokee",bmp:"\u13a0-\u13f5\u13f8-\u13fd\uab70-\uabbf"},{name:"Common",bmp:"\0-@\\x5B-`\\x7B-\xa9\xab-\xb9\xbb-\xbf\xd7\xf7\u02b9-\u02df\u02e5-\u02e9\u02ec-\u02ff\u0374\u037e\u0385\u0387\u0589\u0605\u060c\u061b\u061c\u061f\u0640\u06dd\u08e2\u0964\u0965\u0e3f\u0fd5-\u0fd8\u10fb\u16eb-\u16ed\u1735\u1736\u1802\u1803\u1805\u1cd3\u1ce1\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u2000-\u200b\u200e-\u2064\u2066-\u2070\u2074-\u207e\u2080-\u208e\u20a0-\u20be\u2100-\u2125\u2127-\u2129\u212c-\u2131\u2133-\u214d\u214f-\u215f\u2189-\u218b\u2190-\u23fe\u2400-\u2426\u2440-\u244a\u2460-\u27ff\u2900-\u2b73\u2b76-\u2b95\u2b98-\u2bb9\u2bbd-\u2bc8\u2bca-\u2bd1\u2bec-\u2bef\u2e00-\u2e44\u2ff0-\u2ffb\u3000-\u3004\u3006\u3008-\u3020\u3030-\u3037\u303c-\u303f\u309b\u309c\u30a0\u30fb\u30fc\u3190-\u319f\u31c0-\u31e3\u3220-\u325f\u327f-\u32cf\u3358-\u33ff\u4dc0-\u4dff\ua700-\ua721\ua788-\ua78a\ua830-\ua839\ua92e\ua9cf\uab5b\ufd3e\ufd3f\ufe10-\ufe19\ufe30-\ufe52\ufe54-\ufe66\ufe68-\ufe6b\ufeff\uff01-\uff20\uff3b-\uff40\uff5b-\uff65\uff70\uff9e\uff9f\uffe0-\uffe6\uffe8-\uffee\ufff9-\ufffd",astral:"\ud800[\udd00-\udd02\udd07-\udd33\udd37-\udd3f\udd90-\udd9b\uddd0-\uddfc\udee1-\udefb]|\ud82f[\udca0-\udca3]|\ud834[\udc00-\udcf5\udd00-\udd26\udd29-\udd66\udd6a-\udd7a\udd83\udd84\udd8c-\udda9\uddae-\udde8\udf00-\udf56\udf60-\udf71]|\ud835[\udc00-\udc54\udc56-\udc9c\udc9e\udc9f\udca2\udca5\udca6\udca9-\udcac\udcae-\udcb9\udcbb\udcbd-\udcc3\udcc5-\udd05\udd07-\udd0a\udd0d-\udd14\udd16-\udd1c\udd1e-\udd39\udd3b-\udd3e\udd40-\udd44\udd46\udd4a-\udd50\udd52-\udea5\udea8-\udfcb\udfce-\udfff]|\ud83c[\udc00-\udc2b\udc30-\udc93\udca0-\udcae\udcb1-\udcbf\udcc1-\udccf\udcd1-\udcf5\udd00-\udd0c\udd10-\udd2e\udd30-\udd6b\udd70-\uddac\udde6-\uddff\ude01\ude02\ude10-\ude3b\ude40-\ude48\ude50\ude51\udf00-\udfff]|\ud83d[\udc00-\uded2\udee0-\udeec\udef0-\udef6\udf00-\udf73\udf80-\udfd4]|\ud83e[\udc00-\udc0b\udc10-\udc47\udc50-\udc59\udc60-\udc87\udc90-\udcad\udd10-\udd1e\udd20-\udd27\udd30\udd33-\udd3e\udd40-\udd4b\udd50-\udd5e\udd80-\udd91\uddc0]|\udb40[\udc01\udc20-\udc7f]"},{name:"Coptic",bmp:"\u03e2-\u03ef\u2c80-\u2cf3\u2cf9-\u2cff"},{name:"Cuneiform",astral:"\ud808[\udc00-\udf99]|\ud809[\udc00-\udc6e\udc70-\udc74\udc80-\udd43]"},{name:"Cypriot",astral:"\ud802[\udc00-\udc05\udc08\udc0a-\udc35\udc37\udc38\udc3c\udc3f]"},{name:"Cyrillic",bmp:"\u0400-\u0484\u0487-\u052f\u1c80-\u1c88\u1d2b\u1d78\u2de0-\u2dff\ua640-\ua69f\ufe2e\ufe2f"},{name:"Deseret",astral:"\ud801[\udc00-\udc4f]"},{name:"Devanagari",bmp:"\u0900-\u0950\u0953-\u0963\u0966-\u097f\ua8e0-\ua8fd"},{name:"Duployan",astral:"\ud82f[\udc00-\udc6a\udc70-\udc7c\udc80-\udc88\udc90-\udc99\udc9c-\udc9f]"},{name:"Egyptian_Hieroglyphs",astral:"\ud80c[\udc00-\udfff]|\ud80d[\udc00-\udc2e]"},{name:"Elbasan",astral:"\ud801[\udd00-\udd27]"},{name:"Ethiopic",bmp:"\u1200-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u137c\u1380-\u1399\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e"},{name:"Georgian",bmp:"\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u10ff\u2d00-\u2d25\u2d27\u2d2d"},{name:"Glagolitic",bmp:"\u2c00-\u2c2e\u2c30-\u2c5e",astral:"\ud838[\udc00-\udc06\udc08-\udc18\udc1b-\udc21\udc23\udc24\udc26-\udc2a]"},{name:"Gothic",astral:"\ud800[\udf30-\udf4a]"},{name:"Grantha",astral:"\ud804[\udf00-\udf03\udf05-\udf0c\udf0f\udf10\udf13-\udf28\udf2a-\udf30\udf32\udf33\udf35-\udf39\udf3c-\udf44\udf47\udf48\udf4b-\udf4d\udf50\udf57\udf5d-\udf63\udf66-\udf6c\udf70-\udf74]"},{name:"Greek",bmp:"\u0370-\u0373\u0375-\u0377\u037a-\u037d\u037f\u0384\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03e1\u03f0-\u03ff\u1d26-\u1d2a\u1d5d-\u1d61\u1d66-\u1d6a\u1dbf\u1f00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fc4\u1fc6-\u1fd3\u1fd6-\u1fdb\u1fdd-\u1fef\u1ff2-\u1ff4\u1ff6-\u1ffe\u2126\uab65",astral:"\ud800[\udd40-\udd8e\udda0]|\ud834[\ude00-\ude45]"},{name:"Gujarati",bmp:"\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0af1\u0af9"},{name:"Gurmukhi",bmp:"\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75"},{name:"Han",bmp:"\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u3005\u3007\u3021-\u3029\u3038-\u303b\u3400-\u4db5\u4e00-\u9fd5\uf900-\ufa6d\ufa70-\ufad9",astral:"[\ud840-\ud868\ud86a-\ud86c\ud86f-\ud872][\udc00-\udfff]|\ud869[\udc00-\uded6\udf00-\udfff]|\ud86d[\udc00-\udf34\udf40-\udfff]|\ud86e[\udc00-\udc1d\udc20-\udfff]|\ud873[\udc00-\udea1]|\ud87e[\udc00-\ude1d]"},{name:"Hangul",bmp:"\u1100-\u11ff\u302e\u302f\u3131-\u318e\u3200-\u321e\u3260-\u327e\ua960-\ua97c\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uffa0-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc"},{name:"Hanunoo",bmp:"\u1720-\u1734"},{name:"Hatran",astral:"\ud802[\udce0-\udcf2\udcf4\udcf5\udcfb-\udcff]"},{name:"Hebrew",bmp:"\u0591-\u05c7\u05d0-\u05ea\u05f0-\u05f4\ufb1d-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufb4f"},{name:"Hiragana",bmp:"\u3041-\u3096\u309d-\u309f",astral:"\ud82c\udc01|\ud83c\ude00"},{name:"Imperial_Aramaic",astral:"\ud802[\udc40-\udc55\udc57-\udc5f]"},{name:"Inherited",bmp:"\u0300-\u036f\u0485\u0486\u064b-\u0655\u0670\u0951\u0952\u1ab0-\u1abe\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1cf4\u1cf8\u1cf9\u1dc0-\u1df5\u1dfb-\u1dff\u200c\u200d\u20d0-\u20f0\u302a-\u302d\u3099\u309a\ufe00-\ufe0f\ufe20-\ufe2d",astral:"\ud800[\uddfd\udee0]|\ud834[\udd67-\udd69\udd7b-\udd82\udd85-\udd8b\uddaa-\uddad]|\udb40[\udd00-\uddef]"},{name:"Inscriptional_Pahlavi",astral:"\ud802[\udf60-\udf72\udf78-\udf7f]"},{name:"Inscriptional_Parthian",astral:"\ud802[\udf40-\udf55\udf58-\udf5f]"},{name:"Javanese",bmp:"\ua980-\ua9cd\ua9d0-\ua9d9\ua9de\ua9df"},{name:"Kaithi",astral:"\ud804[\udc80-\udcc1]"},{name:"Kannada",bmp:"\u0c80-\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2"},{name:"Katakana",bmp:"\u30a1-\u30fa\u30fd-\u30ff\u31f0-\u31ff\u32d0-\u32fe\u3300-\u3357\uff66-\uff6f\uff71-\uff9d",astral:"\ud82c\udc00"},{name:"Kayah_Li",bmp:"\ua900-\ua92d\ua92f"},{name:"Kharoshthi",astral:"\ud802[\ude00-\ude03\ude05\ude06\ude0c-\ude13\ude15-\ude17\ude19-\ude33\ude38-\ude3a\ude3f-\ude47\ude50-\ude58]"},{name:"Khmer",bmp:"\u1780-\u17dd\u17e0-\u17e9\u17f0-\u17f9\u19e0-\u19ff"},{name:"Khojki",astral:"\ud804[\ude00-\ude11\ude13-\ude3e]"},{name:"Khudawadi",astral:"\ud804[\udeb0-\udeea\udef0-\udef9]"},{name:"Lao",bmp:"\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf"},{name:"Latin",bmp:"A-Za-z\xaa\xba\xc0-\xd6\xd8-\xf6\xf8-\u02b8\u02e0-\u02e4\u1d00-\u1d25\u1d2c-\u1d5c\u1d62-\u1d65\u1d6b-\u1d77\u1d79-\u1dbe\u1e00-\u1eff\u2071\u207f\u2090-\u209c\u212a\u212b\u2132\u214e\u2160-\u2188\u2c60-\u2c7f\ua722-\ua787\ua78b-\ua7ae\ua7b0-\ua7b7\ua7f7-\ua7ff\uab30-\uab5a\uab5c-\uab64\ufb00-\ufb06\uff21-\uff3a\uff41-\uff5a"},{name:"Lepcha",bmp:"\u1c00-\u1c37\u1c3b-\u1c49\u1c4d-\u1c4f"},{name:"Limbu",bmp:"\u1900-\u191e\u1920-\u192b\u1930-\u193b\u1940\u1944-\u194f"},{name:"Linear_A",astral:"\ud801[\ude00-\udf36\udf40-\udf55\udf60-\udf67]"},{name:"Linear_B",astral:"\ud800[\udc00-\udc0b\udc0d-\udc26\udc28-\udc3a\udc3c\udc3d\udc3f-\udc4d\udc50-\udc5d\udc80-\udcfa]"},{name:"Lisu",bmp:"\ua4d0-\ua4ff"},{name:"Lycian",astral:"\ud800[\ude80-\ude9c]"},{name:"Lydian",astral:"\ud802[\udd20-\udd39\udd3f]"},{name:"Mahajani",astral:"\ud804[\udd50-\udd76]"},{name:"Malayalam",bmp:"\u0d01-\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4f\u0d54-\u0d63\u0d66-\u0d7f"},{name:"Mandaic",bmp:"\u0840-\u085b\u085e"},{name:"Manichaean",astral:"\ud802[\udec0-\udee6\udeeb-\udef6]"},{name:"Marchen",astral:"\ud807[\udc70-\udc8f\udc92-\udca7\udca9-\udcb6]"},{name:"Meetei_Mayek",bmp:"\uaae0-\uaaf6\uabc0-\uabed\uabf0-\uabf9"},{name:"Mende_Kikakui",astral:"\ud83a[\udc00-\udcc4\udcc7-\udcd6]"},{name:"Meroitic_Cursive",astral:"\ud802[\udda0-\uddb7\uddbc-\uddcf\uddd2-\uddff]"},{name:"Meroitic_Hieroglyphs",astral:"\ud802[\udd80-\udd9f]"},{name:"Miao",astral:"\ud81b[\udf00-\udf44\udf50-\udf7e\udf8f-\udf9f]"},{name:"Modi",astral:"\ud805[\ude00-\ude44\ude50-\ude59]"},{name:"Mongolian",bmp:"\u1800\u1801\u1804\u1806-\u180e\u1810-\u1819\u1820-\u1877\u1880-\u18aa",astral:"\ud805[\ude60-\ude6c]"},{name:"Mro",astral:"\ud81a[\ude40-\ude5e\ude60-\ude69\ude6e\ude6f]"},{name:"Multani",astral:"\ud804[\ude80-\ude86\ude88\ude8a-\ude8d\ude8f-\ude9d\ude9f-\udea9]"},{name:"Myanmar",bmp:"\u1000-\u109f\ua9e0-\ua9fe\uaa60-\uaa7f"},{name:"Nabataean",astral:"\ud802[\udc80-\udc9e\udca7-\udcaf]"},{name:"New_Tai_Lue",bmp:"\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19da\u19de\u19df"},{name:"Newa",astral:"\ud805[\udc00-\udc59\udc5b\udc5d]"},{name:"Nko",bmp:"\u07c0-\u07fa"},{name:"Ogham",bmp:"\u1680-\u169c"},{name:"Ol_Chiki",bmp:"\u1c50-\u1c7f"},{name:"Old_Hungarian",astral:"\ud803[\udc80-\udcb2\udcc0-\udcf2\udcfa-\udcff]"},{name:"Old_Italic",astral:"\ud800[\udf00-\udf23]"},{name:"Old_North_Arabian",astral:"\ud802[\ude80-\ude9f]"},{name:"Old_Permic",astral:"\ud800[\udf50-\udf7a]"},{name:"Old_Persian",astral:"\ud800[\udfa0-\udfc3\udfc8-\udfd5]"},{name:"Old_South_Arabian",astral:"\ud802[\ude60-\ude7f]"},{name:"Old_Turkic",astral:"\ud803[\udc00-\udc48]"},{name:"Oriya",bmp:"\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b77"},{name:"Osage",astral:"\ud801[\udcb0-\udcd3\udcd8-\udcfb]"},{name:"Osmanya",astral:"\ud801[\udc80-\udc9d\udca0-\udca9]"},{name:"Pahawh_Hmong",astral:"\ud81a[\udf00-\udf45\udf50-\udf59\udf5b-\udf61\udf63-\udf77\udf7d-\udf8f]"},{name:"Palmyrene",astral:"\ud802[\udc60-\udc7f]"},{name:"Pau_Cin_Hau",astral:"\ud806[\udec0-\udef8]"},{name:"Phags_Pa",bmp:"\ua840-\ua877"},{name:"Phoenician",astral:"\ud802[\udd00-\udd1b\udd1f]"},{name:"Psalter_Pahlavi",astral:"\ud802[\udf80-\udf91\udf99-\udf9c\udfa9-\udfaf]"},{name:"Rejang",bmp:"\ua930-\ua953\ua95f"},{name:"Runic",bmp:"\u16a0-\u16ea\u16ee-\u16f8"},{name:"Samaritan",bmp:"\u0800-\u082d\u0830-\u083e"},{name:"Saurashtra",bmp:"\ua880-\ua8c5\ua8ce-\ua8d9"},{name:"Sharada",astral:"\ud804[\udd80-\uddcd\uddd0-\udddf]"},{name:"Shavian",astral:"\ud801[\udc50-\udc7f]"},{name:"Siddham",astral:"\ud805[\udd80-\uddb5\uddb8-\udddd]"},{name:"SignWriting",astral:"\ud836[\udc00-\ude8b\ude9b-\ude9f\udea1-\udeaf]"},{name:"Sinhala",bmp:"\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2-\u0df4",astral:"\ud804[\udde1-\uddf4]"},{name:"Sora_Sompeng",astral:"\ud804[\udcd0-\udce8\udcf0-\udcf9]"},{name:"Sundanese",bmp:"\u1b80-\u1bbf\u1cc0-\u1cc7"},{name:"Syloti_Nagri",bmp:"\ua800-\ua82b"},{name:"Syriac",bmp:"\u0700-\u070d\u070f-\u074a\u074d-\u074f"},{name:"Tagalog",bmp:"\u1700-\u170c\u170e-\u1714"},{name:"Tagbanwa",bmp:"\u1760-\u176c\u176e-\u1770\u1772\u1773"},{name:"Tai_Le",bmp:"\u1950-\u196d\u1970-\u1974"},{name:"Tai_Tham",bmp:"\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa0-\u1aad"},{name:"Tai_Viet",bmp:"\uaa80-\uaac2\uaadb-\uaadf"},{name:"Takri",astral:"\ud805[\ude80-\udeb7\udec0-\udec9]"},{name:"Tamil",bmp:"\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bfa"},{name:"Tangut",astral:"\ud81b\udfe0|[\ud81c-\ud820][\udc00-\udfff]|\ud821[\udc00-\udfec]|\ud822[\udc00-\udef2]"},{name:"Telugu",bmp:"\u0c00-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58-\u0c5a\u0c60-\u0c63\u0c66-\u0c6f\u0c78-\u0c7f"},{name:"Thaana",bmp:"\u0780-\u07b1"},{name:"Thai",bmp:"\u0e01-\u0e3a\u0e40-\u0e5b"},{name:"Tibetan",bmp:"\u0f00-\u0f47\u0f49-\u0f6c\u0f71-\u0f97\u0f99-\u0fbc\u0fbe-\u0fcc\u0fce-\u0fd4\u0fd9\u0fda"},{name:"Tifinagh",bmp:"\u2d30-\u2d67\u2d6f\u2d70\u2d7f"},{name:"Tirhuta",astral:"\ud805[\udc80-\udcc7\udcd0-\udcd9]"},{name:"Ugaritic",astral:"\ud800[\udf80-\udf9d\udf9f]"},{name:"Vai",bmp:"\ua500-\ua62b"},{name:"Warang_Citi",astral:"\ud806[\udca0-\udcf2\udcff]"},{name:"Yi",bmp:"\ua000-\ua48c\ua490-\ua4c6"}])},e.exports=t.default},503:function(e,t,n){"use strict";var u=n(0),r=n.n(u);t.a=function(e){var t=e.text;return r.a.createElement("section",{className:"empty"},r.a.createElement("div",{className:"icon"},r.a.createElement("img",{src:"/img/logo-square.svg",alt:"The Qovery Logo"})),r.a.createElement("div",{className:"text"},t))}},504:function(e,t,n){"use strict";var u=n(505),r=n(515),a=n(471);e.exports={formats:a,parse:r,stringify:u}},505:function(e,t,n){"use strict";var u=n(506),r=n(478),a=n(471),d=Object.prototype.hasOwnProperty,o={brackets:function(e){return e+"[]"},comma:"comma",indices:function(e,t){return e+"["+t+"]"},repeat:function(e){return e}},i=Array.isArray,c=String.prototype.split,l=Array.prototype.push,f=function(e,t){l.apply(e,i(t)?t:[t])},s=Date.prototype.toISOString,p=a.default,m={addQueryPrefix:!1,allowDots:!1,charset:"utf-8",charsetSentinel:!1,delimiter:"&",encode:!0,encoder:r.encode,encodeValuesOnly:!1,format:p,formatter:a.formatters[p],indices:!1,serializeDate:function(e){return s.call(e)},skipNulls:!1,strictNullHandling:!1},h={},b=function e(t,n,a,d,o,l,s,p,b,v,g,y,_,E,w,D){for(var k,x=t,S=D,C=0,O=!1;void 0!==(S=S.get(h))&&!O;){var I=S.get(t);if(C+=1,void 0!==I){if(I===C)throw new RangeError("Cyclic object value");O=!0}void 0===S.get(h)&&(C=0)}if("function"==typeof p?x=p(n,x):x instanceof Date?x=g(x):"comma"===a&&i(x)&&(x=r.maybeMap(x,(function(e){return e instanceof Date?g(e):e}))),null===x){if(o)return s&&!E?s(n,m.encoder,w,"key",y):n;x=""}if("string"==typeof(k=x)||"number"==typeof k||"boolean"==typeof k||"symbol"==typeof k||"bigint"==typeof k||r.isBuffer(x)){if(s){var A=E?n:s(n,m.encoder,w,"key",y);if("comma"===a&&E){for(var j=c.call(String(x),","),N="",F=0;F0?x.join(",")||null:void 0}];else if(i(p))T=p;else{var M=Object.keys(x);T=b?M.sort(b):M}for(var R=d&&i(x)&&1===x.length?n+"[]":n,L=0;L0?E+_:""}},506:function(e,t,n){"use strict";var u=n(469),r=n(511),a=n(513),d=u("%TypeError%"),o=u("%WeakMap%",!0),i=u("%Map%",!0),c=r("WeakMap.prototype.get",!0),l=r("WeakMap.prototype.set",!0),f=r("WeakMap.prototype.has",!0),s=r("Map.prototype.get",!0),p=r("Map.prototype.set",!0),m=r("Map.prototype.has",!0),h=function(e,t){for(var n,u=e;null!==(n=u.next);u=n)if(n.key===t)return u.next=n.next,n.next=e.next,e.next=n,n};e.exports=function(){var e,t,n,u={assert:function(e){if(!u.has(e))throw new d("Side channel does not contain "+a(e))},get:function(u){if(o&&u&&("object"==typeof u||"function"==typeof u)){if(e)return c(e,u)}else if(i){if(t)return s(t,u)}else if(n)return function(e,t){var n=h(e,t);return n&&n.value}(n,u)},has:function(u){if(o&&u&&("object"==typeof u||"function"==typeof u)){if(e)return f(e,u)}else if(i){if(t)return m(t,u)}else if(n)return function(e,t){return!!h(e,t)}(n,u);return!1},set:function(u,r){o&&u&&("object"==typeof u||"function"==typeof u)?(e||(e=new o),l(e,u,r)):i?(t||(t=new i),p(t,u,r)):(n||(n={key:{},next:null}),function(e,t,n){var u=h(e,t);u?u.value=n:e.next={key:t,next:e.next,value:n}}(n,u,r))}};return u}},507:function(e,t,n){"use strict";var u="undefined"!=typeof Symbol&&Symbol,r=n(508);e.exports=function(){return"function"==typeof u&&("function"==typeof Symbol&&("symbol"==typeof u("foo")&&("symbol"==typeof Symbol("bar")&&r())))}},508:function(e,t,n){"use strict";e.exports=function(){if("function"!=typeof Symbol||"function"!=typeof Object.getOwnPropertySymbols)return!1;if("symbol"==typeof Symbol.iterator)return!0;var e={},t=Symbol("test"),n=Object(t);if("string"==typeof t)return!1;if("[object Symbol]"!==Object.prototype.toString.call(t))return!1;if("[object Symbol]"!==Object.prototype.toString.call(n))return!1;for(t in e[t]=42,e)return!1;if("function"==typeof Object.keys&&0!==Object.keys(e).length)return!1;if("function"==typeof Object.getOwnPropertyNames&&0!==Object.getOwnPropertyNames(e).length)return!1;var u=Object.getOwnPropertySymbols(e);if(1!==u.length||u[0]!==t)return!1;if(!Object.prototype.propertyIsEnumerable.call(e,t))return!1;if("function"==typeof Object.getOwnPropertyDescriptor){var r=Object.getOwnPropertyDescriptor(e,t);if(42!==r.value||!0!==r.enumerable)return!1}return!0}},509:function(e,t,n){"use strict";var u="Function.prototype.bind called on incompatible ",r=Array.prototype.slice,a=Object.prototype.toString;e.exports=function(e){var t=this;if("function"!=typeof t||"[object Function]"!==a.call(t))throw new TypeError(u+t);for(var n,d=r.call(arguments,1),o=function(){if(this instanceof n){var u=t.apply(this,d.concat(r.call(arguments)));return Object(u)===u?u:this}return t.apply(e,d.concat(r.call(arguments)))},i=Math.max(0,t.length-d.length),c=[],l=0;l-1?r(n):n}},512:function(e,t,n){"use strict";var u=n(470),r=n(469),a=r("%Function.prototype.apply%"),d=r("%Function.prototype.call%"),o=r("%Reflect.apply%",!0)||u.call(d,a),i=r("%Object.getOwnPropertyDescriptor%",!0),c=r("%Object.defineProperty%",!0),l=r("%Math.max%");if(c)try{c({},"a",{value:1})}catch(s){c=null}e.exports=function(e){var t=o(u,d,arguments);if(i&&c){var n=i(t,"length");n.configurable&&c(t,"length",{value:1+l(0,e.length-(arguments.length-1))})}return t};var f=function(){return o(u,a,arguments)};c?c(e.exports,"apply",{value:f}):e.exports.apply=f},513:function(e,t,n){var u="function"==typeof Map&&Map.prototype,r=Object.getOwnPropertyDescriptor&&u?Object.getOwnPropertyDescriptor(Map.prototype,"size"):null,a=u&&r&&"function"==typeof r.get?r.get:null,d=u&&Map.prototype.forEach,o="function"==typeof Set&&Set.prototype,i=Object.getOwnPropertyDescriptor&&o?Object.getOwnPropertyDescriptor(Set.prototype,"size"):null,c=o&&i&&"function"==typeof i.get?i.get:null,l=o&&Set.prototype.forEach,f="function"==typeof WeakMap&&WeakMap.prototype?WeakMap.prototype.has:null,s="function"==typeof WeakSet&&WeakSet.prototype?WeakSet.prototype.has:null,p="function"==typeof WeakRef&&WeakRef.prototype?WeakRef.prototype.deref:null,m=Boolean.prototype.valueOf,h=Object.prototype.toString,b=Function.prototype.toString,v=String.prototype.match,g=String.prototype.slice,y=String.prototype.replace,_=String.prototype.toUpperCase,E=String.prototype.toLowerCase,w=RegExp.prototype.test,D=Array.prototype.concat,k=Array.prototype.join,x=Array.prototype.slice,S=Math.floor,C="function"==typeof BigInt?BigInt.prototype.valueOf:null,O=Object.getOwnPropertySymbols,I="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?Symbol.prototype.toString:null,A="function"==typeof Symbol&&"object"==typeof Symbol.iterator,j="function"==typeof Symbol&&Symbol.toStringTag&&(typeof Symbol.toStringTag===A||"symbol")?Symbol.toStringTag:null,N=Object.prototype.propertyIsEnumerable,F=("function"==typeof Reflect?Reflect.getPrototypeOf:Object.getPrototypeOf)||([].__proto__===Array.prototype?function(e){return e.__proto__}:null);function T(e,t){if(e===1/0||e===-1/0||e!=e||e&&e>-1e3&&e<1e3||w.call(/e/,t))return t;var n=/[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;if("number"==typeof e){var u=e<0?-S(-e):S(e);if(u!==e){var r=String(u),a=g.call(t,r.length+1);return y.call(r,n,"$&_")+"."+y.call(y.call(a,/([0-9]{3})/g,"$&_"),/_$/,"")}}return y.call(t,n,"$&_")}var P=n(514),M=P.custom,R=W(M)?M:null;function L(e,t,n){var u="double"===(n.quoteStyle||t)?'"':"'";return u+e+u}function B(e){return y.call(String(e),/"/g,""")}function z(e){return!("[object Array]"!==q(e)||j&&"object"==typeof e&&j in e)}function U(e){return!("[object RegExp]"!==q(e)||j&&"object"==typeof e&&j in e)}function W(e){if(A)return e&&"object"==typeof e&&e instanceof Symbol;if("symbol"==typeof e)return!0;if(!e||"object"!=typeof e||!I)return!1;try{return I.call(e),!0}catch(t){}return!1}e.exports=function e(t,n,u,r){var o=n||{};if($(o,"quoteStyle")&&"single"!==o.quoteStyle&&"double"!==o.quoteStyle)throw new TypeError('option "quoteStyle" must be "single" or "double"');if($(o,"maxStringLength")&&("number"==typeof o.maxStringLength?o.maxStringLength<0&&o.maxStringLength!==1/0:null!==o.maxStringLength))throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`');var i=!$(o,"customInspect")||o.customInspect;if("boolean"!=typeof i&&"symbol"!==i)throw new TypeError("option \"customInspect\", if provided, must be `true`, `false`, or `'symbol'`");if($(o,"indent")&&null!==o.indent&&"\t"!==o.indent&&!(parseInt(o.indent,10)===o.indent&&o.indent>0))throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`');if($(o,"numericSeparator")&&"boolean"!=typeof o.numericSeparator)throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`');var h=o.numericSeparator;if(void 0===t)return"undefined";if(null===t)return"null";if("boolean"==typeof t)return t?"true":"false";if("string"==typeof t)return function e(t,n){if(t.length>n.maxStringLength){var u=t.length-n.maxStringLength,r="... "+u+" more character"+(u>1?"s":"");return e(g.call(t,0,n.maxStringLength),n)+r}return L(y.call(y.call(t,/(['\\])/g,"\\$1"),/[\x00-\x1f]/g,V),"single",n)}(t,o);if("number"==typeof t){if(0===t)return 1/0/t>0?"0":"-0";var _=String(t);return h?T(t,_):_}if("bigint"==typeof t){var w=String(t)+"n";return h?T(t,w):w}var S=void 0===o.depth?5:o.depth;if(void 0===u&&(u=0),u>=S&&S>0&&"object"==typeof t)return z(t)?"[Array]":"[Object]";var O=function(e,t){var n;if("\t"===e.indent)n="\t";else{if(!("number"==typeof e.indent&&e.indent>0))return null;n=k.call(Array(e.indent+1)," ")}return{base:n,prev:k.call(Array(t+1),n)}}(o,u);if(void 0===r)r=[];else if(G(r,t)>=0)return"[Circular]";function M(t,n,a){if(n&&(r=x.call(r)).push(n),a){var d={depth:o.depth};return $(o,"quoteStyle")&&(d.quoteStyle=o.quoteStyle),e(t,d,u+1,r)}return e(t,o,u+1,r)}if("function"==typeof t&&!U(t)){var H=function(e){if(e.name)return e.name;var t=v.call(b.call(e),/^function\s*([\w$]+)/);if(t)return t[1];return null}(t),X=Q(t,M);return"[Function"+(H?": "+H:" (anonymous)")+"]"+(X.length>0?" { "+k.call(X,", ")+" }":"")}if(W(t)){var ee=A?y.call(String(t),/^(Symbol\(.*\))_[^)]*$/,"$1"):I.call(t);return"object"!=typeof t||A?ee:K(ee)}if(function(e){if(!e||"object"!=typeof e)return!1;if("undefined"!=typeof HTMLElement&&e instanceof HTMLElement)return!0;return"string"==typeof e.nodeName&&"function"==typeof e.getAttribute}(t)){for(var te="<"+E.call(String(t.nodeName)),ne=t.attributes||[],ue=0;ue"}if(z(t)){if(0===t.length)return"[]";var re=Q(t,M);return O&&!function(e){for(var t=0;t=0)return!1;return!0}(re)?"["+Y(re,O)+"]":"[ "+k.call(re,", ")+" ]"}if(function(e){return!("[object Error]"!==q(e)||j&&"object"==typeof e&&j in e)}(t)){var ae=Q(t,M);return"cause"in Error.prototype||!("cause"in t)||N.call(t,"cause")?0===ae.length?"["+String(t)+"]":"{ ["+String(t)+"] "+k.call(ae,", ")+" }":"{ ["+String(t)+"] "+k.call(D.call("[cause]: "+M(t.cause),ae),", ")+" }"}if("object"==typeof t&&i){if(R&&"function"==typeof t[R]&&P)return P(t,{depth:S-u});if("symbol"!==i&&"function"==typeof t.inspect)return t.inspect()}if(function(e){if(!a||!e||"object"!=typeof e)return!1;try{a.call(e);try{c.call(e)}catch(te){return!0}return e instanceof Map}catch(t){}return!1}(t)){var de=[];return d.call(t,(function(e,n){de.push(M(n,t,!0)+" => "+M(e,t))})),J("Map",a.call(t),de,O)}if(function(e){if(!c||!e||"object"!=typeof e)return!1;try{c.call(e);try{a.call(e)}catch(t){return!0}return e instanceof Set}catch(n){}return!1}(t)){var oe=[];return l.call(t,(function(e){oe.push(M(e,t))})),J("Set",c.call(t),oe,O)}if(function(e){if(!f||!e||"object"!=typeof e)return!1;try{f.call(e,f);try{s.call(e,s)}catch(te){return!0}return e instanceof WeakMap}catch(t){}return!1}(t))return Z("WeakMap");if(function(e){if(!s||!e||"object"!=typeof e)return!1;try{s.call(e,s);try{f.call(e,f)}catch(te){return!0}return e instanceof WeakSet}catch(t){}return!1}(t))return Z("WeakSet");if(function(e){if(!p||!e||"object"!=typeof e)return!1;try{return p.call(e),!0}catch(t){}return!1}(t))return Z("WeakRef");if(function(e){return!("[object Number]"!==q(e)||j&&"object"==typeof e&&j in e)}(t))return K(M(Number(t)));if(function(e){if(!e||"object"!=typeof e||!C)return!1;try{return C.call(e),!0}catch(t){}return!1}(t))return K(M(C.call(t)));if(function(e){return!("[object Boolean]"!==q(e)||j&&"object"==typeof e&&j in e)}(t))return K(m.call(t));if(function(e){return!("[object String]"!==q(e)||j&&"object"==typeof e&&j in e)}(t))return K(M(String(t)));if(!function(e){return!("[object Date]"!==q(e)||j&&"object"==typeof e&&j in e)}(t)&&!U(t)){var ie=Q(t,M),ce=F?F(t)===Object.prototype:t instanceof Object||t.constructor===Object,le=t instanceof Object?"":"null prototype",fe=!ce&&j&&Object(t)===t&&j in t?g.call(q(t),8,-1):le?"Object":"",se=(ce||"function"!=typeof t.constructor?"":t.constructor.name?t.constructor.name+" ":"")+(fe||le?"["+k.call(D.call([],fe||[],le||[]),": ")+"] ":"");return 0===ie.length?se+"{}":O?se+"{"+Y(ie,O)+"}":se+"{ "+k.call(ie,", ")+" }"}return String(t)};var H=Object.prototype.hasOwnProperty||function(e){return e in this};function $(e,t){return H.call(e,t)}function q(e){return h.call(e)}function G(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0,u=e.length;n-1?e.split(","):e},c=function(e,t,n,u){if(e){var a=n.allowDots?e.replace(/\.([^.[]+)/g,"[$1]"):e,d=/(\[[^[\]]*])/g,o=n.depth>0&&/(\[[^[\]]*])/.exec(a),c=o?a.slice(0,o.index):a,l=[];if(c){if(!n.plainObjects&&r.call(Object.prototype,c)&&!n.allowPrototypes)return;l.push(c)}for(var f=0;n.depth>0&&null!==(o=d.exec(a))&&f=0;--a){var d,o=e[a];if("[]"===o&&n.parseArrays)d=[].concat(r);else{d=n.plainObjects?Object.create(null):{};var c="["===o.charAt(0)&&"]"===o.charAt(o.length-1)?o.slice(1,-1):o,l=parseInt(c,10);n.parseArrays||""!==c?!isNaN(l)&&o!==c&&String(l)===c&&l>=0&&n.parseArrays&&l<=n.arrayLimit?(d=[])[l]=r:"__proto__"!==c&&(d[c]=r):d={0:r}}r=d}return r}(l,t,n,u)}};e.exports=function(e,t){var n=function(e){if(!e)return d;if(null!==e.decoder&&void 0!==e.decoder&&"function"!=typeof e.decoder)throw new TypeError("Decoder has to be a function.");if(void 0!==e.charset&&"utf-8"!==e.charset&&"iso-8859-1"!==e.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var t=void 0===e.charset?d.charset:e.charset;return{allowDots:void 0===e.allowDots?d.allowDots:!!e.allowDots,allowPrototypes:"boolean"==typeof e.allowPrototypes?e.allowPrototypes:d.allowPrototypes,allowSparse:"boolean"==typeof e.allowSparse?e.allowSparse:d.allowSparse,arrayLimit:"number"==typeof e.arrayLimit?e.arrayLimit:d.arrayLimit,charset:t,charsetSentinel:"boolean"==typeof e.charsetSentinel?e.charsetSentinel:d.charsetSentinel,comma:"boolean"==typeof e.comma?e.comma:d.comma,decoder:"function"==typeof e.decoder?e.decoder:d.decoder,delimiter:"string"==typeof e.delimiter||u.isRegExp(e.delimiter)?e.delimiter:d.delimiter,depth:"number"==typeof e.depth||!1===e.depth?+e.depth:d.depth,ignoreQueryPrefix:!0===e.ignoreQueryPrefix,interpretNumericEntities:"boolean"==typeof e.interpretNumericEntities?e.interpretNumericEntities:d.interpretNumericEntities,parameterLimit:"number"==typeof e.parameterLimit?e.parameterLimit:d.parameterLimit,parseArrays:!1!==e.parseArrays,plainObjects:"boolean"==typeof e.plainObjects?e.plainObjects:d.plainObjects,strictNullHandling:"boolean"==typeof e.strictNullHandling?e.strictNullHandling:d.strictNullHandling}}(t);if(""===e||null==e)return n.plainObjects?Object.create(null):{};for(var l="string"==typeof e?function(e,t){var n,c={},l=t.ignoreQueryPrefix?e.replace(/^\?/,""):e,f=t.parameterLimit===1/0?void 0:t.parameterLimit,s=l.split(t.delimiter,f),p=-1,m=t.charset;if(t.charsetSentinel)for(n=0;n-1&&(b=a(b)?[b]:b),r.call(c,h)?c[h]=u.combine(c[h],b):c[h]=b}return c}(e,n):e,f=n.plainObjects?Object.create(null):{},s=Object.keys(l),p=0;p'},heart:{width:12,height:16,path:''},eye:{width:16,height:16,path:''},star:{width:14,height:16,path:''},"repo-forked":{width:10,height:16,path:''},"repo-template":{width:14,height:16,path:''},"issue-opened":{width:14,height:16,path:''},"cloud-download":{width:16,height:16,path:''}},g={},y=function(e,t){var n=g[e]||(g[e]=[]);if(!(n.push(t)>1)){var u=function(e){var t;return function(){t||(t=1,e.apply(this,arguments))}}((function(){for(delete g[e];t=n.shift();)t.apply(null,arguments)}));if(l){var r=new d;s(r,"abort",u),s(r,"error",u),s(r,"load",(function(){var e;try{e=JSON.parse(r.responseText)}catch(t){return void u(t)}u(200!==r.status,e)})),r.open("GET",e),r.send()}else{var a=this||window;a._=function(e){a._=null,u(200!==e.meta.status,e.data)};var i=o(a.document)("script",{async:!0,src:e+(/\?/.test(e)?"&":"?")+"callback=_"}),c=function(){a._&&a._({meta:{}})};s(i,"load",c),s(i,"error",c),i.readyState&&function(e,t,n){var u=function(r){if(t.test(e.readyState))return p(e,"readystatechange",u),n(r)};s(e,"readystatechange",u)}(i,/de|m/,c),a.document.getElementsByTagName("head")[0].appendChild(i)}}},E=function(e,t,n){var u=o(e.ownerDocument),r=e.appendChild(u("style",{type:"text/css"})),a="body{margin:0}a{text-decoration:none;outline:0}.widget{display:inline-block;overflow:hidden;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif;font-size:0;white-space:nowrap}.btn,.social-count{position:relative;display:inline-block;height:14px;padding:2px 5px;font-size:11px;font-weight:600;line-height:14px;vertical-align:bottom;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-repeat:repeat-x;background-position:-1px -1px;background-size:110% 110%;border:1px solid}.btn{border-radius:.25em}.btn:not(:last-child){border-radius:.25em 0 0 .25em}.social-count{border-left:0;border-radius:0 .25em .25em 0}.widget-lg .btn,.widget-lg .social-count{height:20px;padding:3px 10px;font-size:12px;line-height:20px}.octicon{display:inline-block;vertical-align:text-top;fill:currentColor}"+b(t["data-color-scheme"]);r.styleSheet?r.styleSheet.cssText=a:r.appendChild(e.ownerDocument.createTextNode(a));var d,i,l=u("a",{className:"btn",href:t.href,target:"_blank",rel:"noopener",innerHTML:(d=t["data-icon"],i=/^large$/i.test(t["data-size"])?16:14,d=(""+d).toLowerCase().replace(/^octicon-/,""),c(v,d)||(d="mark-github"),'"),"aria-label":t["aria-label"]||void 0},[" ",u("span",{},[t["data-text"]||""])]),f=e.appendChild(u("div",{className:"widget"+(/^large$/i.test(t["data-size"])?" widget-lg":"")},[l])),s=l.hostname.split(".").reverse();if(""===s[0]&&s.shift(),"com"!==s[0]||"github"!==s[1])return l.href="#",l.target="_self",void n(f);var p=s.length,m=(" /"+l.pathname).split(/\/+/);if(((2===p||3===p&&"gist"===s[2])&&"archive"===m[3]||2===p&&"releases"===m[3]&&"download"===m[4]||3===p&&"codeload"===s[2])&&(l.target="_top"),/^true$/i.test(t["data-show-count"])&&2===p){var h,g;if(!m[2]&&m[1])h=g="followers";else if(!m[3]&&m[2])g="stargazers_count",h="stargazers";else if(m[4]||"subscription"!==m[3])if(m[4]||"fork"!==m[3]){if("issues"!==m[3])return void n(f);g="open_issues_count",h="issues"}else g="forks_count",h="network/members";else g="subscribers_count",h="watchers";var _=m[2]?"/repos/"+m[1]+"/"+m[2]:"/users/"+m[1];y.call(this,"https://api.github.com"+_,(function(e,t){if(!e){var r=t[g];f.appendChild(u("a",{className:"social-count",href:t.html_url+"/"+h,target:"_blank",rel:"noopener","aria-label":r+" "+g.replace(/_count$/,"").replace("_"," ").slice(0,r<2?-1:void 0)+" on GitHub"},[(""+r).replace(/\B(?=(\d{3})+(?!\d))/g,",")]))}n(f)}))}else n(f)},w=window.devicePixelRatio||1,D=function(e){return(w>1?r.ceil(r.round(e*w)/w*2)/2:r.ceil(e))||0},k=function(e,t){e.style.width=t[0]+"px",e.style.height=t[1]+"px"},x=function(e,t){if(null!=e&&null!=t)if(e.getAttribute&&(e=function(e){for(var t={href:e.href,title:e.title,"aria-label":e.getAttribute("aria-label")},n=["icon","color-scheme","text","size","show-count"],u=0,r=n.length;u0){var n=t[0];return{x:n.clientX,y:n.clientY}}var u=e.pageX;if(void 0!==u)return{x:u,y:e.pageY}}return{x:0,y:0}}},527:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(430),d=n(423),o=n.n(d);n(147);t.a=function(e){var t=e.className,n=e.previous,u=e.next;return r.a.createElement("nav",{className:o()("pagination-nav",t)},r.a.createElement("div",{className:"pagination-nav__item"},n&&r.a.createElement(a.a,{className:"pagination-nav__link",to:n.permalink},r.a.createElement("h5",{className:"pagination-nav__link--sublabel"},"Previous"),r.a.createElement("h4",{className:"pagination-nav__link--label"},"\xab ",n.title))),r.a.createElement("div",{className:"pagination-nav__item pagination-nav__item--next"},u&&r.a.createElement(a.a,{className:"pagination-nav__link",to:u.permalink},r.a.createElement("h5",{className:"pagination-nav__link--sublabel"},"Next"),r.a.createElement("h4",{className:"pagination-nav__link--label"},u.title," \xbb"))))}},528:function(e,t,n){"use strict";var u=n(0);t.a=function(e,t,n){var r=Object(u.useState)(void 0),a=r[0],d=r[1];Object(u.useEffect)((function(){var u=[],r=[];function o(){var o=function(){var e=0,t=null;for(u=document.getElementsByClassName("anchor");e=0&&a<=n&&(t=r),e+=1}return t}();if(o){var i=0,c=!1;for(r=document.getElementsByClassName(e);i0&&void 0!==arguments[0]?arguments[0]:{};this.action=e.action,this.container=e.container,this.emitter=e.emitter,this.target=e.target,this.text=e.text,this.trigger=e.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function(){var e=this,t="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return e.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[t?"right":"left"]="-9999px";var n=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.style.top=n+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.container.appendChild(this.fakeElem),this.selectedText=r()(this.fakeElem),this.copyText()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=r()(this.target),this.copyText()}},{key:"copyText",value:function(){var e=void 0;try{e=document.execCommand(this.action)}catch(t){e=!1}this.handleResult(e)}},{key:"handleResult",value:function(e){this.emitter.emit(e?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),document.activeElement.blur(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=e,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(e){if(void 0!==e){if(!e||"object"!==(void 0===e?"undefined":a(e))||1!==e.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&e.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(e.hasAttribute("readonly")||e.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=e}},get:function(){return this._target}}]),e}(),i=n(1),c=n.n(i),l=n(2),f=n.n(l),s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},p=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof e.action?e.action:this.defaultAction,this.target="function"==typeof e.target?e.target:this.defaultTarget,this.text="function"==typeof e.text?e.text:this.defaultText,this.container="object"===s(e.container)?e.container:document.body}},{key:"listenClick",value:function(e){var t=this;this.listener=f()(e,"click",(function(e){return t.onClick(e)}))}},{key:"onClick",value:function(e){var t=e.delegateTarget||e.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new o({action:this.action(t),target:this.target(t),text:this.text(t),container:this.container,trigger:t,emitter:this})}},{key:"defaultAction",value:function(e){return h("action",e)}},{key:"defaultTarget",value:function(e){var t=h("target",e);if(t)return document.querySelector(t)}},{key:"defaultText",value:function(e){return h("text",e)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["copy","cut"],t="string"==typeof e?[e]:e,n=!!document.queryCommandSupported;return t.forEach((function(e){n=n&&!!document.queryCommandSupported(e)})),n}}]),t}(c.a);function h(e,t){var n="data-clipboard-"+e;if(t.hasAttribute(n))return t.getAttribute(n)}t.default=m}]).default},e.exports=u()},532:function(e,t){e.exports.parse=function(e){var t=e.split(",").map((function(e){return function(e){if(/^-?\d+$/.test(e))return parseInt(e,10);var t;if(t=e.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){var n=t[1],u=t[2],r=t[3];if(n&&r){var a=[],d=(n=parseInt(n))<(r=parseInt(r))?1:-1;"-"!=u&&".."!=u&&"\u2025"!=u||(r+=d);for(var o=n;o!=r;o+=d)a.push(o);return a}}return[]}(e)}));return 0===t.length?[]:1===t.length?Array.isArray(t[0])?t[0]:t:t.reduce((function(e,t){return Array.isArray(e)||(e=[e]),Array.isArray(t)||(t=[t]),e.concat(t)}))}},533:function(e,t){!function(e){function t(e){return RegExp("(^(?:"+e+"):[ \t]*(?![ \t]))[^]+","i")}e.languages.http={"request-line":{pattern:/^(?:CONNECT|DELETE|GET|HEAD|OPTIONS|PATCH|POST|PRI|PUT|SEARCH|TRACE)\s(?:https?:\/\/|\/)\S*\sHTTP\/[\d.]+/m,inside:{method:{pattern:/^[A-Z]+\b/,alias:"property"},"request-target":{pattern:/^(\s)(?:https?:\/\/|\/)\S*(?=\s)/,lookbehind:!0,alias:"url",inside:e.languages.uri},"http-version":{pattern:/^(\s)HTTP\/[\d.]+/,lookbehind:!0,alias:"property"}}},"response-status":{pattern:/^HTTP\/[\d.]+ \d+ .+/m,inside:{"http-version":{pattern:/^HTTP\/[\d.]+/,alias:"property"},"status-code":{pattern:/^(\s)\d+(?=\s)/,lookbehind:!0,alias:"number"},"reason-phrase":{pattern:/^(\s).+/,lookbehind:!0,alias:"string"}}},header:{pattern:/^[\w-]+:.+(?:(?:\r\n?|\n)[ \t].+)*/m,inside:{"header-value":[{pattern:t(/Content-Security-Policy/.source),lookbehind:!0,alias:["csp","languages-csp"],inside:e.languages.csp},{pattern:t(/Public-Key-Pins(?:-Report-Only)?/.source),lookbehind:!0,alias:["hpkp","languages-hpkp"],inside:e.languages.hpkp},{pattern:t(/Strict-Transport-Security/.source),lookbehind:!0,alias:["hsts","languages-hsts"],inside:e.languages.hsts},{pattern:t(/[^:]+/.source),lookbehind:!0}],"header-name":{pattern:/^[^:]+/,alias:"keyword"},punctuation:/^:/}}};var n,u=e.languages,r={"application/javascript":u.javascript,"application/json":u.json||u.javascript,"application/xml":u.xml,"text/xml":u.xml,"text/html":u.html,"text/css":u.css,"text/plain":u.plain},a={"application/json":!0,"application/xml":!0};function d(e){var t=e.replace(/^[a-z]+\//,"");return"(?:"+e+"|"+("\\w+/(?:[\\w.-]+\\+)+"+t+"(?![+\\w.-])")+")"}for(var o in r)if(r[o]){n=n||{};var i=a[o]?d(o):o;n[o.replace(/\//g,"-")]={pattern:RegExp("("+/content-type:\s*/.source+i+/(?:(?:\r\n?|\n)[\w-].*)*(?:\r(?:\n|(?!\n))|\n)/.source+")"+/[^ \t\w-][\s\S]*/.source,"i"),lookbehind:!0,inside:r[o]}}n&&e.languages.insertBefore("http","header",n)}(Prism)},534:function(e,t){Prism.languages.lua={comment:/^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,string:{pattern:/(["'])(?:(?!\1)[^\\\r\n]|\\z(?:\r\n|\s)|\\(?:\r\n|[^z]))*\1|\[(=*)\[[\s\S]*?\]\2\]/,greedy:!0},number:/\b0x[a-f\d]+(?:\.[a-f\d]*)?(?:p[+-]?\d+)?\b|\b\d+(?:\.\B|(?:\.\d*)?(?:e[+-]?\d+)?\b)|\B\.\d+(?:e[+-]?\d+)?\b/i,keyword:/\b(?:and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,function:/(?!\d)\w+(?=\s*(?:[({]))/,operator:[/[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,{pattern:/(^|[^.])\.\.(?!\.)/,lookbehind:!0}],punctuation:/[\[\](){},;]|\.+|:+/}},535:function(e,t){!function(e){var t=e.languages.powershell={comment:[{pattern:/(^|[^`])<#[\s\S]*?#>/,lookbehind:!0},{pattern:/(^|[^`])#.*/,lookbehind:!0}],string:[{pattern:/"(?:`[\s\S]|[^`"])*"/,greedy:!0,inside:null},{pattern:/'(?:[^']|'')*'/,greedy:!0}],namespace:/\[[a-z](?:\[(?:\[[^\]]*\]|[^\[\]])*\]|[^\[\]])*\]/i,boolean:/\$(?:false|true)\b/i,variable:/\$\w+\b/,function:[/\b(?:Add|Approve|Assert|Backup|Block|Checkpoint|Clear|Close|Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom|ConvertTo|Copy|Debug|Deny|Disable|Disconnect|Dismount|Edit|Enable|Enter|Exit|Expand|Export|Find|ForEach|Format|Get|Grant|Group|Hide|Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push|Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset|Resize|Resolve|Restart|Restore|Resume|Revoke|Save|Search|Select|Send|Set|Show|Skip|Sort|Split|Start|Step|Stop|Submit|Suspend|Switch|Sync|Tee|Test|Trace|Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish|Unregister|Update|Use|Wait|Watch|Where|Write)-[a-z]+\b/i,/\b(?:ac|cat|chdir|clc|cli|clp|clv|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|ebp|echo|epal|epcsv|epsn|erase|fc|fl|ft|fw|gal|gbp|gc|gci|gcs|gdr|gi|gl|gm|gp|gps|group|gsv|gu|gv|gwmi|iex|ii|ipal|ipcsv|ipsn|irm|iwmi|iwr|kill|lp|ls|measure|mi|mount|move|mp|mv|nal|ndr|ni|nv|ogv|popd|ps|pushd|pwd|rbp|rd|rdr|ren|ri|rm|rmdir|rni|rnp|rp|rv|rvpa|rwmi|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spps|spsv|start|sv|swmi|tee|trcm|type|write)\b/i],keyword:/\b(?:Begin|Break|Catch|Class|Continue|Data|Define|Do|DynamicParam|Else|ElseIf|End|Exit|Filter|Finally|For|ForEach|From|Function|If|InlineScript|Parallel|Param|Process|Return|Sequence|Switch|Throw|Trap|Try|Until|Using|Var|While|Workflow)\b/i,operator:{pattern:/(^|\W)(?:!|-(?:b?(?:and|x?or)|as|(?:Not)?(?:Contains|In|Like|Match)|eq|ge|gt|is(?:Not)?|Join|le|lt|ne|not|Replace|sh[lr])\b|-[-=]?|\+[+=]?|[*\/%]=?)/i,lookbehind:!0},punctuation:/[|{}[\];(),.]/};t.string[0].inside={function:{pattern:/(^|[^`])\$\((?:\$\([^\r\n()]*\)|(?!\$\()[^\r\n)])*\)/,lookbehind:!0,inside:t},boolean:t.boolean,variable:t.variable}}(Prism)},536:function(e,t){!function(e){var t=/\b(?:bool|bytes|double|s?fixed(?:32|64)|float|[su]?int(?:32|64)|string)\b/;e.languages.protobuf=e.languages.extend("clike",{"class-name":[{pattern:/(\b(?:enum|extend|message|service)\s+)[A-Za-z_]\w*(?=\s*\{)/,lookbehind:!0},{pattern:/(\b(?:rpc\s+\w+|returns)\s*\(\s*(?:stream\s+)?)\.?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*(?=\s*\))/,lookbehind:!0}],keyword:/\b(?:enum|extend|extensions|import|message|oneof|option|optional|package|public|repeated|required|reserved|returns|rpc(?=\s+\w)|service|stream|syntax|to)\b(?!\s*=\s*\d)/,function:/\b[a-z_]\w*(?=\s*\()/i}),e.languages.insertBefore("protobuf","operator",{map:{pattern:/\bmap<\s*[\w.]+\s*,\s*[\w.]+\s*>(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/[<>.,]/,builtin:t}},builtin:t,"positional-class-name":{pattern:/(?:\b|\B\.)[a-z_]\w*(?:\.[a-z_]\w*)*(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/\./}},annotation:{pattern:/(\[\s*)[a-z_]\w*(?=\s*=)/i,lookbehind:!0}})}(Prism)},537:function(e,t){!function(e){var t=/(?:[\w-]+|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*")/.source;function n(e){return e.replace(/__/g,(function(){return t}))}e.languages.toml={comment:{pattern:/#.*/,greedy:!0},table:{pattern:RegExp(n(/(^[\t ]*\[\s*(?:\[\s*)?)__(?:\s*\.\s*__)*(?=\s*\])/.source),"m"),lookbehind:!0,greedy:!0,alias:"class-name"},key:{pattern:RegExp(n(/(^[\t ]*|[{,]\s*)__(?:\s*\.\s*__)*(?=\s*=)/.source),"m"),lookbehind:!0,greedy:!0,alias:"property"},string:{pattern:/"""(?:\\[\s\S]|[^\\])*?"""|'''[\s\S]*?'''|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},date:[{pattern:/\b\d{4}-\d{2}-\d{2}(?:[T\s]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?\b/i,alias:"number"},{pattern:/\b\d{2}:\d{2}:\d{2}(?:\.\d+)?\b/,alias:"number"}],number:/(?:\b0(?:x[\da-zA-Z]+(?:_[\da-zA-Z]+)*|o[0-7]+(?:_[0-7]+)*|b[10]+(?:_[10]+)*))\b|[-+]?\b\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?\b|[-+]?\b(?:inf|nan)\b/,boolean:/\b(?:false|true)\b/,punctuation:/[.,=[\]{}]/}}(Prism)},538:function(e,t){!function(e){e.languages.kotlin=e.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,lookbehind:!0},function:[{pattern:/(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/,greedy:!0},{pattern:/(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/,lookbehind:!0,greedy:!0}],number:/\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete e.languages.kotlin["class-name"];var t={"interpolation-punctuation":{pattern:/^\$\{?|\}$/,alias:"punctuation"},expression:{pattern:/[\s\S]+/,inside:e.languages.kotlin}};e.languages.insertBefore("kotlin","string",{"string-literal":[{pattern:/"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/,alias:"multiline",inside:{interpolation:{pattern:/\$(?:[a-z_]\w*|\{[^{}]*\})/i,inside:t},string:/[\s\S]+/}},{pattern:/"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/,alias:"singleline",inside:{interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i,lookbehind:!0,inside:t},string:/[\s\S]+/}}],char:{pattern:/'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/,greedy:!0}}),delete e.languages.kotlin.string,e.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),e.languages.insertBefore("kotlin","function",{label:{pattern:/\b\w+@|@\w+\b/,alias:"symbol"}}),e.languages.kt=e.languages.kotlin,e.languages.kts=e.languages.kotlin}(Prism)},539:function(e,t){!function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,n=/(^|[^\w.])(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source,u={pattern:RegExp(n+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}};e.languages.java=e.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,lookbehind:!0,greedy:!0},"class-name":[u,{pattern:RegExp(n+/[A-Z]\w*(?=\s+\w+\s*[;,=()])/.source),lookbehind:!0,inside:u.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"},char:{pattern:/'(?:\\.|[^'\\\r\n]){1,6}'/,greedy:!0}}),e.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":u,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},namespace:{pattern:RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(//g,(function(){return t.source}))),lookbehind:!0,inside:{punctuation:/\./}}})}(Prism)},540:function(e,t){Prism.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},Prism.languages.python["string-interpolation"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python},541:function(e,t){!function(e){var t=/\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/,n=[{pattern:/\b(?:false|true)\b/i,alias:"boolean"},{pattern:/(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,greedy:!0,lookbehind:!0},{pattern:/(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,greedy:!0,lookbehind:!0},/\b(?:null)\b/i,/\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/],u=/\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i,r=/|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,a=/[{}\[\](),:;]/;e.languages.php={delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"},comment:t,variable:/\$+(?:\w+\b|(?=\{))/,package:{pattern:/(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,lookbehind:!0,inside:{punctuation:/\\/}},"class-name-definition":{pattern:/(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,lookbehind:!0,alias:"class-name"},"function-definition":{pattern:/(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,lookbehind:!0,alias:"function"},keyword:[{pattern:/(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i,alias:"type-casting",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string|void)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i,alias:"type-declaration",greedy:!0},{pattern:/(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i,alias:"type-declaration",greedy:!0,lookbehind:!0},{pattern:/\b(?:parent|self|static)(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(\byield\s+)from\b/i,lookbehind:!0},/\bclass\b/i,{pattern:/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|new|or|parent|print|private|protected|public|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i,lookbehind:!0}],"argument-name":{pattern:/([(,]\s+)\b[a-z_]\w*(?=\s*:(?!:))/i,lookbehind:!0},"class-name":[{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/(\|\s*)\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,greedy:!0},{pattern:/(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,alias:"class-name-fully-qualified",greedy:!0,inside:{punctuation:/\\/}},{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*\$)/i,alias:"type-declaration",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-declaration"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,alias:["class-name-fully-qualified","static-context"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-hint"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:["class-name-fully-qualified","return-type"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,function:{pattern:/(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,lookbehind:!0,inside:{punctuation:/\\/}},property:{pattern:/(->\s*)\w+/,lookbehind:!0},number:u,operator:r,punctuation:a};var d={pattern:/\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,lookbehind:!0,inside:e.languages.php},o=[{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,alias:"nowdoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:d}},{pattern:/`(?:\\[\s\S]|[^\\`])*`/,alias:"backtick-quoted-string",greedy:!0},{pattern:/'(?:\\[\s\S]|[^\\'])*'/,alias:"single-quoted-string",greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,alias:"double-quoted-string",greedy:!0,inside:{interpolation:d}}];e.languages.insertBefore("php","variable",{string:o,attribute:{pattern:/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,greedy:!0,inside:{"attribute-content":{pattern:/^(#\[)[\s\S]+(?=\]$)/,lookbehind:!0,inside:{comment:t,string:o,"attribute-class-name":[{pattern:/([^:]|^)\b[a-z_]\w*(?!\\)\b/i,alias:"class-name",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\?\b[a-z_]\w*)+/i,alias:["class-name","class-name-fully-qualified"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,number:u,operator:r,punctuation:a}},delimiter:{pattern:/^#\[|\]$/,alias:"punctuation"}}}}),e.hooks.add("before-tokenize",(function(t){if(/<\?/.test(t.code)){e.languages["markup-templating"].buildPlaceholders(t,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g)}})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"php")}))}(Prism)},542:function(e,t){!function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,u="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",r=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*/.source.replace(//g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),a=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function d(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<>/g,(function(){return u})).replace(/<>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<>/g,(function(){return u}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)<>(?=\s*:\s)/.source.replace(/<>/g,(function(){return u})).replace(/<>/g,(function(){return"(?:"+r+"|"+a+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:d(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:d(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:d(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:d(a),lookbehind:!0,greedy:!0},number:{pattern:d(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(Prism)},543:function(e,t){e.exports={plain:{color:"#bfc7d5",backgroundColor:"#292d3e"},styles:[{types:["comment"],style:{color:"rgb(105, 112, 152)",fontStyle:"italic"}},{types:["string"],style:{color:"rgb(195, 232, 141)"}},{types:["number"],style:{color:"rgb(247, 140, 108)"}},{types:["builtin","char","constant","function"],style:{color:"rgb(130, 170, 255)"}},{types:["punctuation","selector"],style:{color:"rgb(199, 146, 234)"}},{types:["variable"],style:{color:"rgb(191, 199, 213)"}},{types:["class-name","attr-name"],style:{color:"rgb(255, 203, 107)"}},{types:["tag"],style:{color:"rgb(255, 85, 114)"}},{types:["operator"],style:{color:"rgb(137, 221, 255)"}},{types:["boolean"],style:{color:"rgb(255, 88, 116)"}},{types:["keyword"],style:{fontStyle:"italic"}},{types:["doctype"],style:{color:"rgb(199, 146, 234)",fontStyle:"italic"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)"}},{types:["url"],style:{color:"rgb(221, 221, 221)"}}]}},544:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.canUseDOM=void 0;var u,r=n(565);var a=((u=r)&&u.__esModule?u:{default:u}).default,d=a.canUseDOM?window.HTMLElement:{};t.canUseDOM=a.canUseDOM;t.default=d},545:function(e,t,n){"use strict";var u=n(28),r=n(57);e.exports=function(e,t,n){t in e?u.f(e,t,r(0,n)):e[t]=n}},546:function(e,t,n){"use strict";var u=n(28).f,r=n(89),a=n(82),d=n(30),o=n(80),i=n(81),c=n(61),l=n(88),f=n(94),s=n(10),p=n(491).fastKey,m=n(492),h=s?"_s":"size",b=function(e,t){var n,u=p(t);if("F"!==u)return e._i[u];for(n=e._f;n;n=n.n)if(n.k==t)return n};e.exports={getConstructor:function(e,t,n,c){var l=e((function(e,u){o(e,l,t,"_i"),e._t=t,e._i=r(null),e._f=void 0,e._l=void 0,e[h]=0,null!=u&&i(u,n,e[c],e)}));return a(l.prototype,{clear:function(){for(var e=m(this,t),n=e._i,u=e._f;u;u=u.n)u.r=!0,u.p&&(u.p=u.p.n=void 0),delete n[u.i];e._f=e._l=void 0,e[h]=0},delete:function(e){var n=m(this,t),u=b(n,e);if(u){var r=u.n,a=u.p;delete n._i[u.i],u.r=!0,a&&(a.n=r),r&&(r.p=a),n._f==u&&(n._f=r),n._l==u&&(n._l=a),n[h]--}return!!u},forEach:function(e){m(this,t);for(var n,u=d(e,arguments.length>1?arguments[1]:void 0,3);n=n?n.n:this._f;)for(u(n.v,n.k,this);n&&n.r;)n=n.p},has:function(e){return!!b(m(this,t),e)}}),s&&u(l.prototype,"size",{get:function(){return m(this,t)[h]}}),l},def:function(e,t,n){var u,r,a=b(e,t);return a?a.v=n:(e._l=a={i:r=p(t,!0),k:t,v:n,p:u=e._l,n:void 0,r:!1},e._f||(e._f=a),u&&(u.n=a),e[h]++,"F"!==r&&(e._i[r]=a)),e},getEntry:b,setStrong:function(e,t,n){c(e,t,(function(e,n){this._t=m(e,t),this._k=n,this._l=void 0}),(function(){for(var e=this._k,t=this._l;t&&t.r;)t=t.p;return this._t&&(this._l=t=t?t.n:this._t._f)?l(0,"keys"==e?t.k:"values"==e?t.v:[t.k,t.v]):(this._t=void 0,l(1))}),n?"entries":"values",!n,!0),f(t)}}},547:function(e,t,n){"use strict";var u=n(5),r=n(12),a=n(16),d=n(82),o=n(491),i=n(81),c=n(80),l=n(13),f=n(14),s=n(83),p=n(41),m=n(548);e.exports=function(e,t,n,h,b,v){var g=u[e],y=g,_=b?"set":"add",E=y&&y.prototype,w={},D=function(e){var t=E[e];a(E,e,"delete"==e||"has"==e?function(e){return!(v&&!l(e))&&t.call(this,0===e?0:e)}:"get"==e?function(e){return v&&!l(e)?void 0:t.call(this,0===e?0:e)}:"add"==e?function(e){return t.call(this,0===e?0:e),this}:function(e,n){return t.call(this,0===e?0:e,n),this})};if("function"==typeof y&&(v||E.forEach&&!f((function(){(new y).entries().next()})))){var k=new y,x=k[_](v?{}:-0,1)!=k,S=f((function(){k.has(1)})),C=s((function(e){new y(e)})),O=!v&&f((function(){for(var e=new y,t=5;t--;)e[_](t,t);return!e.has(-0)}));C||((y=t((function(t,n){c(t,y,e);var u=m(new g,t,y);return null!=n&&i(n,b,u[_],u),u}))).prototype=E,E.constructor=y),(S||O)&&(D("delete"),D("has"),b&&D("get")),(O||x)&&D(_),v&&E.clear&&delete E.clear}else y=h.getConstructor(t,e,b,_),d(y.prototype,n),o.NEED=!0;return p(y,e),w[e]=y,r(r.G+r.W+r.F*(y!=g),w),v||h.setStrong(y,e,b),y}},548:function(e,t,n){var u=n(13),r=n(549).set;e.exports=function(e,t,n){var a,d=t.constructor;return d!==n&&"function"==typeof d&&(a=d.prototype)!==n.prototype&&u(a)&&r&&r(e,a),e}},549:function(e,t,n){var u=n(13),r=n(8),a=function(e,t){if(r(e),!u(t)&&null!==t)throw TypeError(t+": can't set as prototype!")};e.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(e,t,u){try{(u=n(30)(Function.call,n(550).f(Object.prototype,"__proto__").set,2))(e,[]),t=!(e instanceof Array)}catch(r){t=!0}return function(e,n){return a(e,n),t?e.__proto__=n:u(e,n),e}}({},!1):void 0),check:a}},550:function(e,t,n){var u=n(62),r=n(57),a=n(33),d=n(87),o=n(31),i=n(86),c=Object.getOwnPropertyDescriptor;t.f=n(10)?c:function(e,t){if(e=a(e),t=d(t,!0),i)try{return c(e,t)}catch(n){}if(o(e,t))return r(!u.f.call(e,t),e[t])}},551:function(e,t,n){"use strict";var u=n(12),r=n(32),a=n(27),d=n(14),o=[].sort,i=[1,2,3];u(u.P+u.F*(d((function(){i.sort(void 0)}))||!d((function(){i.sort(null)}))||!n(552)(o)),"Array",{sort:function(e){return void 0===e?o.call(a(this)):o.call(a(this),r(e))}})},552:function(e,t,n){"use strict";var u=n(14);e.exports=function(e,t){return!!e&&u((function(){t?e.call(null,(function(){}),1):e.call(null)}))}},561:function(e,t,n){"use strict";n(489),n(79),n(490),n(551),n(29),n(22),n(21),n(85),n(442);var u=n(1),r=(n(446),n(447),n(77),n(428),n(0)),a=n.n(r),d=n(481),o=n.n(d);n(150);var i=function(e){var t=e.humanize,n=e.icon,u=e.values,r=e.currentState,d=e.setState;if(0==u.size)return null;var i=Array.from(u);return a.a.createElement(a.a.Fragment,null,i.map((function(e,u){var i="string"==typeof e&&t?o()(e):e;return a.a.createElement("label",{key:u},a.a.createElement("input",{type:"checkbox",onChange:function(t){var n=new Set(r);t.currentTarget.checked?n.add(e):n.delete(e),d(n)},checked:r.has(e)}),i&&a.a.createElement(a.a.Fragment,null,n?a.a.createElement("i",{className:"feather icon-"+n}):""," ",i))})))},c=n(503),l=n(431),f=n(430),s=(n(440),n(451)),p=n.n(s),m=n(423),h=n.n(m),b=n(504),v=n.n(b),g=n(436);n(151);function y(e){var t=e.delivery_guarantee,n=e.description,u=e.event_types,r=e.function_category,d=(e.logo_path,e.name),o=e.pathTemplate,i=e.status,c=e.title,l=e.type,s=o;s||("source"==l&&(s="/docs/reference/sources//"),"transform"==l&&(s="/docs/reference/transforms//"),"sink"==l&&(s="/docs/reference/sinks//"));var p=s.replace("",d);return a.a.createElement(f.a,{to:p,className:"qovery-component",title:n},a.a.createElement("div",{className:"qovery-component--header"},a.a.createElement("div",{className:"qovery-component--name"},c)),a.a.createElement("div",{className:"qovery-component--badges"},"beta"==i?a.a.createElement("span",{className:"badge badge--warning",title:"This component is in beta and is not recommended for production environments"},a.a.createElement("i",{className:"feather icon-alert-triangle"})):a.a.createElement("span",{className:"badge badge--primary",title:"This component has passed reliability standards that make it production ready"},a.a.createElement("i",{className:"feather icon-award"})),"best_effort"==t?a.a.createElement("span",{className:"badge badge--warning",title:"This component makes a best-effort delivery guarantee, and in rare cases can lose data"},a.a.createElement("i",{className:"feather icon-shield-off"})):a.a.createElement("span",{className:"badge badge--primary",title:"This component offers an at-least-once delivery guarantee"},a.a.createElement("i",{className:"feather icon-shield"})),u.includes("log")?a.a.createElement("span",{className:"badge badge--primary",title:"This component works with log event types"},"log"):"",u.includes("metric")?a.a.createElement("span",{className:"badge badge--primary",title:"This component works with metric event types"},"metric"):"",a.a.createElement("span",{className:"badge badge--primary"},r)))}function _(e){var t=e.components,n=e.headingLevel,r=e.pathTemplate,d=e.titles,o=t.filter((function(e){return"source"==e.type})),i=t.filter((function(e){return"transform"==e.type})),f=t.filter((function(e){return"sink"==e.type})),s="h"+(n||3);return t.length>0?a.a.createElement(a.a.Fragment,null,o.length>0?a.a.createElement(a.a.Fragment,null,d&&a.a.createElement(s,null,o.length," Sources"),a.a.createElement("div",{className:"qovery-components--grid"},o.map((function(e,t){return a.a.createElement(y,Object(u.a)({key:t,pathTemplate:r},e))})))):"",i.length>0?a.a.createElement(a.a.Fragment,null,d&&a.a.createElement(s,null,i.length," Transforms"),a.a.createElement("div",{className:"qovery-components--grid"},i.map((function(e,t){return a.a.createElement(y,Object(u.a)({key:t,pathTemplate:r},e))})))):"",f.length>0?a.a.createElement(a.a.Fragment,null,d&&a.a.createElement(s,null,f.length," Sinks"),a.a.createElement("div",{className:"qovery-components--grid"},f.map((function(e,t){return a.a.createElement(y,Object(u.a)({key:t,pathTemplate:r},e))})))):"",a.a.createElement("hr",null),a.a.createElement(l.a,{to:"https://github.com/qovery/documentation/issues/new?labels=type%3A+new+feature",target:"_blank",rightIcon:"plus-circle"},"Request a new component")):a.a.createElement(c.a,{text:"no components found"})}t.a=function(e){var t=Object(g.a)().siteConfig.customFields.metadata,n=t.sources,u=t.transforms,d=t.sinks,o=e.titles||null==e.titles,c=1==e.filterColumn,l=e.pathTemplate,s=e.location?v.a.parse(e.location.search,{ignoreQueryPrefix:!0}):{},m=[];(e.sources||null==e.sources)&&(m=m.concat(Object.values(n))),(e.transforms||null==e.transforms)&&(m=m.concat(Object.values(u))),(e.sinks||null==e.sinks)&&(m=m.concat(Object.values(d))),m=m.sort((function(e,t){return e.name>t.name?1:-1}));var b=Object(r.useState)("true"==s["at-least-once"]),y=b[0],E=b[1],w=Object(r.useState)(new Set(s["event-types"]||e.eventTypes)),D=w[0],k=w[1],x=Object(r.useState)(new Set(s.functions)),S=x[0],C=x[1],O=Object(r.useState)(new Set(s["operating-systems"])),I=O[0],A=O[1],j=Object(r.useState)("true"==s["prod-ready"]),N=j[0],F=j[1],T=Object(r.useState)(new Set(s.providers)),P=T[0],M=T[1],R=Object(r.useState)(s.search),L=R[0],B=R[1];L&&(m=m.filter((function(e){return(e.name.toLowerCase()+" "+e.type.toLowerCase()).includes(L.toLowerCase())}))),y&&(m=m.filter((function(e){return"at_least_once"==e.delivery_guarantee}))),D.size>0&&(m=m.filter((function(e){return Array.from(D).some((function(t){return e.event_types.includes(t)}))}))),S.size>0&&(m=m.filter((function(e){return S.has(e.function_category)}))),I.size>0&&(m=m.filter((function(e){return Array.from(I).every((function(t){return e.operating_systems.includes(t)}))}))),N&&(m=m.filter((function(e){return"prod-ready"==e.status}))),P.size>0&&(m=m.filter((function(e){return Array.from(P).every((function(t){return e.service_providers&&e.service_providers.includes(t)}))}))),e.exceptNames&&e.exceptNames.length>0&&(m=m.filter((function(t){return!e.exceptNames.includes(t.name)}))),e.exceptFunctions&&e.exceptFunctions.length>0&&(m=m.filter((function(t){return!e.exceptFunctions.includes(t.function_category)})));var z=D.size>0?D:new Set(p()(m).map((function(e){return e.event_types})).flatten().uniq().compact().sort().value()),U=new Set(p()(m).map((function(e){return e.operating_systems})).flatten().uniq().compact().sort().value()),W=new Set(p()(m).map((function(e){return e.service_providers})).flatten().uniq().compact().sort().value()),H=new Set(p()(m).filter((function(e){return"source"==e.type})).map((function(e){return e.function_category})).uniq().compact().sort().value()),$=new Set(p()(m).filter((function(e){return"transform"==e.type})).map((function(e){return e.function_category})).uniq().compact().sort().value()),q=new Set(p()(m).filter((function(e){return"sink"==e.type})).map((function(e){return e.function_category})).uniq().compact().sort().value());return a.a.createElement("div",{className:h()("qovery-components",{"qovery-components--cols":c})},a.a.createElement("div",{className:"filters"},a.a.createElement("div",{className:"search"},a.a.createElement("input",{className:"input--text input--lg",type:"text",onChange:function(e){return B(e.currentTarget.value)},placeholder:"\ud83d\udd0d Search..."})),a.a.createElement("div",{className:"filter"},a.a.createElement("div",{className:"filter--label"},a.a.createElement(f.a,{to:"/docs/getting-started/data-model/",title:"Learn more about Qovery's event types"},"Event types ",a.a.createElement("i",{className:"feather icon-info"}))),a.a.createElement("div",{className:"filter--choices"},a.a.createElement(i,{label:"Event Types",icon:"database",values:z,humanize:!0,currentState:D,setState:k}))),a.a.createElement("div",{className:"filter"},a.a.createElement("div",{className:"filter--label"},a.a.createElement(f.a,{to:"/docs/getting-started/whats-next/",title:"Learn more about Qovery's guarantees"},"Guarantees ",a.a.createElement("i",{className:"feather icon-info"}))),a.a.createElement("div",{className:"filter--choices"},a.a.createElement("label",{title:"Show only components that offer an at-least-once delivery guarantee."},a.a.createElement("input",{type:"checkbox",onChange:function(e){return E(e.currentTarget.checked)},checked:y}),a.a.createElement("i",{className:"feather icon-shield"})," At-least-once"),a.a.createElement("label",{title:"Show only production ready components."},a.a.createElement("input",{type:"checkbox",onChange:function(e){return F(e.currentTarget.checked)},checked:N}),a.a.createElement("i",{className:"feather icon-award"})," Prod-ready"))),H.size>0&&a.a.createElement("div",{className:"filter"},a.a.createElement("div",{className:"filter--label"},"Source Functions"),a.a.createElement("div",{className:"filter--choices"},a.a.createElement(i,{label:"Functions",icon:"settings",values:H,humanize:!0,currentState:S,setState:C}))),$.size>0&&a.a.createElement("div",{className:"filter"},a.a.createElement("div",{className:"filter--label"},"Transform Functions"),a.a.createElement("div",{className:"filter--choices"},a.a.createElement(i,{label:"Functions",icon:"settings",values:$,humanize:!0,currentState:S,setState:C}))),q.size>0&&a.a.createElement("div",{className:"filter"},a.a.createElement("div",{className:"filter--label"},"Sink Functions"),a.a.createElement("div",{className:"filter--choices"},a.a.createElement(i,{label:"Functions",icon:"settings",values:q,humanize:!0,currentState:S,setState:C}))),W.size>0&&a.a.createElement("div",{className:"filter"},a.a.createElement("div",{className:"filter--label"},"Providers"),a.a.createElement("div",{className:"filter--choices"},a.a.createElement(i,{label:"Providers",icon:"cloud",values:W,currentState:P,setState:M}))),U.size>0&&a.a.createElement("div",{className:"filter"},a.a.createElement("div",{className:"filter--label"},a.a.createElement(f.a,{to:"/docs/setup/installation/operating-systems/",title:"Learn more about Qovery's operating systems"},"Operating Systems")),a.a.createElement("div",{className:"filter--choices"},a.a.createElement(i,{label:"Operating Systems",icon:"cpu",values:U,currentState:I,setState:A})))),a.a.createElement("div",{className:"qovery-components--results"},a.a.createElement(_,{components:m,headingLevel:e.headingLevel,pathTemplate:l,titles:o})))}},563:function(e,t,n){"use strict";n.d(t,"b",(function(){return d}));var u=n(53),r={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","at-rule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]},a=n(0),d={Prism:u.a,theme:r};function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(){return(i=Object.assign||function(e){for(var t=1;t0&&e[n-1]===t?e:e.concat(t)},s=function(e,t){var n=e.plain,u=Object.create(null),r=e.styles.reduce((function(e,n){var u=n.languages,r=n.style;return u&&!u.includes(t)||n.types.forEach((function(t){var n=i({},e[t],r);e[t]=n})),e}),u);return r.root=n,r.plain=i({},n,{backgroundColor:null}),r};function p(e,t){var n={};for(var u in e)Object.prototype.hasOwnProperty.call(e,u)&&-1===t.indexOf(u)&&(n[u]=e[u]);return n}var m=function(e){function t(){for(var t=this,n=[],u=arguments.length;u--;)n[u]=arguments[u];e.apply(this,n),o(this,"getThemeDict",(function(e){if(void 0!==t.themeDict&&e.theme===t.prevTheme&&e.language===t.prevLanguage)return t.themeDict;t.prevTheme=e.theme,t.prevLanguage=e.language;var n=e.theme?s(e.theme,e.language):void 0;return t.themeDict=n})),o(this,"getLineProps",(function(e){var n=e.key,u=e.className,r=e.style,a=i({},p(e,["key","className","style","line"]),{className:"token-line",style:void 0,key:void 0}),d=t.getThemeDict(t.props);return void 0!==d&&(a.style=d.plain),void 0!==r&&(a.style=void 0!==a.style?i({},a.style,r):r),void 0!==n&&(a.key=n),u&&(a.className+=" "+u),a})),o(this,"getStyleForToken",(function(e){var n=e.types,u=e.empty,r=n.length,a=t.getThemeDict(t.props);if(void 0!==a){if(1===r&&"plain"===n[0])return u?{display:"inline-block"}:void 0;if(1===r&&!u)return a[n[0]];var d=u?{display:"inline-block"}:{},o=n.map((function(e){return a[e]}));return Object.assign.apply(Object,[d].concat(o))}})),o(this,"getTokenProps",(function(e){var n=e.key,u=e.className,r=e.style,a=e.token,d=i({},p(e,["key","className","style","token"]),{className:"token "+a.types.join(" "),children:a.content,style:t.getStyleForToken(a),key:void 0});return void 0!==r&&(d.style=void 0!==d.style?i({},d.style,r):r),void 0!==n&&(d.key=n),u&&(d.className+=" "+u),d}))}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.render=function(){var e=this.props,t=e.Prism,n=e.language,u=e.code,r=e.children,a=this.getThemeDict(this.props),d=t.languages[n];return r({tokens:function(e){for(var t=[[]],n=[e],u=[0],r=[e.length],a=0,d=0,o=[],i=[o];d>-1;){for(;(a=u[d]++)0?p:["plain"],s=m):(p=f(p,m.type),m.alias&&(p=f(p,m.alias)),s=m.content),"string"==typeof s){var h=s.split(c),b=h.length;o.push({types:p,content:h[0]});for(var v=1;v=0)&&a(e,!n)}e.exports=t.default},568:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.assertNodeList=i,t.setElement=function(e){var t=e;if("string"==typeof t&&d.canUseDOM){var n=document.querySelectorAll(t);i(n,t),t="length"in n?n[0]:n}return o=t||o},t.validateElement=c,t.hide=function(e){c(e)&&(e||o).setAttribute("aria-hidden","true")},t.show=function(e){c(e)&&(e||o).removeAttribute("aria-hidden")},t.documentNotReadyOrSSRTesting=function(){o=null},t.resetForTesting=function(){o=null};var u,r=n(593),a=(u=r)&&u.__esModule?u:{default:u},d=n(544);var o=null;function i(e,t){if(!e||!e.length)throw new Error("react-modal: No elements were found for selector "+t+".")}function c(e){return!(!e&&!o)||((0,a.default)(!1,["react-modal: App element is not defined.","Please use `Modal.setAppElement(el)` or set `appElement={el}`.","This is needed so screen readers don't see main content","when modal is opened. It is not recommended, but you can opt-out","by setting `ariaHideApp={false}`."].join(" ")),!1)}},569:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u=new function e(){var t=this;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.register=function(e){-1===t.openInstances.indexOf(e)&&(t.openInstances.push(e),t.emit("register"))},this.deregister=function(e){var n=t.openInstances.indexOf(e);-1!==n&&(t.openInstances.splice(n,1),t.emit("deregister"))},this.subscribe=function(e){t.subscribers.push(e)},this.emit=function(e){t.subscribers.forEach((function(n){return n(e,t.openInstances.slice())}))},this.openInstances=[],this.subscribers=[]};t.default=u,e.exports=t.default},588:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u,r=n(589),a=(u=r)&&u.__esModule?u:{default:u};t.default=a.default,e.exports=t.default},589:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.bodyOpenClassName=t.portalClassName=void 0;var u=Object.assign||function(e){for(var t=1;t0&&0===(g-=1)&&f.show(t),n.props.shouldFocusAfterRender&&(n.props.shouldReturnFocusAfterClose?(c.returnFocus(),c.teardownScopedFocus()):c.popWithoutFocus()),n.props.onAfterClose&&n.props.onAfterClose(),m.default.deregister(n)},n.open=function(){n.beforeOpen(),n.state.afterOpen&&n.state.beforeClose?(clearTimeout(n.closeTimer),n.setState({beforeClose:!1})):(n.props.shouldFocusAfterRender&&(c.setupScopedFocus(n.node),c.markForFocusLater()),n.setState({isOpen:!0},(function(){n.setState({afterOpen:!0}),n.props.isOpen&&n.props.onAfterOpen&&n.props.onAfterOpen({overlayEl:n.overlay,contentEl:n.content})})))},n.close=function(){n.props.closeTimeoutMS>0?n.closeWithTimeout():n.closeWithoutTimeout()},n.focusContent=function(){return n.content&&!n.contentHasFocus()&&n.content.focus()},n.closeWithTimeout=function(){var e=Date.now()+n.props.closeTimeoutMS;n.setState({beforeClose:!0,closesAt:e},(function(){n.closeTimer=setTimeout(n.closeWithoutTimeout,n.state.closesAt-Date.now())}))},n.closeWithoutTimeout=function(){n.setState({beforeClose:!1,isOpen:!1,afterOpen:!1,closesAt:null},n.afterClose)},n.handleKeyDown=function(e){9===e.keyCode&&(0,l.default)(n.content,e),n.props.shouldCloseOnEsc&&27===e.keyCode&&(e.stopPropagation(),n.requestClose(e))},n.handleOverlayOnClick=function(e){null===n.shouldClose&&(n.shouldClose=!0),n.shouldClose&&n.props.shouldCloseOnOverlayClick&&(n.ownerHandlesClose()?n.requestClose(e):n.focusContent()),n.shouldClose=null},n.handleContentOnMouseUp=function(){n.shouldClose=!1},n.handleOverlayOnMouseDown=function(e){n.props.shouldCloseOnOverlayClick||e.target!=n.overlay||e.preventDefault()},n.handleContentOnClick=function(){n.shouldClose=!1},n.handleContentOnMouseDown=function(){n.shouldClose=!1},n.requestClose=function(e){return n.ownerHandlesClose()&&n.props.onRequestClose(e)},n.ownerHandlesClose=function(){return n.props.onRequestClose},n.shouldBeClosed=function(){return!n.state.isOpen&&!n.state.beforeClose},n.contentHasFocus=function(){return document.activeElement===n.content||n.content.contains(document.activeElement)},n.buildClassName=function(e,t){var u="object"===(void 0===t?"undefined":r(t))?t:{base:v[e],afterOpen:v[e]+"--after-open",beforeClose:v[e]+"--before-close"},a=u.base;return n.state.afterOpen&&(a=a+" "+u.afterOpen),n.state.beforeClose&&(a=a+" "+u.beforeClose),"string"==typeof t&&t?a+" "+t:a},n.attributesFromObject=function(e,t){return Object.keys(t).reduce((function(n,u){return n[e+"-"+u]=t[u],n}),{})},n.state={afterOpen:!1,beforeClose:!1},n.shouldClose=null,n.moveFromContentToOverlay=null,n}return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}(t,e),a(t,[{key:"componentDidMount",value:function(){this.props.isOpen&&this.open()}},{key:"componentDidUpdate",value:function(e,t){this.props.isOpen&&!e.isOpen?this.open():!this.props.isOpen&&e.isOpen&&this.close(),this.props.shouldFocusAfterRender&&this.state.isOpen&&!t.isOpen&&this.focusContent()}},{key:"componentWillUnmount",value:function(){this.state.isOpen&&this.afterClose(),clearTimeout(this.closeTimer)}},{key:"beforeOpen",value:function(){var e=this.props,t=e.appElement,n=e.ariaHideApp,u=e.htmlOpenClassName,r=e.bodyOpenClassName;r&&s.add(document.body,r),u&&s.add(document.getElementsByTagName("html")[0],u),n&&(g+=1,f.hide(t)),m.default.register(this)}},{key:"render",value:function(){var e=this.props,t=e.id,n=e.className,r=e.overlayClassName,a=e.defaultStyles,d=n?{}:a.content,i=r?{}:a.overlay;return this.shouldBeClosed()?null:o.default.createElement("div",{ref:this.setOverlayRef,className:this.buildClassName("overlay",r),style:u({},i,this.props.style.overlay),onClick:this.handleOverlayOnClick,onMouseDown:this.handleOverlayOnMouseDown},o.default.createElement("div",u({id:t,ref:this.setContentRef,style:u({},d,this.props.style.content),className:this.buildClassName("content",n),tabIndex:"-1",onKeyDown:this.handleKeyDown,onMouseDown:this.handleContentOnMouseDown,onMouseUp:this.handleContentOnMouseUp,onClick:this.handleContentOnClick,role:this.props.role,"aria-label":this.props.contentLabel},this.attributesFromObject("aria",this.props.aria||{}),this.attributesFromObject("data",this.props.data||{}),{"data-testid":this.props.testId}),this.props.children))}}]),t}(d.Component);y.defaultProps={style:{overlay:{},content:{}},defaultStyles:{}},y.propTypes={isOpen:i.default.bool.isRequired,defaultStyles:i.default.shape({content:i.default.object,overlay:i.default.object}),style:i.default.shape({content:i.default.object,overlay:i.default.object}),className:i.default.oneOfType([i.default.string,i.default.object]),overlayClassName:i.default.oneOfType([i.default.string,i.default.object]),bodyOpenClassName:i.default.string,htmlOpenClassName:i.default.string,ariaHideApp:i.default.bool,appElement:i.default.instanceOf(p.default),onAfterOpen:i.default.func,onAfterClose:i.default.func,onRequestClose:i.default.func,closeTimeoutMS:i.default.number,shouldFocusAfterRender:i.default.bool,shouldCloseOnOverlayClick:i.default.bool,shouldReturnFocusAfterClose:i.default.bool,role:i.default.string,contentLabel:i.default.string,aria:i.default.object,data:i.default.object,children:i.default.node,shouldCloseOnEsc:i.default.bool,overlayRef:i.default.func,contentRef:i.default.func,id:i.default.string,testId:i.default.string},t.default=y,e.exports=t.default},591:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.handleBlur=c,t.handleFocus=l,t.markForFocusLater=function(){d.push(document.activeElement)},t.returnFocus=function(){var e=null;try{return void(0!==d.length&&(e=d.pop()).focus())}catch(t){console.warn(["You tried to return focus to",e,"but it is not in the DOM anymore"].join(" "))}},t.popWithoutFocus=function(){d.length>0&&d.pop()},t.setupScopedFocus=function(e){o=e,window.addEventListener?(window.addEventListener("blur",c,!1),document.addEventListener("focus",l,!0)):(window.attachEvent("onBlur",c),document.attachEvent("onFocus",l))},t.teardownScopedFocus=function(){o=null,window.addEventListener?(window.removeEventListener("blur",c),document.removeEventListener("focus",l)):(window.detachEvent("onBlur",c),document.detachEvent("onFocus",l))};var u,r=n(567),a=(u=r)&&u.__esModule?u:{default:u};var d=[],o=null,i=!1;function c(){i=!0}function l(){if(i){if(i=!1,!o)return;setTimeout((function(){o.contains(document.activeElement)||((0,a.default)(o)[0]||o).focus()}),0)}}},592:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){var n=(0,a.default)(e);if(!n.length)return void t.preventDefault();var u=void 0,r=t.shiftKey,d=n[0],o=n[n.length-1];if(e===document.activeElement){if(!r)return;u=o}o!==document.activeElement||r||(u=d);d===document.activeElement&&r&&(u=o);if(u)return t.preventDefault(),void u.focus();var i=/(\bChrome\b|\bSafari\b)\//.exec(navigator.userAgent);if(null==i||"Chrome"==i[1]||null!=/\biPod\b|\biPad\b/g.exec(navigator.userAgent))return;var c=n.indexOf(document.activeElement);c>-1&&(c+=r?-1:1);if(void 0===(u=n[c]))return t.preventDefault(),void(u=r?o:d).focus();t.preventDefault(),u.focus()};var u,r=n(567),a=(u=r)&&u.__esModule?u:{default:u};e.exports=t.default},593:function(e,t,n){"use strict";var u=function(){};e.exports=u},594:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.dumpClassLists=function(){0};var u={},r={};t.add=function(e,t){return n=e.classList,a="html"==e.nodeName.toLowerCase()?u:r,void t.split(" ").forEach((function(e){!function(e,t){e[t]||(e[t]=0),e[t]+=1}(a,e),n.add(e)}));var n,a},t.remove=function(e,t){return n=e.classList,a="html"==e.nodeName.toLowerCase()?u:r,void t.split(" ").forEach((function(e){!function(e,t){e[t]&&(e[t]-=1)}(a,e),0===a[e]&&n.remove(e)}));var n,a}},595:function(e,t,n){"use strict";var u,r=n(569),a=(u=r)&&u.__esModule?u:{default:u};var d=void 0,o=void 0,i=[];function c(){0!==i.length&&i[i.length-1].focusContent()}a.default.subscribe((function(e,t){d&&o||((d=document.createElement("div")).setAttribute("data-react-modal-body-trap",""),d.style.position="absolute",d.style.opacity="0",d.setAttribute("tabindex","0"),d.addEventListener("focus",c),(o=d.cloneNode()).addEventListener("focus",c)),(i=t).length>0?(document.body.firstChild!==d&&document.body.insertBefore(d,document.body.firstChild),document.body.lastChild!==o&&document.body.appendChild(o)):(d.parentElement&&d.parentElement.removeChild(d),o.parentElement&&o.parentElement.removeChild(o))}))},596:function(e,t,n){"use strict";function u(){var e=this.constructor.getDerivedStateFromProps(this.props,this.state);null!=e&&this.setState(e)}function r(e){this.setState(function(t){var n=this.constructor.getDerivedStateFromProps(e,t);return null!=n?n:null}.bind(this))}function a(e,t){try{var n=this.props,u=this.state;this.props=e,this.state=t,this.__reactInternalSnapshotFlag=!0,this.__reactInternalSnapshot=this.getSnapshotBeforeUpdate(n,u)}finally{this.props=n,this.state=u}}function d(e){var t=e.prototype;if(!t||!t.isReactComponent)throw new Error("Can only polyfill class components");if("function"!=typeof e.getDerivedStateFromProps&&"function"!=typeof t.getSnapshotBeforeUpdate)return e;var n=null,d=null,o=null;if("function"==typeof t.componentWillMount?n="componentWillMount":"function"==typeof t.UNSAFE_componentWillMount&&(n="UNSAFE_componentWillMount"),"function"==typeof t.componentWillReceiveProps?d="componentWillReceiveProps":"function"==typeof t.UNSAFE_componentWillReceiveProps&&(d="UNSAFE_componentWillReceiveProps"),"function"==typeof t.componentWillUpdate?o="componentWillUpdate":"function"==typeof t.UNSAFE_componentWillUpdate&&(o="UNSAFE_componentWillUpdate"),null!==n||null!==d||null!==o){var i=e.displayName||e.name,c="function"==typeof e.getDerivedStateFromProps?"getDerivedStateFromProps()":"getSnapshotBeforeUpdate()";throw Error("Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n"+i+" uses "+c+" but also contains the following legacy lifecycles:"+(null!==n?"\n "+n:"")+(null!==d?"\n "+d:"")+(null!==o?"\n "+o:"")+"\n\nThe above lifecycles should be removed. Learn more about this warning here:\nhttps://fb.me/react-async-component-lifecycle-hooks")}if("function"==typeof e.getDerivedStateFromProps&&(t.componentWillMount=u,t.componentWillReceiveProps=r),"function"==typeof t.getSnapshotBeforeUpdate){if("function"!=typeof t.componentDidUpdate)throw new Error("Cannot polyfill getSnapshotBeforeUpdate() for components that do not define componentDidUpdate() on the prototype");t.componentWillUpdate=a;var l=t.componentDidUpdate;t.componentDidUpdate=function(e,t,n){var u=this.__reactInternalSnapshotFlag?this.__reactInternalSnapshot:n;l.call(this,e,t,u)}}return e}n.r(t),n.d(t,"polyfill",(function(){return d})),u.__suppressDeprecationWarning=!0,r.__suppressDeprecationWarning=!0,a.__suppressDeprecationWarning=!0},597:function(e,t,n){var u;!function(r){"use strict";var a,d,o,i=(a=/d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZWN]|"[^"]*"|'[^']*'/g,d=/\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,o=/[^-+\dA-Z]/g,function(e,t,n,u){if(1!==arguments.length||"string"!==s(e)||/\d/.test(e)||(t=e,e=void 0),(e=e||new Date)instanceof Date||(e=new Date(e)),isNaN(e))throw TypeError("Invalid date");var r=(t=String(i.masks[t]||t||i.masks.default)).slice(0,4);"UTC:"!==r&&"GMT:"!==r||(t=t.slice(4),n=!0,"GMT:"===r&&(u=!0));var p=n?"getUTC":"get",m=e[p+"Date"](),h=e[p+"Day"](),b=e[p+"Month"](),v=e[p+"FullYear"](),g=e[p+"Hours"](),y=e[p+"Minutes"](),_=e[p+"Seconds"](),E=e[p+"Milliseconds"](),w=n?0:e.getTimezoneOffset(),D=l(e),k=f(e),x={d:m,dd:c(m),ddd:i.i18n.dayNames[h],dddd:i.i18n.dayNames[h+7],m:b+1,mm:c(b+1),mmm:i.i18n.monthNames[b],mmmm:i.i18n.monthNames[b+12],yy:String(v).slice(2),yyyy:v,h:g%12||12,hh:c(g%12||12),H:g,HH:c(g),M:y,MM:c(y),s:_,ss:c(_),l:c(E,3),L:c(Math.round(E/10)),t:g<12?i.i18n.timeNames[0]:i.i18n.timeNames[1],tt:g<12?i.i18n.timeNames[2]:i.i18n.timeNames[3],T:g<12?i.i18n.timeNames[4]:i.i18n.timeNames[5],TT:g<12?i.i18n.timeNames[6]:i.i18n.timeNames[7],Z:u?"GMT":n?"UTC":(String(e).match(d)||[""]).pop().replace(o,""),o:(w>0?"-":"+")+c(100*Math.floor(Math.abs(w)/60)+Math.abs(w)%60,4),S:["th","st","nd","rd"][m%10>3?0:(m%100-m%10!=10)*m%10],W:D,N:k};return t.replace(a,(function(e){return e in x?x[e]:e.slice(1,e.length-1)}))});function c(e,t){for(e=String(e),t=t||2;e.length=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),b=r,m=p["".concat(i,".").concat(b)]||p[b]||f[b]||o;return n?a.a.createElement(m,c({ref:t},l,{components:n})):a.a.createElement(m,c({ref:t},l))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:a(s,n);l>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(430),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,p=Object(c.a)(u),f=Object(a.useRef)(!1),b=l.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!b&&p&&window.docusaurus.prefetch(u),function(){b&&t&&t.disconnect()}}),[u,b,p]),u&&p?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){f.current||(window.docusaurus.preload(u),f.current=!0)},innerRef:function(e){var n,r;b&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(r.a)({},e,{href:u}))}},429:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,f=c()("jump-to","jump-to--"+l,n),b=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?a.a.createElement("a",{href:p,target:u,className:f},b):a.a.createElement(o.a,{to:p,className:f},b)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/1d187ae3.dc320e8d.js b/1d187ae3.dc320e8d.js new file mode 100644 index 0000000000..051a88a15c --- /dev/null +++ b/1d187ae3.dc320e8d.js @@ -0,0 +1,2 @@ +/*! For license information please see 1d187ae3.dc320e8d.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[37],{189:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return p}));var r=n(1),a=n(9),o=(n(0),n(425)),i=n(424),c=(n(431),n(429),{last_modified_on:"2023-10-09",title:"API Token",description:"Learn how to manage the API token via Qovery"}),s={id:"using-qovery/configuration/organization/api-token",title:"API Token",description:"Learn how to manage the API token via Qovery",source:"@site/docs/using-qovery/configuration/organization/api-token.md",permalink:"/docs/using-qovery/configuration/organization/api-token",sidebar:"docs",previous:{title:"Helm Repository",permalink:"/docs/using-qovery/configuration/organization/helm-repository"},next:{title:"Clusters",permalink:"/docs/using-qovery/configuration/clusters"}},l=[{value:"Create a new token",id:"create-a-new-token",children:[]},{value:"Delete a token",id:"delete-a-token",children:[]},{value:"Edit a token",id:"edit-a-token",children:[]}],u={rightToc:l};function p(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"API token allows third-party applications or script to access your organization via the Qovery API (CI/CD, Terraform script, Pulumi etc..)."),Object(o.b)("p",null,"You can manage the API tokens attached to your organization directly from the Qovery console."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"You can manage the API tokens of your organization with the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#generate-api-token"}),"Qovery CLI")," as well")),Object(o.b)("p",null,"You can access the token API configuration by opening the ",Object(o.b)("inlineCode",{parentName:"p"},"Token API")," section within the organization settings."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/organization/access_settings.png",alt:"How to access your organization settings"})),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/organization/token_api_access.png",alt:"How to access your Token API section"})),Object(o.b)("h2",{id:"create-a-new-token"},"Create a new token"),Object(o.b)("p",null,"You can create a new token API by pressing the ",Object(o.b)("inlineCode",{parentName:"p"},"Add")," button. You need to provide:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"A name"),Object(o.b)("li",{parentName:"ul"},"A description"),Object(o.b)("li",{parentName:"ul"},"A role: this allows to manage the permission assigned to the new API Token. The permission is managed via the ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/members-rbac/#roles-based-access-control-rbac"}),"Qovery RBAC system"))),Object(o.b)("p",null,"Once validated the token value will be displayed on the interface."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Make sure you safely store the token returned by the UI. You won't be able to retrieve it again (you will have to create a new one)")),Object(o.b)("h2",{id:"delete-a-token"},"Delete a token"),Object(o.b)("p",null,"You can create a new token API by pressing the ",Object(o.b)("inlineCode",{parentName:"p"},"Bin")," button next to the Token you want to delete."),Object(o.b)("h2",{id:"edit-a-token"},"Edit a token"),Object(o.b)("p",null,"This functionality is not yet available"))}p.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),b=r,m=p["".concat(i,".").concat(b)]||p[b]||f[b]||o;return n?a.a.createElement(m,c({ref:t},l,{components:n})):a.a.createElement(m,c({ref:t},l))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:a(s,n);l>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(432),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,p=Object(c.a)(u),f=Object(a.useRef)(!1),b=l.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!b&&p&&window.docusaurus.prefetch(u),function(){b&&t&&t.disconnect()}}),[u,b,p]),u&&p?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){f.current||(window.docusaurus.preload(u),f.current=!0)},innerRef:function(e){var n,r;b&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(r.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,f=c()("jump-to","jump-to--"+l,n),b=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?a.a.createElement("a",{href:p,target:u,className:f},b):a.a.createElement(o.a,{to:p,className:f},b)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/1d3be599.c9ef14c7.js.LICENSE.txt b/1d187ae3.dc320e8d.js.LICENSE.txt similarity index 100% rename from 1d3be599.c9ef14c7.js.LICENSE.txt rename to 1d187ae3.dc320e8d.js.LICENSE.txt diff --git a/1d3be599.c9ef14c7.js b/1d3be599.4e669d3d.js similarity index 72% rename from 1d3be599.c9ef14c7.js rename to 1d3be599.4e669d3d.js index d65a625563..171dae2d48 100644 --- a/1d3be599.c9ef14c7.js +++ b/1d3be599.4e669d3d.js @@ -1,2 +1,2 @@ -/*! For license information please see 1d3be599.c9ef14c7.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[37],{189:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return f}));var r=n(1),o=n(9),a=(n(0),n(422)),i=n(431),c=n(421),s=n(426),u=(n(429),{last_modified_on:"2022-09-30",$schema:"/.meta/.schemas/guides.json",title:"How to run commands before the application starts",description:"How to run commands before a Qovery application starts",author_github:"https://github.com/l0ck3",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to run commands before the application starts",description:"How to run commands before a Qovery application starts",permalink:"/guides/tutorial/how-to-run-commands-at-application-startup",readingTime:"3 min read",source:"@site/guides/tutorial/how-to-run-commands-at-application-startup.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to run commands before the application starts",truncated:!1,prevItem:{title:"How to integrate Qovery with GitHub Actions",permalink:"/guides/tutorial/how-to-integrate-qovery-with-github-actions"},nextItem:{title:"How to seed a Postgres database on a dev environment",permalink:"/guides/tutorial/data-seeding-in-postgres"}},p=[{value:"Goal",id:"goal",children:[]}],d={rightToc:p};function f(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Running your applications on Qovery is pretty straightforward, but there are many cases where you will need to run some tasks before your application starts, like running database migrations, and it might not be obvious how to do it."),Object(a.b)(s.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Your app is running in Dockerfile mode."))),Object(a.b)("h2",{id:"goal"},"Goal"),Object(a.b)("p",null,"This tutorial will cover how to run tasks when your application is starting. We'll use the case of a database migration with Ruby on Rails, but the same principle can be applied for any framework or command you need to run."),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"add-an-entrypoint-script"},"Add an entrypoint script"),Object(a.b)("p",null,"The first thing to do is to add an entrypoint script. We'll add it to a docker directory at the project's root, but you can put it anywhere you want."),Object(a.b)("p",null,"Let's create the docker/entrypoint.sh with the following content:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'#! /bin/sh\n\nbundle exec rails db:migrate\n\nif [[ $? -eq 0 ]] ; then\n echo -e "\\n== Failed to migrate. Running setup first. ==\\n"\n bundle exec rails db:setup\nfi\n\n# Execute the given or default command:\n\nexec "$@"\n')),Object(a.b)("p",null,"This script will execute the Rails database migration script. If it fails because the database doesn't exist, it will run the setup command instead."),Object(a.b)("p",null,"The last line is necessary to execute the main command of your Dockerfile."),Object(a.b)(c.a,{type:"warning",mdxType:"Alert"},"These instructions will be executed on each running instances of your application. If you're running multiple instances (or autoscaling), make sure instructions in the entrypoint are idempotent.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"give-execution-permission-to-the-entrypoint-script"},"Give execution permission to the entrypoint script"),Object(a.b)("p",null,"You can give execution permission to this file with the following command:"),Object(a.b)("p",null,Object(a.b)("inlineCode",{parentName:"p"},"chmod +x docker/entrypoint.sh"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-the-entrypoint-to-your-dockerfile"},"Add the entrypoint to your Dockerfile"),Object(a.b)("p",null,"You will now need to add an ENTRYPOINT instruction to your Dockerfile. (Make sure the entrypoint.sh file is copied to the image somewhere)"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'# ...\n\n# Dockerfile content omitted for brevity\n\n# ...\n\nENTRYPOINT ["./docker/entrypoint.sh"]\n\nEXPOSE 3000\n\nCMD ["rails", "server", "-p", "3000", "-b", "0.0.0.0"]\n')),Object(a.b)("p",null,"You can learn more about Docker entrypoints here: ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.docker.com/engine/reference/builder/#entrypoint"}),"https://docs.docker.com/engine/reference/builder/#entrypoint"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"deploy-your-application"},"Deploy your application"),Object(a.b)("p",null,"You can now commit and push your changes to your Git repository. The instructions you specified in the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"http://entrypoint.sh/"}),"entrypoint.sh")," file will be executed before the application starts.")))),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},"Lifecycle hooks and shell access will shortly be available on Qovery. You'll be able to manage this more conveniently."))}f.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),l=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),f=r,m=p["".concat(i,".").concat(f)]||p[f]||d[f]||a;return n?o.a.createElement(m,c({ref:t},u,{components:n})):o.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,u=void 0===s?n:o(s,n);u>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(430),s=n(20),u=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,l=n||s,p=Object(c.a)(l),d=Object(o.useRef)(!1),f=u.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!f&&p&&window.docusaurus.prefetch(l),function(){f&&t&&t.disconnect()}}),[l,f,p]),l&&p?a.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(l),d.current=!0)},innerRef:function(e){var n,r;f&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(l)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:l})):a.a.createElement("a",Object(r.a)({},e,{href:l}))}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,d=c()("jump-to","jump-to--"+u,n),f=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return l?o.a.createElement("a",{href:p,target:l,className:d},f):o.a.createElement(a.a,{to:p,className:d},f)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),p=l[0],d=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 1d3be599.4e669d3d.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[38],{190:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return f}));var r=n(1),o=n(9),a=(n(0),n(425)),i=n(434),c=n(424),s=n(429),u=(n(431),{last_modified_on:"2022-09-30",$schema:"/.meta/.schemas/guides.json",title:"How to run commands before the application starts",description:"How to run commands before a Qovery application starts",author_github:"https://github.com/l0ck3",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to run commands before the application starts",description:"How to run commands before a Qovery application starts",permalink:"/guides/tutorial/how-to-run-commands-at-application-startup",readingTime:"3 min read",source:"@site/guides/tutorial/how-to-run-commands-at-application-startup.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to run commands before the application starts",truncated:!1,prevItem:{title:"How to integrate Qovery with GitHub Actions",permalink:"/guides/tutorial/how-to-integrate-qovery-with-github-actions"},nextItem:{title:"How to seed a Postgres database on a dev environment",permalink:"/guides/tutorial/data-seeding-in-postgres"}},p=[{value:"Goal",id:"goal",children:[]}],d={rightToc:p};function f(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Running your applications on Qovery is pretty straightforward, but there are many cases where you will need to run some tasks before your application starts, like running database migrations, and it might not be obvious how to do it."),Object(a.b)(s.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Your app is running in Dockerfile mode."))),Object(a.b)("h2",{id:"goal"},"Goal"),Object(a.b)("p",null,"This tutorial will cover how to run tasks when your application is starting. We'll use the case of a database migration with Ruby on Rails, but the same principle can be applied for any framework or command you need to run."),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"add-an-entrypoint-script"},"Add an entrypoint script"),Object(a.b)("p",null,"The first thing to do is to add an entrypoint script. We'll add it to a docker directory at the project's root, but you can put it anywhere you want."),Object(a.b)("p",null,"Let's create the docker/entrypoint.sh with the following content:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'#! /bin/sh\n\nbundle exec rails db:migrate\n\nif [[ $? -eq 0 ]] ; then\n echo -e "\\n== Failed to migrate. Running setup first. ==\\n"\n bundle exec rails db:setup\nfi\n\n# Execute the given or default command:\n\nexec "$@"\n')),Object(a.b)("p",null,"This script will execute the Rails database migration script. If it fails because the database doesn't exist, it will run the setup command instead."),Object(a.b)("p",null,"The last line is necessary to execute the main command of your Dockerfile."),Object(a.b)(c.a,{type:"warning",mdxType:"Alert"},"These instructions will be executed on each running instances of your application. If you're running multiple instances (or autoscaling), make sure instructions in the entrypoint are idempotent.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"give-execution-permission-to-the-entrypoint-script"},"Give execution permission to the entrypoint script"),Object(a.b)("p",null,"You can give execution permission to this file with the following command:"),Object(a.b)("p",null,Object(a.b)("inlineCode",{parentName:"p"},"chmod +x docker/entrypoint.sh"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-the-entrypoint-to-your-dockerfile"},"Add the entrypoint to your Dockerfile"),Object(a.b)("p",null,"You will now need to add an ENTRYPOINT instruction to your Dockerfile. (Make sure the entrypoint.sh file is copied to the image somewhere)"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'# ...\n\n# Dockerfile content omitted for brevity\n\n# ...\n\nENTRYPOINT ["./docker/entrypoint.sh"]\n\nEXPOSE 3000\n\nCMD ["rails", "server", "-p", "3000", "-b", "0.0.0.0"]\n')),Object(a.b)("p",null,"You can learn more about Docker entrypoints here: ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.docker.com/engine/reference/builder/#entrypoint"}),"https://docs.docker.com/engine/reference/builder/#entrypoint"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"deploy-your-application"},"Deploy your application"),Object(a.b)("p",null,"You can now commit and push your changes to your Git repository. The instructions you specified in the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"http://entrypoint.sh/"}),"entrypoint.sh")," file will be executed before the application starts.")))),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},"Lifecycle hooks and shell access will shortly be available on Qovery. You'll be able to manage this more conveniently."))}f.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),l=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),f=r,m=p["".concat(i,".").concat(f)]||p[f]||d[f]||a;return n?o.a.createElement(m,c({ref:t},u,{components:n})):o.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,u=void 0===s?n:o(s,n);u>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(432),s=n(20),u=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,l=n||s,p=Object(c.a)(l),d=Object(o.useRef)(!1),f=u.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!f&&p&&window.docusaurus.prefetch(l),function(){f&&t&&t.disconnect()}}),[l,f,p]),l&&p?a.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(l),d.current=!0)},innerRef:function(e){var n,r;f&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(l)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:l})):a.a.createElement("a",Object(r.a)({},e,{href:l}))}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,d=c()("jump-to","jump-to--"+u,n),f=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return l?o.a.createElement("a",{href:p,target:l,className:d},f):o.a.createElement(a.a,{to:p,className:d},f)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),p=l[0],d=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/1dd2c233.fc271294.js.LICENSE.txt b/1d3be599.4e669d3d.js.LICENSE.txt similarity index 100% rename from 1dd2c233.fc271294.js.LICENSE.txt rename to 1d3be599.4e669d3d.js.LICENSE.txt diff --git a/498daee8.6c30e0e2.js b/1dd2c233.62f8eba6.js similarity index 93% rename from 498daee8.6c30e0e2.js rename to 1dd2c233.62f8eba6.js index 99beb32fce..d010656d0c 100644 --- a/498daee8.6c30e0e2.js +++ b/1dd2c233.62f8eba6.js @@ -1,2 +1,2 @@ -/*! For license information please see 498daee8.6c30e0e2.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[83],{235:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return l})),r.d(t,"rightToc",(function(){return u})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),o=(r(0),r(422)),c=(r(431),r(426),r(421)),i={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Deploy Frontend App",description:"Learn how to deploy your Frontend app with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","language: javascript"]},l={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Deploy Frontend App",description:"Learn how to deploy your Frontend app with Qovery",permalink:"/guides/advanced/deploy-frontend",readingTime:"2 min read",source:"@site/guides/advanced/deploy-frontend.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"language: javascript",permalink:"/guides/tags/language-javascript"}],title:"Deploy Frontend App",truncated:!1,prevItem:{title:"Deploy External Services",permalink:"/guides/advanced/deploy-external-services"},nextItem:{title:"Deploy Rails with PostgreSQL and Sidekiq",permalink:"/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq"}},u=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:u};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery is versatile and has the ability to cater to a wide range of frontend applications. Whether you're working with a Single-Page\nApplication (SPA), a Server-Side Rendered (SSR) applications, or a general web app, Qovery has you covered."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to deploy your different type of Frontend apps with Qovery."),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Most Frontend apps does not require to have much CPU and RAM resources allocated to them at runtime.\nYou can use 100 mCPU and 128 MiB of RAM for most of them."),Object(o.b)("p",null,"However, build time can be very CPU and RAM intensive. Qovery provides default build resources for each type of Frontend app.\nYou can change them in your ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/advanced-settings/"}),"app advanced settings"),".")),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy SPA container")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy your frontend SPA (React) app inside a container with a NGINX web server")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy SPA container with Cloudfront")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy your frontend SPA (React) app inside a container with a NGINX web server and expose it via Cloudfront CDN")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery/"}),"Use Cloudflare as a CDN")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery/"}),"Use Cloudflare as a CDN for your frontend SPA (React) app")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy SSR container"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy your frontend SSR (NextJS) app inside a container with a NGINX web server"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy SSR on Cloudfront"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy your frontend SSR (NextJS) app on AWS Cloudfront"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=react"}),'"React" forum threads')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=react"}),'List "React" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=nextjs"}),'"NextJS" forum threads')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=nextjs"}),'List "NextJS" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=angular"}),'"Angular" forum threads')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=angular"}),'List "Angular" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},420:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),b=n,m=p["".concat(c,".").concat(b)]||p[b]||d[b]||o;return r?a.a.createElement(m,i({ref:t},u,{components:r})):a.a.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,c=new Array(o);c[0]=b;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var u=2;u1?arguments[1]:void 0,r),l=c>2?arguments[2]:void 0,u=void 0===l?r:a(l,r);u>i;)t[i++]=e;return t}},425:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,r){"use strict";r(425);var n=r(0),a=r.n(n),o=r(421);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},428:function(e,t,r){"use strict";var n=r(432),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var c=[];return a.slice().forEach((function(e){void 0!==e&&c.push(r(n,e,c.length))})),c.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(420),r(428)),c=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(n.useState)(null),p=s[0],d=s[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 1dd2c233.62f8eba6.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[39],{191:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return l})),r.d(t,"rightToc",(function(){return u})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),o=(r(0),r(425)),c=(r(434),r(429),r(424)),i={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Deploy Frontend App",description:"Learn how to deploy your Frontend app with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","language: javascript"]},l={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Deploy Frontend App",description:"Learn how to deploy your Frontend app with Qovery",permalink:"/guides/advanced/deploy-frontend",readingTime:"2 min read",source:"@site/guides/advanced/deploy-frontend.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"language: javascript",permalink:"/guides/tags/language-javascript"}],title:"Deploy Frontend App",truncated:!1,prevItem:{title:"Deploy External Services",permalink:"/guides/advanced/deploy-external-services"},nextItem:{title:"Deploy Rails with PostgreSQL and Sidekiq",permalink:"/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq"}},u=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:u};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery is versatile and has the ability to cater to a wide range of frontend applications. Whether you're working with a Single-Page\nApplication (SPA), a Server-Side Rendered (SSR) applications, or a general web app, Qovery has you covered."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to deploy your different type of Frontend apps with Qovery."),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Most Frontend apps does not require to have much CPU and RAM resources allocated to them at runtime.\nYou can use 100 mCPU and 128 MiB of RAM for most of them."),Object(o.b)("p",null,"However, build time can be very CPU and RAM intensive. Qovery provides default build resources for each type of Frontend app.\nYou can change them in your ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/advanced-settings/"}),"app advanced settings"),".")),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy SPA container")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy your frontend SPA (React) app inside a container with a NGINX web server")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy SPA container with Cloudfront")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy your frontend SPA (React) app inside a container with a NGINX web server and expose it via Cloudfront CDN")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery/"}),"Use Cloudflare as a CDN")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery/"}),"Use Cloudflare as a CDN for your frontend SPA (React) app")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy SSR container"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy your frontend SSR (NextJS) app inside a container with a NGINX web server"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy SSR on Cloudfront"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy your frontend SSR (NextJS) app on AWS Cloudfront"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=react"}),'"React" forum threads')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=react"}),'List "React" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=nextjs"}),'"NextJS" forum threads')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=nextjs"}),'List "NextJS" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=angular"}),'"Angular" forum threads')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=angular"}),'List "Angular" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),b=n,m=p["".concat(c,".").concat(b)]||p[b]||d[b]||o;return r?a.a.createElement(m,i({ref:t},u,{components:r})):a.a.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,c=new Array(o);c[0]=b;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var u=2;u1?arguments[1]:void 0,r),l=c>2?arguments[2]:void 0,u=void 0===l?r:a(l,r);u>i;)t[i++]=e;return t}},428:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,r){"use strict";r(428);var n=r(0),a=r.n(n),o=r(424);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},433:function(e,t,r){"use strict";var n=r(435),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var c=[];return a.slice().forEach((function(e){void 0!==e&&c.push(r(n,e,c.length))})),c.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(423),r(433)),c=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(n.useState)(null),p=s[0],d=s[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/228c86a3.fdea663b.js.LICENSE.txt b/1dd2c233.62f8eba6.js.LICENSE.txt similarity index 100% rename from 228c86a3.fdea663b.js.LICENSE.txt rename to 1dd2c233.62f8eba6.js.LICENSE.txt diff --git a/2.078c09af.js b/2.27ebdbf7.js similarity index 92% rename from 2.078c09af.js rename to 2.27ebdbf7.js index beb99ae078..fbd2677e23 100644 --- a/2.078c09af.js +++ b/2.27ebdbf7.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{427:function(t,e,n){"use strict";var r=n(1),o=n(0),i=n.n(o),a=n(39),c=n(430),u=n(20),s=n.n(u);e.a=function(t){var e,n=t.to,u=t.href,f=n||u,l=Object(c.a)(f),p=Object(o.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&l&&window.docusaurus.prefetch(f),function(){d&&e&&e.disconnect()}}),[f,d,l]),f&&l?i.a.createElement(a.b,Object(r.a)({},t,{onMouseEnter:function(){p.current||(window.docusaurus.preload(f),p.current=!0)},innerRef:function(t){var n,r;d&&t&&l&&(n=t,r=function(){window.docusaurus.prefetch(f)},(e=new window.IntersectionObserver((function(t){t.forEach((function(t){n===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(e.unobserve(n),e.disconnect(),r())}))}))).observe(n))},to:f})):i.a.createElement("a",Object(r.a)({},t,{href:f}))}},430:function(t,e,n){"use strict";function r(t){return!1===/^(https?:|\/\/)/.test(t)}n.d(e,"a",(function(){return r}))},433:function(t,e,n){"use strict";var r=n(0),o=n(69);e.a=function(){return Object(r.useContext)(o.a)}},435:function(t,e,n){"use strict";n.d(e,"a",(function(){return o}));n(470);var r=n(433);function o(t){var e=(Object(r.a)().siteConfig||{}).baseUrl,n=void 0===e?"/":e;if(!t)return t;return/^(https?:|\/\/)/.test(t)?t:t.startsWith("/")?n+t.slice(1):n+t}},440:function(t,e,n){"use strict";var r=n(0),o=n.n(r),i=n(581);e.a=function(t){return o.a.createElement(i.a,t)}},443:function(t,e,n){"use strict";var r=n(12),o=n(96)(!0);r(r.P,"Array",{includes:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}}),n(74)("includes")},444:function(t,e,n){"use strict";var r=n(12),o=n(514);r(r.P+r.F*n(515)("includes"),"String",{includes:function(t){return!!~o(this,t,"includes").indexOf(t,arguments.length>1?arguments[1]:void 0)}})},470:function(t,e,n){"use strict";var r=n(12),o=n(26),i=n(514),a="".startsWith;r(r.P+r.F*n(515)("startsWith"),"String",{startsWith:function(t){var e=i(this,t,"startsWith"),n=o(Math.min(arguments.length>1?arguments[1]:void 0,e.length)),r=String(t);return a?a.call(e,r,n):e.slice(n,n+r.length)===r}})},514:function(t,e,n){var r=n(95),o=n(34);t.exports=function(t,e,n){if(r(e))throw TypeError("String#"+n+" doesn't accept regex!");return String(o(t))}},515:function(t,e,n){var r=n(2)("match");t.exports=function(t){var e=/./;try{"/./"[t](e)}catch(n){try{return e[r]=!1,!"/./"[t](e)}catch(o){}}return!0}},581:function(t,e,n){"use strict";(function(t){n.d(e,"a",(function(){return yt}));var r,o,i,a,c=n(15),u=n.n(c),s=n(582),f=n.n(s),l=n(583),p=n.n(l),d=n(0),h=n.n(d),y=n(51),m=n.n(y),b="bodyAttributes",v="htmlAttributes",T="titleAttributes",g={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title"},w=(Object.keys(g).map((function(t){return g[t]})),"charset"),O="cssText",A="href",C="http-equiv",E="innerHTML",S="itemprop",j="name",P="property",k="rel",x="src",I="target",L={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},M="defaultTitle",R="defer",N="encodeSpecialCharacters",D="onChangeClientState",H="titleTemplate",q=Object.keys(L).reduce((function(t,e){return t[L[e]]=e,t}),{}),F=[g.NOSCRIPT,g.SCRIPT,g.STYLE],_="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},U=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},Y=function(){function t(t,e){for(var n=0;n=0||Object.prototype.hasOwnProperty.call(t,r)&&(n[r]=t[r]);return n},K=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e},z=function(t){var e=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];return!1===e?String(t):String(t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")},J=function(t){var e=X(t,g.TITLE),n=X(t,H);if(n&&e)return n.replace(/%s/g,(function(){return Array.isArray(e)?e.join(""):e}));var r=X(t,M);return e||r||void 0},$=function(t){return X(t,D)||function(){}},G=function(t,e){return e.filter((function(e){return void 0!==e[t]})).map((function(e){return e[t]})).reduce((function(t,e){return B({},t,e)}),{})},Q=function(t,e){return e.filter((function(t){return void 0!==t[g.BASE]})).map((function(t){return t[g.BASE]})).reverse().reduce((function(e,n){if(!e.length)for(var r=Object.keys(n),o=0;o=0;n--){var r=t[n];if(r.hasOwnProperty(e))return r[e]}return null},Z=(r=Date.now(),function(t){var e=Date.now();e-r>16?(r=e,t(e)):setTimeout((function(){Z(t)}),0)}),tt=function(t){return clearTimeout(t)},et="undefined"!=typeof window?window.requestAnimationFrame&&window.requestAnimationFrame.bind(window)||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||Z:t.requestAnimationFrame||Z,nt="undefined"!=typeof window?window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||tt:t.cancelAnimationFrame||tt,rt=function(t){return console&&"function"==typeof console.warn&&console.warn(t)},ot=null,it=function(t,e){var n=t.baseTag,r=t.bodyAttributes,o=t.htmlAttributes,i=t.linkTags,a=t.metaTags,c=t.noscriptTags,u=t.onChangeClientState,s=t.scriptTags,f=t.styleTags,l=t.title,p=t.titleAttributes;ut(g.BODY,r),ut(g.HTML,o),ct(l,p);var d={baseTag:st(g.BASE,n),linkTags:st(g.LINK,i),metaTags:st(g.META,a),noscriptTags:st(g.NOSCRIPT,c),scriptTags:st(g.SCRIPT,s),styleTags:st(g.STYLE,f)},h={},y={};Object.keys(d).forEach((function(t){var e=d[t],n=e.newTags,r=e.oldTags;n.length&&(h[t]=n),r.length&&(y[t]=d[t].oldTags)})),e&&e(),u(t,h,y)},at=function(t){return Array.isArray(t)?t.join(""):t},ct=function(t,e){void 0!==t&&document.title!==t&&(document.title=at(t)),ut(g.TITLE,e)},ut=function(t,e){var n=document.getElementsByTagName(t)[0];if(n){for(var r=n.getAttribute("data-react-helmet"),o=r?r.split(","):[],i=[].concat(o),a=Object.keys(e),c=0;c=0;l--)n.removeAttribute(i[l]);o.length===i.length?n.removeAttribute("data-react-helmet"):n.getAttribute("data-react-helmet")!==a.join(",")&&n.setAttribute("data-react-helmet",a.join(","))}},st=function(t,e){var n=document.head||document.querySelector(g.HEAD),r=n.querySelectorAll(t+"[data-react-helmet]"),o=Array.prototype.slice.call(r),i=[],a=void 0;return e&&e.length&&e.forEach((function(e){var n=document.createElement(t);for(var r in e)if(e.hasOwnProperty(r))if(r===E)n.innerHTML=e.innerHTML;else if(r===O)n.styleSheet?n.styleSheet.cssText=e.cssText:n.appendChild(document.createTextNode(e.cssText));else{var c=void 0===e[r]?"":e[r];n.setAttribute(r,c)}n.setAttribute("data-react-helmet","true"),o.some((function(t,e){return a=e,n.isEqualNode(t)}))?o.splice(a,1):i.push(n)})),o.forEach((function(t){return t.parentNode.removeChild(t)})),i.forEach((function(t){return n.appendChild(t)})),{oldTags:o,newTags:i}},ft=function(t){return Object.keys(t).reduce((function(e,n){var r=void 0!==t[n]?n+'="'+t[n]+'"':""+n;return e?e+" "+r:r}),"")},lt=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return Object.keys(t).reduce((function(e,n){return e[L[n]||n]=t[n],e}),e)},pt=function(t,e,n){switch(t){case g.TITLE:return{toComponent:function(){return t=e.title,n=e.titleAttributes,(r={key:t})["data-react-helmet"]=!0,o=lt(n,r),[h.a.createElement(g.TITLE,o,t)];var t,n,r,o},toString:function(){return function(t,e,n,r){var o=ft(n),i=at(e);return o?"<"+t+' data-react-helmet="true" '+o+">"+z(i,r)+"":"<"+t+' data-react-helmet="true">'+z(i,r)+""}(t,e.title,e.titleAttributes,n)}};case b:case v:return{toComponent:function(){return lt(e)},toString:function(){return ft(e)}};default:return{toComponent:function(){return function(t,e){return e.map((function(e,n){var r,o=((r={key:n})["data-react-helmet"]=!0,r);return Object.keys(e).forEach((function(t){var n=L[t]||t;if(n===E||n===O){var r=e.innerHTML||e.cssText;o.dangerouslySetInnerHTML={__html:r}}else o[n]=e[t]})),h.a.createElement(t,o)}))}(t,e)},toString:function(){return function(t,e,n){return e.reduce((function(e,r){var o=Object.keys(r).filter((function(t){return!(t===E||t===O)})).reduce((function(t,e){var o=void 0===r[e]?e:e+'="'+z(r[e],n)+'"';return t?t+" "+o:o}),""),i=r.innerHTML||r.cssText||"",a=-1===F.indexOf(t);return e+"<"+t+' data-react-helmet="true" '+o+(a?"/>":">"+i+"")}),"")}(t,e,n)}}}},dt=function(t){var e=t.baseTag,n=t.bodyAttributes,r=t.encode,o=t.htmlAttributes,i=t.linkTags,a=t.metaTags,c=t.noscriptTags,u=t.scriptTags,s=t.styleTags,f=t.title,l=void 0===f?"":f,p=t.titleAttributes;return{base:pt(g.BASE,e,r),bodyAttributes:pt(b,n,r),htmlAttributes:pt(v,o,r),link:pt(g.LINK,i,r),meta:pt(g.META,a,r),noscript:pt(g.NOSCRIPT,c,r),script:pt(g.SCRIPT,u,r),style:pt(g.STYLE,s,r),title:pt(g.TITLE,{title:l,titleAttributes:p},r)}},ht=f()((function(t){return{baseTag:Q([A,I],t),bodyAttributes:G(b,t),defer:X(t,R),encode:X(t,N),htmlAttributes:G(v,t),linkTags:V(g.LINK,[k,A],t),metaTags:V(g.META,[j,w,C,P,S],t),noscriptTags:V(g.NOSCRIPT,[E],t),onChangeClientState:$(t),scriptTags:V(g.SCRIPT,[x,E],t),styleTags:V(g.STYLE,[O],t),title:J(t),titleAttributes:G(T,t)}}),(function(t){ot&&nt(ot),t.defer?ot=et((function(){it(t,(function(){ot=null}))})):(it(t),ot=null)}),dt)((function(){return null})),yt=(o=ht,a=i=function(t){function e(){return U(this,e),K(this,t.apply(this,arguments))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,t),e.prototype.shouldComponentUpdate=function(t){return!p()(this.props,t)},e.prototype.mapNestedChildrenToProps=function(t,e){if(!e)return null;switch(t.type){case g.SCRIPT:case g.NOSCRIPT:return{innerHTML:e};case g.STYLE:return{cssText:e}}throw new Error("<"+t.type+" /> elements are self-closing and can not contain children. Refer to our API for more information.")},e.prototype.flattenArrayTypeChildren=function(t){var e,n=t.child,r=t.arrayTypeChildren,o=t.newChildProps,i=t.nestedChildren;return B({},r,((e={})[n.type]=[].concat(r[n.type]||[],[B({},o,this.mapNestedChildrenToProps(n,i))]),e))},e.prototype.mapObjectTypeChildren=function(t){var e,n,r=t.child,o=t.newProps,i=t.newChildProps,a=t.nestedChildren;switch(r.type){case g.TITLE:return B({},o,((e={})[r.type]=a,e.titleAttributes=B({},i),e));case g.BODY:return B({},o,{bodyAttributes:B({},i)});case g.HTML:return B({},o,{htmlAttributes:B({},i)})}return B({},o,((n={})[r.type]=B({},i),n))},e.prototype.mapArrayTypeChildrenToProps=function(t,e){var n=B({},e);return Object.keys(t).forEach((function(e){var r;n=B({},n,((r={})[e]=t[e],r))})),n},e.prototype.warnOnInvalidChildren=function(t,e){return!0},e.prototype.mapChildrenToProps=function(t,e){var n=this,r={};return h.a.Children.forEach(t,(function(t){if(t&&t.props){var o=t.props,i=o.children,a=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return Object.keys(t).reduce((function(e,n){return e[q[n]||n]=t[n],e}),e)}(W(o,["children"]));switch(n.warnOnInvalidChildren(t,i),t.type){case g.LINK:case g.META:case g.NOSCRIPT:case g.SCRIPT:case g.STYLE:r=n.flattenArrayTypeChildren({child:t,arrayTypeChildren:r,newChildProps:a,nestedChildren:i});break;default:e=n.mapObjectTypeChildren({child:t,newProps:e,newChildProps:a,nestedChildren:i})}}})),e=this.mapArrayTypeChildrenToProps(r,e)},e.prototype.render=function(){var t=this.props,e=t.children,n=W(t,["children"]),r=B({},n);return e&&(r=this.mapChildrenToProps(e,r)),h.a.createElement(o,r)},Y(e,null,[{key:"canUseDOM",set:function(t){o.canUseDOM=t}}]),e}(h.a.Component),i.propTypes={base:u.a.object,bodyAttributes:u.a.object,children:u.a.oneOfType([u.a.arrayOf(u.a.node),u.a.node]),defaultTitle:u.a.string,defer:u.a.bool,encodeSpecialCharacters:u.a.bool,htmlAttributes:u.a.object,link:u.a.arrayOf(u.a.object),meta:u.a.arrayOf(u.a.object),noscript:u.a.arrayOf(u.a.object),onChangeClientState:u.a.func,script:u.a.arrayOf(u.a.object),style:u.a.arrayOf(u.a.object),title:u.a.string,titleAttributes:u.a.object,titleTemplate:u.a.string},i.defaultProps={defer:!0,encodeSpecialCharacters:!0},i.peek=o.peek,i.rewind=function(){var t=o.rewind();return t||(t=dt({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}})),t},a);yt.renderStatic=yt.rewind}).call(this,n(76))},582:function(t,e,n){"use strict";var r,o=n(0),i=(r=o)&&"object"==typeof r&&"default"in r?r.default:r;function a(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var c=!("undefined"==typeof window||!window.document||!window.document.createElement);t.exports=function(t,e,n){if("function"!=typeof t)throw new Error("Expected reducePropsToState to be a function.");if("function"!=typeof e)throw new Error("Expected handleStateChangeOnClient to be a function.");if(void 0!==n&&"function"!=typeof n)throw new Error("Expected mapStateOnServer to either be undefined or a function.");return function(r){if("function"!=typeof r)throw new Error("Expected WrappedComponent to be a React component.");var u,s=[];function f(){u=t(s.map((function(t){return t.props}))),l.canUseDOM?e(u):n&&(u=n(u))}var l=function(t){var e,n;function o(){return t.apply(this,arguments)||this}n=t,(e=o).prototype=Object.create(n.prototype),e.prototype.constructor=e,e.__proto__=n,o.peek=function(){return u},o.rewind=function(){if(o.canUseDOM)throw new Error("You may only call rewind() on the server. Call peek() to read the current state.");var t=u;return u=void 0,s=[],t};var a=o.prototype;return a.UNSAFE_componentWillMount=function(){s.push(this),f()},a.componentDidUpdate=function(){f()},a.componentWillUnmount=function(){var t=s.indexOf(this);s.splice(t,1),f()},a.render=function(){return i.createElement(r,this.props)},o}(o.PureComponent);return a(l,"displayName","SideEffect("+function(t){return t.displayName||t.name||"Component"}(r)+")"),a(l,"canUseDOM",c),l}}},583:function(t,e,n){"use strict";var r=Array.isArray,o=Object.keys,i=Object.prototype.hasOwnProperty,a="undefined"!=typeof Element;t.exports=function(t,e){try{return function t(e,n){if(e===n)return!0;if(e&&n&&"object"==typeof e&&"object"==typeof n){var c,u,s,f=r(e),l=r(n);if(f&&l){if((u=e.length)!=n.length)return!1;for(c=u;0!=c--;)if(!t(e[c],n[c]))return!1;return!0}if(f!=l)return!1;var p=e instanceof Date,d=n instanceof Date;if(p!=d)return!1;if(p&&d)return e.getTime()==n.getTime();var h=e instanceof RegExp,y=n instanceof RegExp;if(h!=y)return!1;if(h&&y)return e.toString()==n.toString();var m=o(e);if((u=m.length)!==o(n).length)return!1;for(c=u;0!=c--;)if(!i.call(n,m[c]))return!1;if(a&&e instanceof Element&&n instanceof Element)return e===n;for(c=u;0!=c--;)if(!("_owner"===(s=m[c])&&e.$$typeof||t(e[s],n[s])))return!1;return!0}return e!=e&&n!=n}(t,e)}catch(n){if(n.message&&n.message.match(/stack|recursion/i)||-2146828260===n.number)return console.warn("Warning: react-fast-compare does not handle circular references.",n.name,n.message),!1;throw n}}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{430:function(t,e,n){"use strict";var r=n(1),o=n(0),i=n.n(o),a=n(39),c=n(432),u=n(20),s=n.n(u);e.a=function(t){var e,n=t.to,u=t.href,f=n||u,l=Object(c.a)(f),p=Object(o.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&l&&window.docusaurus.prefetch(f),function(){d&&e&&e.disconnect()}}),[f,d,l]),f&&l?i.a.createElement(a.b,Object(r.a)({},t,{onMouseEnter:function(){p.current||(window.docusaurus.preload(f),p.current=!0)},innerRef:function(t){var n,r;d&&t&&l&&(n=t,r=function(){window.docusaurus.prefetch(f)},(e=new window.IntersectionObserver((function(t){t.forEach((function(t){n===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(e.unobserve(n),e.disconnect(),r())}))}))).observe(n))},to:f})):i.a.createElement("a",Object(r.a)({},t,{href:f}))}},432:function(t,e,n){"use strict";function r(t){return!1===/^(https?:|\/\/)/.test(t)}n.d(e,"a",(function(){return r}))},436:function(t,e,n){"use strict";var r=n(0),o=n(69);e.a=function(){return Object(r.useContext)(o.a)}},438:function(t,e,n){"use strict";n.d(e,"a",(function(){return o}));n(473);var r=n(436);function o(t){var e=(Object(r.a)().siteConfig||{}).baseUrl,n=void 0===e?"/":e;if(!t)return t;return/^(https?:|\/\/)/.test(t)?t:t.startsWith("/")?n+t.slice(1):n+t}},443:function(t,e,n){"use strict";var r=n(0),o=n.n(r),i=n(584);e.a=function(t){return o.a.createElement(i.a,t)}},446:function(t,e,n){"use strict";var r=n(12),o=n(96)(!0);r(r.P,"Array",{includes:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}}),n(74)("includes")},447:function(t,e,n){"use strict";var r=n(12),o=n(517);r(r.P+r.F*n(518)("includes"),"String",{includes:function(t){return!!~o(this,t,"includes").indexOf(t,arguments.length>1?arguments[1]:void 0)}})},473:function(t,e,n){"use strict";var r=n(12),o=n(26),i=n(517),a="".startsWith;r(r.P+r.F*n(518)("startsWith"),"String",{startsWith:function(t){var e=i(this,t,"startsWith"),n=o(Math.min(arguments.length>1?arguments[1]:void 0,e.length)),r=String(t);return a?a.call(e,r,n):e.slice(n,n+r.length)===r}})},517:function(t,e,n){var r=n(95),o=n(34);t.exports=function(t,e,n){if(r(e))throw TypeError("String#"+n+" doesn't accept regex!");return String(o(t))}},518:function(t,e,n){var r=n(2)("match");t.exports=function(t){var e=/./;try{"/./"[t](e)}catch(n){try{return e[r]=!1,!"/./"[t](e)}catch(o){}}return!0}},584:function(t,e,n){"use strict";(function(t){n.d(e,"a",(function(){return yt}));var r,o,i,a,c=n(15),u=n.n(c),s=n(585),f=n.n(s),l=n(586),p=n.n(l),d=n(0),h=n.n(d),y=n(51),m=n.n(y),b="bodyAttributes",v="htmlAttributes",T="titleAttributes",g={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title"},w=(Object.keys(g).map((function(t){return g[t]})),"charset"),O="cssText",A="href",C="http-equiv",E="innerHTML",S="itemprop",j="name",P="property",k="rel",x="src",I="target",L={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},M="defaultTitle",R="defer",N="encodeSpecialCharacters",D="onChangeClientState",H="titleTemplate",q=Object.keys(L).reduce((function(t,e){return t[L[e]]=e,t}),{}),F=[g.NOSCRIPT,g.SCRIPT,g.STYLE],_="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},U=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},Y=function(){function t(t,e){for(var n=0;n=0||Object.prototype.hasOwnProperty.call(t,r)&&(n[r]=t[r]);return n},K=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e},z=function(t){var e=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];return!1===e?String(t):String(t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")},J=function(t){var e=X(t,g.TITLE),n=X(t,H);if(n&&e)return n.replace(/%s/g,(function(){return Array.isArray(e)?e.join(""):e}));var r=X(t,M);return e||r||void 0},$=function(t){return X(t,D)||function(){}},G=function(t,e){return e.filter((function(e){return void 0!==e[t]})).map((function(e){return e[t]})).reduce((function(t,e){return B({},t,e)}),{})},Q=function(t,e){return e.filter((function(t){return void 0!==t[g.BASE]})).map((function(t){return t[g.BASE]})).reverse().reduce((function(e,n){if(!e.length)for(var r=Object.keys(n),o=0;o=0;n--){var r=t[n];if(r.hasOwnProperty(e))return r[e]}return null},Z=(r=Date.now(),function(t){var e=Date.now();e-r>16?(r=e,t(e)):setTimeout((function(){Z(t)}),0)}),tt=function(t){return clearTimeout(t)},et="undefined"!=typeof window?window.requestAnimationFrame&&window.requestAnimationFrame.bind(window)||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||Z:t.requestAnimationFrame||Z,nt="undefined"!=typeof window?window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||tt:t.cancelAnimationFrame||tt,rt=function(t){return console&&"function"==typeof console.warn&&console.warn(t)},ot=null,it=function(t,e){var n=t.baseTag,r=t.bodyAttributes,o=t.htmlAttributes,i=t.linkTags,a=t.metaTags,c=t.noscriptTags,u=t.onChangeClientState,s=t.scriptTags,f=t.styleTags,l=t.title,p=t.titleAttributes;ut(g.BODY,r),ut(g.HTML,o),ct(l,p);var d={baseTag:st(g.BASE,n),linkTags:st(g.LINK,i),metaTags:st(g.META,a),noscriptTags:st(g.NOSCRIPT,c),scriptTags:st(g.SCRIPT,s),styleTags:st(g.STYLE,f)},h={},y={};Object.keys(d).forEach((function(t){var e=d[t],n=e.newTags,r=e.oldTags;n.length&&(h[t]=n),r.length&&(y[t]=d[t].oldTags)})),e&&e(),u(t,h,y)},at=function(t){return Array.isArray(t)?t.join(""):t},ct=function(t,e){void 0!==t&&document.title!==t&&(document.title=at(t)),ut(g.TITLE,e)},ut=function(t,e){var n=document.getElementsByTagName(t)[0];if(n){for(var r=n.getAttribute("data-react-helmet"),o=r?r.split(","):[],i=[].concat(o),a=Object.keys(e),c=0;c=0;l--)n.removeAttribute(i[l]);o.length===i.length?n.removeAttribute("data-react-helmet"):n.getAttribute("data-react-helmet")!==a.join(",")&&n.setAttribute("data-react-helmet",a.join(","))}},st=function(t,e){var n=document.head||document.querySelector(g.HEAD),r=n.querySelectorAll(t+"[data-react-helmet]"),o=Array.prototype.slice.call(r),i=[],a=void 0;return e&&e.length&&e.forEach((function(e){var n=document.createElement(t);for(var r in e)if(e.hasOwnProperty(r))if(r===E)n.innerHTML=e.innerHTML;else if(r===O)n.styleSheet?n.styleSheet.cssText=e.cssText:n.appendChild(document.createTextNode(e.cssText));else{var c=void 0===e[r]?"":e[r];n.setAttribute(r,c)}n.setAttribute("data-react-helmet","true"),o.some((function(t,e){return a=e,n.isEqualNode(t)}))?o.splice(a,1):i.push(n)})),o.forEach((function(t){return t.parentNode.removeChild(t)})),i.forEach((function(t){return n.appendChild(t)})),{oldTags:o,newTags:i}},ft=function(t){return Object.keys(t).reduce((function(e,n){var r=void 0!==t[n]?n+'="'+t[n]+'"':""+n;return e?e+" "+r:r}),"")},lt=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return Object.keys(t).reduce((function(e,n){return e[L[n]||n]=t[n],e}),e)},pt=function(t,e,n){switch(t){case g.TITLE:return{toComponent:function(){return t=e.title,n=e.titleAttributes,(r={key:t})["data-react-helmet"]=!0,o=lt(n,r),[h.a.createElement(g.TITLE,o,t)];var t,n,r,o},toString:function(){return function(t,e,n,r){var o=ft(n),i=at(e);return o?"<"+t+' data-react-helmet="true" '+o+">"+z(i,r)+"":"<"+t+' data-react-helmet="true">'+z(i,r)+""}(t,e.title,e.titleAttributes,n)}};case b:case v:return{toComponent:function(){return lt(e)},toString:function(){return ft(e)}};default:return{toComponent:function(){return function(t,e){return e.map((function(e,n){var r,o=((r={key:n})["data-react-helmet"]=!0,r);return Object.keys(e).forEach((function(t){var n=L[t]||t;if(n===E||n===O){var r=e.innerHTML||e.cssText;o.dangerouslySetInnerHTML={__html:r}}else o[n]=e[t]})),h.a.createElement(t,o)}))}(t,e)},toString:function(){return function(t,e,n){return e.reduce((function(e,r){var o=Object.keys(r).filter((function(t){return!(t===E||t===O)})).reduce((function(t,e){var o=void 0===r[e]?e:e+'="'+z(r[e],n)+'"';return t?t+" "+o:o}),""),i=r.innerHTML||r.cssText||"",a=-1===F.indexOf(t);return e+"<"+t+' data-react-helmet="true" '+o+(a?"/>":">"+i+"")}),"")}(t,e,n)}}}},dt=function(t){var e=t.baseTag,n=t.bodyAttributes,r=t.encode,o=t.htmlAttributes,i=t.linkTags,a=t.metaTags,c=t.noscriptTags,u=t.scriptTags,s=t.styleTags,f=t.title,l=void 0===f?"":f,p=t.titleAttributes;return{base:pt(g.BASE,e,r),bodyAttributes:pt(b,n,r),htmlAttributes:pt(v,o,r),link:pt(g.LINK,i,r),meta:pt(g.META,a,r),noscript:pt(g.NOSCRIPT,c,r),script:pt(g.SCRIPT,u,r),style:pt(g.STYLE,s,r),title:pt(g.TITLE,{title:l,titleAttributes:p},r)}},ht=f()((function(t){return{baseTag:Q([A,I],t),bodyAttributes:G(b,t),defer:X(t,R),encode:X(t,N),htmlAttributes:G(v,t),linkTags:V(g.LINK,[k,A],t),metaTags:V(g.META,[j,w,C,P,S],t),noscriptTags:V(g.NOSCRIPT,[E],t),onChangeClientState:$(t),scriptTags:V(g.SCRIPT,[x,E],t),styleTags:V(g.STYLE,[O],t),title:J(t),titleAttributes:G(T,t)}}),(function(t){ot&&nt(ot),t.defer?ot=et((function(){it(t,(function(){ot=null}))})):(it(t),ot=null)}),dt)((function(){return null})),yt=(o=ht,a=i=function(t){function e(){return U(this,e),K(this,t.apply(this,arguments))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,t),e.prototype.shouldComponentUpdate=function(t){return!p()(this.props,t)},e.prototype.mapNestedChildrenToProps=function(t,e){if(!e)return null;switch(t.type){case g.SCRIPT:case g.NOSCRIPT:return{innerHTML:e};case g.STYLE:return{cssText:e}}throw new Error("<"+t.type+" /> elements are self-closing and can not contain children. Refer to our API for more information.")},e.prototype.flattenArrayTypeChildren=function(t){var e,n=t.child,r=t.arrayTypeChildren,o=t.newChildProps,i=t.nestedChildren;return B({},r,((e={})[n.type]=[].concat(r[n.type]||[],[B({},o,this.mapNestedChildrenToProps(n,i))]),e))},e.prototype.mapObjectTypeChildren=function(t){var e,n,r=t.child,o=t.newProps,i=t.newChildProps,a=t.nestedChildren;switch(r.type){case g.TITLE:return B({},o,((e={})[r.type]=a,e.titleAttributes=B({},i),e));case g.BODY:return B({},o,{bodyAttributes:B({},i)});case g.HTML:return B({},o,{htmlAttributes:B({},i)})}return B({},o,((n={})[r.type]=B({},i),n))},e.prototype.mapArrayTypeChildrenToProps=function(t,e){var n=B({},e);return Object.keys(t).forEach((function(e){var r;n=B({},n,((r={})[e]=t[e],r))})),n},e.prototype.warnOnInvalidChildren=function(t,e){return!0},e.prototype.mapChildrenToProps=function(t,e){var n=this,r={};return h.a.Children.forEach(t,(function(t){if(t&&t.props){var o=t.props,i=o.children,a=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return Object.keys(t).reduce((function(e,n){return e[q[n]||n]=t[n],e}),e)}(W(o,["children"]));switch(n.warnOnInvalidChildren(t,i),t.type){case g.LINK:case g.META:case g.NOSCRIPT:case g.SCRIPT:case g.STYLE:r=n.flattenArrayTypeChildren({child:t,arrayTypeChildren:r,newChildProps:a,nestedChildren:i});break;default:e=n.mapObjectTypeChildren({child:t,newProps:e,newChildProps:a,nestedChildren:i})}}})),e=this.mapArrayTypeChildrenToProps(r,e)},e.prototype.render=function(){var t=this.props,e=t.children,n=W(t,["children"]),r=B({},n);return e&&(r=this.mapChildrenToProps(e,r)),h.a.createElement(o,r)},Y(e,null,[{key:"canUseDOM",set:function(t){o.canUseDOM=t}}]),e}(h.a.Component),i.propTypes={base:u.a.object,bodyAttributes:u.a.object,children:u.a.oneOfType([u.a.arrayOf(u.a.node),u.a.node]),defaultTitle:u.a.string,defer:u.a.bool,encodeSpecialCharacters:u.a.bool,htmlAttributes:u.a.object,link:u.a.arrayOf(u.a.object),meta:u.a.arrayOf(u.a.object),noscript:u.a.arrayOf(u.a.object),onChangeClientState:u.a.func,script:u.a.arrayOf(u.a.object),style:u.a.arrayOf(u.a.object),title:u.a.string,titleAttributes:u.a.object,titleTemplate:u.a.string},i.defaultProps={defer:!0,encodeSpecialCharacters:!0},i.peek=o.peek,i.rewind=function(){var t=o.rewind();return t||(t=dt({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}})),t},a);yt.renderStatic=yt.rewind}).call(this,n(76))},585:function(t,e,n){"use strict";var r,o=n(0),i=(r=o)&&"object"==typeof r&&"default"in r?r.default:r;function a(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var c=!("undefined"==typeof window||!window.document||!window.document.createElement);t.exports=function(t,e,n){if("function"!=typeof t)throw new Error("Expected reducePropsToState to be a function.");if("function"!=typeof e)throw new Error("Expected handleStateChangeOnClient to be a function.");if(void 0!==n&&"function"!=typeof n)throw new Error("Expected mapStateOnServer to either be undefined or a function.");return function(r){if("function"!=typeof r)throw new Error("Expected WrappedComponent to be a React component.");var u,s=[];function f(){u=t(s.map((function(t){return t.props}))),l.canUseDOM?e(u):n&&(u=n(u))}var l=function(t){var e,n;function o(){return t.apply(this,arguments)||this}n=t,(e=o).prototype=Object.create(n.prototype),e.prototype.constructor=e,e.__proto__=n,o.peek=function(){return u},o.rewind=function(){if(o.canUseDOM)throw new Error("You may only call rewind() on the server. Call peek() to read the current state.");var t=u;return u=void 0,s=[],t};var a=o.prototype;return a.UNSAFE_componentWillMount=function(){s.push(this),f()},a.componentDidUpdate=function(){f()},a.componentWillUnmount=function(){var t=s.indexOf(this);s.splice(t,1),f()},a.render=function(){return i.createElement(r,this.props)},o}(o.PureComponent);return a(l,"displayName","SideEffect("+function(t){return t.displayName||t.name||"Component"}(r)+")"),a(l,"canUseDOM",c),l}}},586:function(t,e,n){"use strict";var r=Array.isArray,o=Object.keys,i=Object.prototype.hasOwnProperty,a="undefined"!=typeof Element;t.exports=function(t,e){try{return function t(e,n){if(e===n)return!0;if(e&&n&&"object"==typeof e&&"object"==typeof n){var c,u,s,f=r(e),l=r(n);if(f&&l){if((u=e.length)!=n.length)return!1;for(c=u;0!=c--;)if(!t(e[c],n[c]))return!1;return!0}if(f!=l)return!1;var p=e instanceof Date,d=n instanceof Date;if(p!=d)return!1;if(p&&d)return e.getTime()==n.getTime();var h=e instanceof RegExp,y=n instanceof RegExp;if(h!=y)return!1;if(h&&y)return e.toString()==n.toString();var m=o(e);if((u=m.length)!==o(n).length)return!1;for(c=u;0!=c--;)if(!i.call(n,m[c]))return!1;if(a&&e instanceof Element&&n instanceof Element)return e===n;for(c=u;0!=c--;)if(!("_owner"===(s=m[c])&&e.$$typeof||t(e[s],n[s])))return!1;return!0}return e!=e&&n!=n}(t,e)}catch(n){if(n.message&&n.message.match(/stack|recursion/i)||-2146828260===n.number)return console.warn("Warning: react-fast-compare does not handle circular references.",n.name,n.message),!1;throw n}}}}]); \ No newline at end of file diff --git a/20ac7829.3162f600.js b/20ac7829.3162f600.js new file mode 100644 index 0000000000..2f3cb13327 --- /dev/null +++ b/20ac7829.3162f600.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[40],{192:function(e){e.exports=JSON.parse('{"docsSidebars":{"docs":[{"type":"category","label":"Getting Started","items":[{"type":"link","label":"hidden","href":"/docs/getting-started"},{"type":"link","label":"What is Qovery?","href":"/docs/getting-started/what-is-qovery"},{"type":"link","label":"How Qovery Works","href":"/docs/getting-started/how-qovery-works"},{"type":"link","label":"Basic Concepts","href":"/docs/getting-started/basic-concepts"},{"type":"link","label":"Install Qovery","href":"/docs/getting-started/install-qovery"},{"type":"link","label":"Deploy my application","href":"/docs/getting-started/deploy-my-app"},{"type":"link","label":"What\'s next?","href":"/docs/getting-started/whats-next"}]},{"type":"category","label":"Usage","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery"},{"type":"category","label":"Interface","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/interface"},{"type":"link","label":"Web interface","href":"/docs/using-qovery/interface/web-interface"},{"type":"link","label":"CLI","href":"/docs/using-qovery/interface/cli"},{"type":"link","label":"REST API","href":"/docs/using-qovery/interface/rest-api"},{"type":"link","label":"Terraform","href":"/docs/using-qovery/interface/terraform-interface"}]},{"type":"category","label":"Integrations","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/integration"},{"type":"link","label":"Git Repository","href":"/docs/using-qovery/integration/git-repository"},{"type":"link","label":"Container Registry","href":"/docs/using-qovery/integration/container-registry"},{"type":"link","label":"Helm Repository","href":"/docs/using-qovery/integration/helm-repository"},{"type":"link","label":"Terraform","href":"/docs/using-qovery/integration/terraform"},{"type":"category","label":"Continuous Integration","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/integration/continuous-integration"},{"type":"link","label":"GitHub Actions","href":"/docs/using-qovery/integration/continuous-integration/github-actions"},{"type":"link","label":"GitLab CI","href":"/docs/using-qovery/integration/continuous-integration/gitlab-ci"},{"type":"link","label":"Circle CI","href":"/docs/using-qovery/integration/continuous-integration/circle-ci"},{"type":"link","label":"Jenkins","href":"/docs/using-qovery/integration/continuous-integration/jenkins"}]},{"type":"category","label":"Monitoring","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/integration/monitoring"},{"type":"link","label":"Datadog","href":"/docs/using-qovery/integration/monitoring/datadog"},{"type":"link","label":"New Relic","href":"/docs/using-qovery/integration/monitoring/new-relic"}]},{"type":"category","label":"Secret Manager","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/integration/secret-manager"},{"type":"link","label":"Doppler","href":"/docs/using-qovery/integration/secret-manager/doppler"},{"type":"link","label":"AWS Secrets Manager","href":"/docs/using-qovery/integration/secret-manager/aws-secrets-manager"}]},{"type":"link","label":"Webhooks","href":"/docs/using-qovery/integration/webhook"},{"type":"link","label":"API","href":"/docs/using-qovery/integration/api-integration"},{"type":"link","label":"Slack","href":"/docs/using-qovery/integration/slack"}]},{"type":"category","label":"Configuration","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/configuration"},{"type":"category","label":"Organization","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/configuration/organization"},{"type":"link","label":"Members and RBAC","href":"/docs/using-qovery/configuration/organization/members-rbac"},{"type":"link","label":"Git Repository access","href":"/docs/using-qovery/configuration/organization/git-repository-access"},{"type":"link","label":"Container Registry","href":"/docs/using-qovery/configuration/organization/container-registry"},{"type":"link","label":"Helm Repository","href":"/docs/using-qovery/configuration/organization/helm-repository"},{"type":"link","label":"API Token","href":"/docs/using-qovery/configuration/organization/api-token"}]},{"type":"link","label":"Clusters","href":"/docs/using-qovery/configuration/clusters"},{"type":"category","label":"Cloud Service Provider","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/configuration/cloud-service-provider"},{"type":"link","label":"Amazon Web Services (AWS)","href":"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services"},{"type":"link","label":"Google Cloud Platform (GCP)","href":"/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform"},{"type":"link","label":"Microsoft Azure","href":"/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure"},{"type":"link","label":"Scaleway (SCW)","href":"/docs/using-qovery/configuration/cloud-service-provider/scaleway"},{"type":"link","label":"Other Cloud Service Provider","href":"/docs/using-qovery/configuration/cloud-service-provider/other-csps"}]},{"type":"category","label":"Provider","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/configuration/provider"},{"type":"link","label":"Kubernetes","href":"/docs/using-qovery/configuration/provider/kubernetes"}]},{"type":"link","label":"Cluster Advanced Settings","href":"/docs/using-qovery/configuration/cluster-advanced-settings"},{"type":"link","label":"Project","href":"/docs/using-qovery/configuration/project"},{"type":"link","label":"Environment","href":"/docs/using-qovery/configuration/environment"},{"type":"link","label":"Application","href":"/docs/using-qovery/configuration/application"},{"type":"link","label":"Helm","href":"/docs/using-qovery/configuration/helm"},{"type":"category","label":"Database","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/configuration/database"},{"type":"link","label":"PostgreSQL","href":"/docs/using-qovery/configuration/database/postgresql"},{"type":"link","label":"MySQL","href":"/docs/using-qovery/configuration/database/mysql"},{"type":"link","label":"MongoDB","href":"/docs/using-qovery/configuration/database/mongodb"},{"type":"link","label":"Redis","href":"/docs/using-qovery/configuration/database/redis"}]},{"type":"link","label":"Cronjob","href":"/docs/using-qovery/configuration/cronjob"},{"type":"link","label":"Lifecycle Job","href":"/docs/using-qovery/configuration/lifecycle-job"},{"type":"link","label":"Environment Variable & Secrets","href":"/docs/using-qovery/configuration/environment-variable"},{"type":"link","label":"Service Health Checks","href":"/docs/using-qovery/configuration/service-health-checks"},{"type":"link","label":"Service Advanced Settings","href":"/docs/using-qovery/configuration/advanced-settings"},{"type":"link","label":"Object Storage","href":"/docs/using-qovery/configuration/object-storage"},{"type":"link","label":"Deployment Rule","href":"/docs/using-qovery/configuration/deployment-rule"},{"type":"link","label":"User Account","href":"/docs/using-qovery/configuration/user-account"}]},{"type":"category","label":"Deployment","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/deployment"},{"type":"link","label":"Deploying with the auto-deploy feature","href":"/docs/using-qovery/deployment/deploying-with-auto-deploy"},{"type":"link","label":"Deploying with your CI/CD","href":"/docs/using-qovery/deployment/deploying-with-ci-cd"},{"type":"link","label":"Deployment Pipeline","href":"/docs/using-qovery/deployment/deployment-pipeline"},{"type":"link","label":"Deployment Actions","href":"/docs/using-qovery/deployment/deployment-actions"},{"type":"link","label":"Deployment History","href":"/docs/using-qovery/deployment/deployment-history"},{"type":"link","label":"Running and Deployment Statuses","href":"/docs/using-qovery/deployment/running-and-deployment-statuses"},{"type":"link","label":"Logs","href":"/docs/using-qovery/deployment/logs"},{"type":"link","label":"Deployment Strategies","href":"/docs/using-qovery/deployment/deployment-strategies"},{"type":"link","label":"Image Mirroring","href":"/docs/using-qovery/deployment/image-mirroring"}]},{"type":"category","label":"Troubleshoot","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/troubleshoot"},{"type":"link","label":"Application Troubleshoot","href":"/docs/using-qovery/troubleshoot/application-troubleshoot"},{"type":"link","label":"Database Troubleshoot","href":"/docs/using-qovery/troubleshoot/database-troubleshoot"},{"type":"link","label":"Lifecycle Job Troubleshoot","href":"/docs/using-qovery/troubleshoot/lifecycle-troubleshoot"},{"type":"link","label":"Cluster Troubleshoot","href":"/docs/using-qovery/troubleshoot/cluster-troubleshoot"}]},{"type":"link","label":"Audit Logs","href":"/docs/using-qovery/audit-logs"},{"type":"category","label":"Maintenance","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/maintenance"}]}]},{"type":"category","label":"Security and Compliance","items":[{"type":"link","label":"hidden","href":"/docs/security-and-compliance"},{"type":"link","label":"Backup and Restore","href":"/docs/security-and-compliance/backup-and-restore"},{"type":"link","label":"Encryption","href":"/docs/security-and-compliance/encryption"},{"type":"link","label":"GDPR","href":"/docs/security-and-compliance/gdpr"},{"type":"link","label":"SOC2","href":"/docs/security-and-compliance/soc2"}]},{"type":"category","label":"Useful Resources","items":[{"type":"link","label":"API documentation","href":"https://api-doc.qovery.com"},{"type":"link","label":"FAQ","href":"/docs/useful-resources/faq"},{"type":"link","label":"Roadmap","href":"https://roadmap.qovery.com"},{"type":"link","label":"Github","href":"https://github.com/qovery"},{"type":"link","label":"Help and Support","href":"/docs/useful-resources/help-and-support"}]}]},"permalinkToSidebar":{"/docs/getting-started":"docs","/docs/getting-started/basic-concepts":"docs","/docs/getting-started/deploy-my-app":"docs","/docs/getting-started/how-qovery-works":"docs","/docs/getting-started/install-qovery":"docs","/docs/getting-started/what-is-qovery":"docs","/docs/getting-started/whats-next":"docs","/docs/security-and-compliance":"docs","/docs/security-and-compliance/backup-and-restore":"docs","/docs/security-and-compliance/encryption":"docs","/docs/security-and-compliance/gdpr":"docs","/docs/security-and-compliance/soc2":"docs","/docs/useful-resources/faq":"docs","/docs/useful-resources/help-and-support":"docs","/docs/using-qovery":"docs","/docs/using-qovery/audit-logs":"docs","/docs/using-qovery/configuration":"docs","/docs/using-qovery/configuration/advanced-settings":"docs","/docs/using-qovery/configuration/application":"docs","/docs/using-qovery/configuration/cloud-service-provider":"docs","/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services":"docs","/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform":"docs","/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure":"docs","/docs/using-qovery/configuration/cloud-service-provider/other-csps":"docs","/docs/using-qovery/configuration/cloud-service-provider/scaleway":"docs","/docs/using-qovery/configuration/cluster-advanced-settings":"docs","/docs/using-qovery/configuration/clusters":"docs","/docs/using-qovery/configuration/cronjob":"docs","/docs/using-qovery/configuration/database":"docs","/docs/using-qovery/configuration/database/mongodb":"docs","/docs/using-qovery/configuration/database/mysql":"docs","/docs/using-qovery/configuration/database/postgresql":"docs","/docs/using-qovery/configuration/database/redis":"docs","/docs/using-qovery/configuration/deployment-rule":"docs","/docs/using-qovery/configuration/environment":"docs","/docs/using-qovery/configuration/environment-variable":"docs","/docs/using-qovery/configuration/helm":"docs","/docs/using-qovery/configuration/lifecycle-job":"docs","/docs/using-qovery/configuration/object-storage":"docs","/docs/using-qovery/configuration/organization":"docs","/docs/using-qovery/configuration/organization/api-token":"docs","/docs/using-qovery/configuration/organization/container-registry":"docs","/docs/using-qovery/configuration/organization/git-repository-access":"docs","/docs/using-qovery/configuration/organization/helm-repository":"docs","/docs/using-qovery/configuration/organization/members-rbac":"docs","/docs/using-qovery/configuration/project":"docs","/docs/using-qovery/configuration/provider":"docs","/docs/using-qovery/configuration/provider/kubernetes":"docs","/docs/using-qovery/configuration/service-health-checks":"docs","/docs/using-qovery/configuration/user-account":"docs","/docs/using-qovery/deployment":"docs","/docs/using-qovery/deployment/deploying-with-auto-deploy":"docs","/docs/using-qovery/deployment/deploying-with-ci-cd":"docs","/docs/using-qovery/deployment/deployment-actions":"docs","/docs/using-qovery/deployment/deployment-history":"docs","/docs/using-qovery/deployment/deployment-pipeline":"docs","/docs/using-qovery/deployment/deployment-strategies":"docs","/docs/using-qovery/deployment/image-mirroring":"docs","/docs/using-qovery/deployment/logs":"docs","/docs/using-qovery/deployment/running-and-deployment-statuses":"docs","/docs/using-qovery/integration":"docs","/docs/using-qovery/integration/api-integration":"docs","/docs/using-qovery/integration/container-registry":"docs","/docs/using-qovery/integration/continuous-integration":"docs","/docs/using-qovery/integration/continuous-integration/circle-ci":"docs","/docs/using-qovery/integration/continuous-integration/github-actions":"docs","/docs/using-qovery/integration/continuous-integration/gitlab-ci":"docs","/docs/using-qovery/integration/continuous-integration/jenkins":"docs","/docs/using-qovery/integration/git-repository":"docs","/docs/using-qovery/integration/helm-repository":"docs","/docs/using-qovery/integration/monitoring":"docs","/docs/using-qovery/integration/monitoring/datadog":"docs","/docs/using-qovery/integration/monitoring/new-relic":"docs","/docs/using-qovery/integration/secret-manager":"docs","/docs/using-qovery/integration/secret-manager/aws-secrets-manager":"docs","/docs/using-qovery/integration/secret-manager/doppler":"docs","/docs/using-qovery/integration/slack":"docs","/docs/using-qovery/integration/terraform":"docs","/docs/using-qovery/integration/webhook":"docs","/docs/using-qovery/interface":"docs","/docs/using-qovery/interface/cli":"docs","/docs/using-qovery/interface/rest-api":"docs","/docs/using-qovery/interface/terraform-interface":"docs","/docs/using-qovery/interface/web-interface":"docs","/docs/using-qovery/maintenance":"docs","/docs/using-qovery/troubleshoot":"docs","/docs/using-qovery/troubleshoot/application-troubleshoot":"docs","/docs/using-qovery/troubleshoot/cluster-troubleshoot":"docs","/docs/using-qovery/troubleshoot/database-troubleshoot":"docs","/docs/using-qovery/troubleshoot/lifecycle-troubleshoot":"docs"}}')}}]); \ No newline at end of file diff --git a/20ac7829.656a01ce.js b/20ac7829.656a01ce.js deleted file mode 100644 index e8b7bdb7d6..0000000000 --- a/20ac7829.656a01ce.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[39],{191:function(e){e.exports=JSON.parse('{"docsSidebars":{"docs":[{"type":"category","label":"Getting Started","items":[{"type":"link","label":"hidden","href":"/docs/getting-started"},{"type":"link","label":"What is Qovery?","href":"/docs/getting-started/what-is-qovery"},{"type":"link","label":"How Qovery Works","href":"/docs/getting-started/how-qovery-works"},{"type":"link","label":"Basic Concepts","href":"/docs/getting-started/basic-concepts"},{"type":"link","label":"Install Qovery","href":"/docs/getting-started/install-qovery"},{"type":"link","label":"Deploy my application","href":"/docs/getting-started/deploy-my-app"},{"type":"link","label":"What\'s next?","href":"/docs/getting-started/whats-next"}]},{"type":"category","label":"Usage","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery"},{"type":"category","label":"Interface","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/interface"},{"type":"link","label":"Web interface","href":"/docs/using-qovery/interface/web-interface"},{"type":"link","label":"CLI","href":"/docs/using-qovery/interface/cli"},{"type":"link","label":"REST API","href":"/docs/using-qovery/interface/rest-api"},{"type":"link","label":"Terraform","href":"/docs/using-qovery/interface/terraform-interface"}]},{"type":"category","label":"Integrations","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/integration"},{"type":"link","label":"Git Repository","href":"/docs/using-qovery/integration/git-repository"},{"type":"link","label":"Container Registry","href":"/docs/using-qovery/integration/container-registry"},{"type":"link","label":"Terraform","href":"/docs/using-qovery/integration/terraform"},{"type":"category","label":"Continuous Integration","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/integration/continuous-integration"},{"type":"link","label":"GitHub Actions","href":"/docs/using-qovery/integration/continuous-integration/github-actions"},{"type":"link","label":"GitLab CI","href":"/docs/using-qovery/integration/continuous-integration/gitlab-ci"},{"type":"link","label":"Circle CI","href":"/docs/using-qovery/integration/continuous-integration/circle-ci"},{"type":"link","label":"Jenkins","href":"/docs/using-qovery/integration/continuous-integration/jenkins"}]},{"type":"category","label":"Monitoring","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/integration/monitoring"},{"type":"link","label":"Datadog","href":"/docs/using-qovery/integration/monitoring/datadog"},{"type":"link","label":"New Relic","href":"/docs/using-qovery/integration/monitoring/new-relic"}]},{"type":"category","label":"Secret Manager","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/integration/secret-manager"},{"type":"link","label":"Doppler","href":"/docs/using-qovery/integration/secret-manager/doppler"},{"type":"link","label":"AWS Secrets Manager","href":"/docs/using-qovery/integration/secret-manager/aws-secrets-manager"}]},{"type":"link","label":"Webhooks","href":"/docs/using-qovery/integration/webhook"},{"type":"link","label":"API","href":"/docs/using-qovery/integration/api-integration"},{"type":"link","label":"Slack","href":"/docs/using-qovery/integration/slack"}]},{"type":"category","label":"Configuration","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/configuration"},{"type":"category","label":"Organization","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/configuration/organization"},{"type":"link","label":"Members and RBAC","href":"/docs/using-qovery/configuration/organization/members-rbac"},{"type":"link","label":"Git Repository access","href":"/docs/using-qovery/configuration/organization/git-repository-access"},{"type":"link","label":"Container Registry","href":"/docs/using-qovery/configuration/organization/container-registry"},{"type":"link","label":"API Token","href":"/docs/using-qovery/configuration/organization/api-token"}]},{"type":"link","label":"Clusters","href":"/docs/using-qovery/configuration/clusters"},{"type":"category","label":"Cloud Service Provider","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/configuration/cloud-service-provider"},{"type":"link","label":"Amazon Web Services (AWS)","href":"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services"},{"type":"link","label":"Google Cloud Platform (GCP)","href":"/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform"},{"type":"link","label":"Microsoft Azure","href":"/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure"},{"type":"link","label":"Scaleway (SCW)","href":"/docs/using-qovery/configuration/cloud-service-provider/scaleway"},{"type":"link","label":"Other Cloud Service Provider","href":"/docs/using-qovery/configuration/cloud-service-provider/other-csps"}]},{"type":"category","label":"Provider","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/configuration/provider"},{"type":"link","label":"Kubernetes","href":"/docs/using-qovery/configuration/provider/kubernetes"}]},{"type":"link","label":"Cluster Advanced Settings","href":"/docs/using-qovery/configuration/cluster-advanced-settings"},{"type":"link","label":"Project","href":"/docs/using-qovery/configuration/project"},{"type":"link","label":"Environment","href":"/docs/using-qovery/configuration/environment"},{"type":"link","label":"Application","href":"/docs/using-qovery/configuration/application"},{"type":"category","label":"Database","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/configuration/database"},{"type":"link","label":"PostgreSQL","href":"/docs/using-qovery/configuration/database/postgresql"},{"type":"link","label":"MySQL","href":"/docs/using-qovery/configuration/database/mysql"},{"type":"link","label":"MongoDB","href":"/docs/using-qovery/configuration/database/mongodb"},{"type":"link","label":"Redis","href":"/docs/using-qovery/configuration/database/redis"}]},{"type":"link","label":"Cronjob","href":"/docs/using-qovery/configuration/cronjob"},{"type":"link","label":"Lifecycle Job","href":"/docs/using-qovery/configuration/lifecycle-job"},{"type":"link","label":"Environment Variable & Secrets","href":"/docs/using-qovery/configuration/environment-variable"},{"type":"link","label":"Service Health Checks","href":"/docs/using-qovery/configuration/service-health-checks"},{"type":"link","label":"Service Advanced Settings","href":"/docs/using-qovery/configuration/advanced-settings"},{"type":"link","label":"Object Storage","href":"/docs/using-qovery/configuration/object-storage"},{"type":"link","label":"Deployment Rule","href":"/docs/using-qovery/configuration/deployment-rule"},{"type":"link","label":"User Account","href":"/docs/using-qovery/configuration/user-account"}]},{"type":"category","label":"Deployment","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/deployment"},{"type":"link","label":"Deploying with the auto-deploy feature","href":"/docs/using-qovery/deployment/deploying-with-auto-deploy"},{"type":"link","label":"Deploying with your CI/CD","href":"/docs/using-qovery/deployment/deploying-with-ci-cd"},{"type":"link","label":"Deployment Pipeline","href":"/docs/using-qovery/deployment/deployment-pipeline"},{"type":"link","label":"Deployment Actions","href":"/docs/using-qovery/deployment/deployment-actions"},{"type":"link","label":"Deployment History","href":"/docs/using-qovery/deployment/deployment-history"},{"type":"link","label":"Running and Deployment Statuses","href":"/docs/using-qovery/deployment/running-and-deployment-statuses"},{"type":"link","label":"Logs","href":"/docs/using-qovery/deployment/logs"},{"type":"link","label":"Deployment Strategies","href":"/docs/using-qovery/deployment/deployment-strategies"},{"type":"link","label":"Image Mirroring","href":"/docs/using-qovery/deployment/image-mirroring"}]},{"type":"category","label":"Troubleshoot","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/troubleshoot"},{"type":"link","label":"Application Troubleshoot","href":"/docs/using-qovery/troubleshoot/application-troubleshoot"},{"type":"link","label":"Database Troubleshoot","href":"/docs/using-qovery/troubleshoot/database-troubleshoot"},{"type":"link","label":"Lifecycle Job Troubleshoot","href":"/docs/using-qovery/troubleshoot/lifecycle-troubleshoot"},{"type":"link","label":"Cluster Troubleshoot","href":"/docs/using-qovery/troubleshoot/cluster-troubleshoot"}]},{"type":"link","label":"Audit Logs","href":"/docs/using-qovery/audit-logs"},{"type":"category","label":"Maintenance","items":[{"type":"link","label":"hidden","href":"/docs/using-qovery/maintenance"}]}]},{"type":"category","label":"Security and Compliance","items":[{"type":"link","label":"hidden","href":"/docs/security-and-compliance"},{"type":"link","label":"Backup and Restore","href":"/docs/security-and-compliance/backup-and-restore"},{"type":"link","label":"Encryption","href":"/docs/security-and-compliance/encryption"},{"type":"link","label":"GDPR","href":"/docs/security-and-compliance/gdpr"},{"type":"link","label":"SOC2","href":"/docs/security-and-compliance/soc2"}]},{"type":"category","label":"Useful Resources","items":[{"type":"link","label":"API documentation","href":"https://api-doc.qovery.com"},{"type":"link","label":"FAQ","href":"/docs/useful-resources/faq"},{"type":"link","label":"Roadmap","href":"https://roadmap.qovery.com"},{"type":"link","label":"Github","href":"https://github.com/qovery"},{"type":"link","label":"Help and Support","href":"/docs/useful-resources/help-and-support"}]}]},"permalinkToSidebar":{"/docs/getting-started":"docs","/docs/getting-started/basic-concepts":"docs","/docs/getting-started/deploy-my-app":"docs","/docs/getting-started/how-qovery-works":"docs","/docs/getting-started/install-qovery":"docs","/docs/getting-started/what-is-qovery":"docs","/docs/getting-started/whats-next":"docs","/docs/security-and-compliance":"docs","/docs/security-and-compliance/backup-and-restore":"docs","/docs/security-and-compliance/encryption":"docs","/docs/security-and-compliance/gdpr":"docs","/docs/security-and-compliance/soc2":"docs","/docs/useful-resources/faq":"docs","/docs/useful-resources/help-and-support":"docs","/docs/using-qovery":"docs","/docs/using-qovery/audit-logs":"docs","/docs/using-qovery/configuration":"docs","/docs/using-qovery/configuration/advanced-settings":"docs","/docs/using-qovery/configuration/application":"docs","/docs/using-qovery/configuration/cloud-service-provider":"docs","/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services":"docs","/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform":"docs","/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure":"docs","/docs/using-qovery/configuration/cloud-service-provider/other-csps":"docs","/docs/using-qovery/configuration/cloud-service-provider/scaleway":"docs","/docs/using-qovery/configuration/cluster-advanced-settings":"docs","/docs/using-qovery/configuration/clusters":"docs","/docs/using-qovery/configuration/cronjob":"docs","/docs/using-qovery/configuration/database":"docs","/docs/using-qovery/configuration/database/mongodb":"docs","/docs/using-qovery/configuration/database/mysql":"docs","/docs/using-qovery/configuration/database/postgresql":"docs","/docs/using-qovery/configuration/database/redis":"docs","/docs/using-qovery/configuration/deployment-rule":"docs","/docs/using-qovery/configuration/environment":"docs","/docs/using-qovery/configuration/environment-variable":"docs","/docs/using-qovery/configuration/lifecycle-job":"docs","/docs/using-qovery/configuration/object-storage":"docs","/docs/using-qovery/configuration/organization":"docs","/docs/using-qovery/configuration/organization/api-token":"docs","/docs/using-qovery/configuration/organization/container-registry":"docs","/docs/using-qovery/configuration/organization/git-repository-access":"docs","/docs/using-qovery/configuration/organization/members-rbac":"docs","/docs/using-qovery/configuration/project":"docs","/docs/using-qovery/configuration/provider":"docs","/docs/using-qovery/configuration/provider/kubernetes":"docs","/docs/using-qovery/configuration/service-health-checks":"docs","/docs/using-qovery/configuration/user-account":"docs","/docs/using-qovery/deployment":"docs","/docs/using-qovery/deployment/deploying-with-auto-deploy":"docs","/docs/using-qovery/deployment/deploying-with-ci-cd":"docs","/docs/using-qovery/deployment/deployment-actions":"docs","/docs/using-qovery/deployment/deployment-history":"docs","/docs/using-qovery/deployment/deployment-pipeline":"docs","/docs/using-qovery/deployment/deployment-strategies":"docs","/docs/using-qovery/deployment/image-mirroring":"docs","/docs/using-qovery/deployment/logs":"docs","/docs/using-qovery/deployment/running-and-deployment-statuses":"docs","/docs/using-qovery/integration":"docs","/docs/using-qovery/integration/api-integration":"docs","/docs/using-qovery/integration/container-registry":"docs","/docs/using-qovery/integration/continuous-integration":"docs","/docs/using-qovery/integration/continuous-integration/circle-ci":"docs","/docs/using-qovery/integration/continuous-integration/github-actions":"docs","/docs/using-qovery/integration/continuous-integration/gitlab-ci":"docs","/docs/using-qovery/integration/continuous-integration/jenkins":"docs","/docs/using-qovery/integration/git-repository":"docs","/docs/using-qovery/integration/monitoring":"docs","/docs/using-qovery/integration/monitoring/datadog":"docs","/docs/using-qovery/integration/monitoring/new-relic":"docs","/docs/using-qovery/integration/secret-manager":"docs","/docs/using-qovery/integration/secret-manager/aws-secrets-manager":"docs","/docs/using-qovery/integration/secret-manager/doppler":"docs","/docs/using-qovery/integration/slack":"docs","/docs/using-qovery/integration/terraform":"docs","/docs/using-qovery/integration/webhook":"docs","/docs/using-qovery/interface":"docs","/docs/using-qovery/interface/cli":"docs","/docs/using-qovery/interface/rest-api":"docs","/docs/using-qovery/interface/terraform-interface":"docs","/docs/using-qovery/interface/web-interface":"docs","/docs/using-qovery/maintenance":"docs","/docs/using-qovery/troubleshoot":"docs","/docs/using-qovery/troubleshoot/application-troubleshoot":"docs","/docs/using-qovery/troubleshoot/cluster-troubleshoot":"docs","/docs/using-qovery/troubleshoot/database-troubleshoot":"docs","/docs/using-qovery/troubleshoot/lifecycle-troubleshoot":"docs"}}')}}]); \ No newline at end of file diff --git a/2121549d.6accd8fc.js b/2121549d.83e910bc.js similarity index 98% rename from 2121549d.6accd8fc.js rename to 2121549d.83e910bc.js index 665dd1540a..dc5708f61d 100644 --- a/2121549d.6accd8fc.js +++ b/2121549d.83e910bc.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[40],{192:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return p}));var a=n(1),o=n(9),r=(n(0),n(422)),i=n(421),l=(n(434),n(426)),s={last_modified_on:"2023-09-08",$schema:"/.meta/.schemas/guides.json",title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",description:"Step-by-step guide to build e2e testing ephemeral environments with GitHub Actions and Qovery",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",description:"Step-by-step guide to build e2e testing ephemeral environments with GitHub Actions and Qovery",permalink:"/guides/tutorial/build-e2e-testing-ephemeral-environments",readingTime:"12 min read",source:"@site/guides/tutorial/build-e2e-testing-ephemeral-environments.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",truncated:!1,prevItem:{title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",permalink:"/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws"},nextItem:{title:"Continuous Integration",permalink:"/guides/advanced/continuous-integration"}},b=[{value:"Why E2E Testing?",id:"why-e2e-testing",children:[]},{value:"The Importance of Ephemeral Environments",id:"the-importance-of-ephemeral-environments",children:[]},{value:"GitHub Actions and Qovery: A Perfect Match",id:"github-actions-and-qovery-a-perfect-match",children:[]},{value:"What You'll Learn",id:"what-youll-learn",children:[]},{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Tools",id:"tools",children:[]},{value:"7 Steps to build E2E testing ephemeral environments with GitHub Actions and Qovery",id:"7-steps-to-build-e2e-testing-ephemeral-environments-with-github-actions-and-qovery",children:[{value:"1. Prepare Qovery blueprint environment",id:"1-prepare-qovery-blueprint-environment",children:[]},{value:"2. Build and push container image",id:"2-build-and-push-container-image",children:[]},{value:"3. Create an Ephemeral Environment with GitHub Actions and Qovery",id:"3-create-an-ephemeral-environment-with-github-actions-and-qovery",children:[]},{value:"4. Run E2E tests with K6",id:"4-run-e2e-tests-with-k6",children:[]},{value:"5. Display test results in Pull Request",id:"5-display-test-results-in-pull-request",children:[]},{value:"6. Destroy Ephemeral Environment and clean up resources",id:"6-destroy-ephemeral-environment-and-clean-up-resources",children:[]}]},{value:"Wrapping up",id:"wrapping-up",children:[]}],u={rightToc:b};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Welcome to this comprehensive step-by-step guide on building End-to-End (E2E) testing ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/ephemeral-environments"}),"ephemeral environments")," using ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/features/actions"}),"GitHub Actions")," and ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com"}),"Qovery"),". If you've been seeking ways to automate your testing processes, reduce operational overhead, and improve the efficiency of your development cycle, then you're in the right place."),Object(r.b)("p",null,Object(r.b)("em",{parentName:"p"},"This article is available in the webinar format as well")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/1be8d4229cb74ed7b0526cc2acbca8ad",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"why-e2e-testing"},"Why E2E Testing?"),Object(r.b)("p",null,"End-to-End testing is a critical phase in the software development lifecycle. It validates that your application works cohesively from start to finish, mimicking real-world scenarios."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/e2e-pyramid.png",alt:"E2E vs UI Tests vs Integation Tests vs Unit Tests - from SemaphoreCI"})),Object(r.b)("p",null,"While unit tests and integration tests offer valuable insights, they do not replicate how multiple components interact in a live production environment. E2E testing fills that gap and ensures that your application performs as expected when it goes live."),Object(r.b)("h2",{id:"the-importance-of-ephemeral-environments"},"The Importance of Ephemeral Environments"),Object(r.b)("p",null,"In the world of DevOps and CI/CD, ephemeral environments (aka ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/blog/why-preview-environments-are-the-new-thing-in-devops"}),"Preview Environments"),") serve as temporary, isolated setups where you can test your applications. These environments are increasingly vital in agile development frameworks where frequent changes are the norm. They can be provisioned quickly, teared down when no longer needed, and replicated easily. This means you can push your changes more rapidly into production with confidence."),Object(r.b)("h2",{id:"github-actions-and-qovery-a-perfect-match"},"GitHub Actions and Qovery: A Perfect Match"),Object(r.b)("p",null,"GitHub Actions offers a powerful platform for automating workflows, allowing you to build, test, and deploy your code right from GitHub. Qovery, on the other hand, simplifies the provisioning and management of cloud resources, making it incredibly straightforward to set up ephemeral environments. When used in tandem, these tools provide a seamless, automated pipeline for E2E testing."),Object(r.b)("h2",{id:"what-youll-learn"},"What You'll Learn"),Object(r.b)("p",null,"This guide is designed to walk you through the entire process of setting up an automated E2E testing pipeline. We'll start by setting up GitHub Actions, move on to configuring ephemeral environments with Qovery, and finally, integrate these components into a cohesive, automated testing solution."),Object(r.b)("p",null,"By the end of this guide, you'll have a fully operational E2E testing pipeline that will allow you to:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Automate your testing process"),Object(r.b)("li",{parentName:"ol"},"Quickly provision and de-provision environments"),Object(r.b)("li",{parentName:"ol"},"Integrate closely with your GitHub repository"),Object(r.b)("li",{parentName:"ol"},"Save both time and operational costs")),Object(r.b)("p",null,"So, whether you are a developer, a DevOps engineer, a QA specialist, an engineering manager, or even a CTO, this guide offers valuable insights for anyone involved in the software development process."),Object(r.b)("p",null,"Let's dive in!"),Object(r.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(r.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://start.qovery.com"}),"sign in on Qovery")),Object(r.b)("li",{parentName:"ul"},"You have a GitHub account"))),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Contact us via ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum")," if you have any questions concerning Qovery")),Object(r.b)("h2",{id:"tools"},"Tools"),Object(r.b)("p",null,"Here are the tools we will use in this guide:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.qovery.com"}),"Qovery")," for the infrastructure and the ephemeral environment"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/features/actions"}),"GitHub Actions")," for the CI/CD pipeline"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://k6.io/"}),"K6")," for the e2e tests")),Object(r.b)("h2",{id:"7-steps-to-build-e2e-testing-ephemeral-environments-with-github-actions-and-qovery"},"7 Steps to build E2E testing ephemeral environments with GitHub Actions and Qovery"),Object(r.b)("p",null,"Here is the big picture of what we will build:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/1.png",alt:"e2e testing Workflow with github actions and Qovery"})),Object(r.b)("p",null,"We will focus on the most important parts of the workflow - from label number 2 to 11. I assume that you already know GitHub and how to create a Pull Request :)"),Object(r.b)("p",null,"Let's go!"),Object(r.b)("h3",{id:"1-prepare-qovery-blueprint-environment"},"1. Prepare Qovery blueprint environment"),Object(r.b)("p",null,"If you are not already familiar with Qovery, I recommend you to ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/getting-started/what-is-qovery/"}),"What's Qovery"),". In this guide, we will use Qovery to provision our ephemeral environments composed of a Java application (",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app"}),"TODO app"),") and a PostgreSQL database. For this, we will create a blueprint environment that will be used as a template to create ephemeral environments."),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can skip this part if you already have an environment that you want to use as a base for your ephemeral environments.")),Object(r.b)("p",null,"Here are the steps I did to create my blueprint environment:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Connect to ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://console.qovery.com"}),"Qovery"),"."),Object(r.b)("li",{parentName:"ol"},"Create a new project."),Object(r.b)("li",{parentName:"ol"},"Create a new environment named ",Object(r.b)("inlineCode",{parentName:"li"},"blueprint"),"."),Object(r.b)("li",{parentName:"ol"},"Add a ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"/guides/getting-started/create-a-database/"}),"PostgreSQL database")," inside your ",Object(r.b)("inlineCode",{parentName:"li"},"blueprint")," environment."),Object(r.b)("li",{parentName:"ol"},"Add a ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/application/#create-an-application"}),"TODO app")," by using my ECR container registry where I push my image from GitHub Actions (cf next step).")),Object(r.b)("p",null,"At the end of those steps, you should have something like this:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/2.png",alt:"Blueprint environment"})),Object(r.b)("p",null,"If you want to use my ",Object(r.b)("inlineCode",{parentName:"p"},"TODO app")," as an example, you need to properly configure the environment variables of the application. Here is a table with the environment variables you need to set:"),Object(r.b)("details",null,Object(r.b)("summary",null,"Environment Variables"),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Name"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Is Alias?"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Scope"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Value"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Comment"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_DB_NAME")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._DEFAULT_DATABASE_NAME")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database name")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_HOST")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._HOST_INTERNAL")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database host")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_PORT")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._PORT")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database port")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_DATASOURCE_USERNAME")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._LOGIN")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database login")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_DATASOURCE_PASSWORD")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._PASSWORD")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database password")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"QUARKUS_DATASOURCE_JDBC_URL")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"No"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"jdbc:postgresql://{{POSTGRES_HOST}}:{{POSTGRES_PORT}}/{{POSTGRES_DB_NAME}}"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Connection string to the PostgreSQL database"))))),Object(r.b)("p",null,"You're good to go! Now, let's move on to the next step."),Object(r.b)("h3",{id:"2-build-and-push-container-image"},"2. Build and push container image"),Object(r.b)("p",null,"In this step, we will build and push the container image of our application to our ECR container registry. We will use GitHub Actions to do that."),Object(r.b)("p",null,"Create your GitHub Actions workflow inside ",Object(r.b)("inlineCode",{parentName:"p"},".github/workflows")," folder. I named mine ",Object(r.b)("inlineCode",{parentName:"p"},"build-and-push-image.yml"),". Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"...\n build-and-push-container:\n runs-on: ubuntu-latest\n needs: run-unit-tests\n steps:\n - name: Checkout code\n uses: actions/checkout@v3\n\n - name: Configure AWS credentials\n uses: aws-actions/configure-aws-credentials@v2\n with:\n aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}\n aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}\n aws-region: eu-west-3\n\n - name: Login to Amazon ECR\n id: login-ecr\n uses: aws-actions/amazon-ecr-login@v1\n with:\n mask-password: 'true'\n\n - name: Build, Tag, and push image to Amazon ECR\n env:\n ECR_REGISTRY: 687975725498.dkr.ecr.eu-west-3.amazonaws.com\n ECR_REPOSITORY: todo-app\n IMAGE_TAG: ${{ github.sha }}\n run: |\n docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .\n docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest\n docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Find my complete file ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/build-and-push-image.yml"}),"here"))),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"AWS_ACCESS_KEY_ID")," and ",Object(r.b)("inlineCode",{parentName:"p"},"AWS_SECRET_ACCESS_KEY")," are stored as ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.github.com/en/actions/reference/encrypted-secrets"}),"GitHub secrets"),"."),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"The ECR registry is also connected to my Qovery account - so I can pull the pushed image from Qovery as well.")),Object(r.b)("h3",{id:"3-create-an-ephemeral-environment-with-github-actions-and-qovery"},"3. Create an Ephemeral Environment with GitHub Actions and Qovery"),Object(r.b)("p",null,"In this step, we will create an ephemeral environment with GitHub Actions and Qovery. We will use the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI")," inside our GitHub Actions workflow to do that."),Object(r.b)("p",null,"Create your GitHub Actions workflow inside ",Object(r.b)("inlineCode",{parentName:"p"},".github/workflows")," folder. I named mine ",Object(r.b)("inlineCode",{parentName:"p"},"pull-request-run-e2e-tests.yml"),". Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'...\njobs:\n create-e2e-environment:\n if: ${{ github.event.label.name == \'e2e\' }}\n runs-on: ubuntu-latest\n permissions:\n pull-requests: write\n steps:\n - id: create-environment\n name: Create and deploy Qovery E2E environment\n env:\n QOVERY_CLI_ACCESS_TOKEN: ${{ secrets.QOVERY_CLI_ACCESS_TOKEN }}\n run: |\n # Download and install Qovery CLI\n curl -s https://get.qovery.com | bash\n\n echo "Organization name: ${{ vars.QOVERY_ORGANIZATION_NAME }}"\n echo "Project name: ${{ vars.QOVERY_PROJECT_NAME }}"\n echo "Blueprint name: ${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}"\n\n new_environment_name="${GITHUB_HEAD_REF}"\n\n echo "Let\'s clone \'${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}\' environment into \'$new_environment_name\' environment"\n\n qovery environment clone \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}" \\\n --new-environment-name "$new_environment_name"\n\n qovery container update \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}" \\\n --container "${{ vars.QOVERY_APPLICATION_NAME }}" \\\n --tag ${{ github.sha }}\n\n qovery environment deploy \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n -w\n\n qovery_status_markdown_output=`qovery service list \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n --markdown`\n\n echo "QOVERY_STATUS_MARKDOWN_OUTPUT<> "$GITHUB_OUTPUT"\n echo "$qovery_status_markdown_output" >> "$GITHUB_OUTPUT"\n echo "EOF" >> "$GITHUB_OUTPUT"\n')),Object(r.b)("p",null,"Basically, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery environment clone")," command to clone our blueprint environment into a new environment. Then, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery container update")," command to update the container tag of our application. Finally, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery environment deploy")," command to deploy our application. The option ",Object(r.b)("inlineCode",{parentName:"p"},"-w")," is used to wait for the deployment to be completed. We also use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery service list")," command to get the status of our environment and store it in a GitHub output variable. This variable will be used in the next step to display the status of the environment in the Pull Request."),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"...\n - name: PR Comment with URL\n uses: mshick/add-pr-comment@v2\n with:\n message-id: qovery-e2e-environment-status\n message: |\n ${{ steps.create-environment.outputs.QOVERY_STATUS_MARKDOWN_OUTPUT }}\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Find my complete file ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-run-e2e-tests.yml"}),"here"))),Object(r.b)("p",null,"You can see the result of this step in the Pull Request:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/3.png",alt:"Ephemeral environment status in Pull Request"})),Object(r.b)("h3",{id:"4-run-e2e-tests-with-k6"},"4. Run E2E tests with K6"),Object(r.b)("p",null,"In this step, we will run our E2E tests with ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://k6.io"}),"K6"),". K6 is a modern load testing tool that allows you to write tests in JavaScript. It's a great tool to run E2E tests as well. Here is the script we will use:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"import http from 'k6/http';\nimport {check, group, sleep, fail} from 'k6';\nimport {uuidv4} from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';\n\nconst api_host = `${__ENV.API_HOST}/api`;\nexport const options = {\n stages: [\n {duration: '5m', target: 100}, // traffic ramp-up from 1 to 100 users over 5 minutes.\n //{ duration: '30m', target: 100 }, // stay at 100 users for 30 minutes\n {duration: '1m', target: 50}, // ramp-down to 50 users\n ]\n}\n\nexport function setup() {\n // add some data\n const params = {\n headers: {\n 'Content-Type': 'application/json',\n },\n };\n\n for (let i = 0; i < 20; i++) {\n const res = http.post(api_host, JSON.stringify({title: uuidv4()}), params);\n check(res, {'item added': (r) => r.status === 201});\n }\n}\n\nexport default function () {\n http.get(api_host);\n}\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete script is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/e2e/e2e.js"}),"here"))),Object(r.b)("p",null,"We will use the ",Object(r.b)("inlineCode",{parentName:"p"},"setup")," function to add some data to our database. Then, we will use the ",Object(r.b)("inlineCode",{parentName:"p"},"default")," function to get the list of items from our API. We will use the ",Object(r.b)("inlineCode",{parentName:"p"},"options")," variable to define the number of users we want to simulate. In this example, we will simulate 100 users for 5 minutes. You can find more information about the ",Object(r.b)("inlineCode",{parentName:"p"},"options")," variable ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://k6.io/docs/using-k6/options"}),"here"),"."),Object(r.b)("p",null,"To run our E2E tests, we will use the ",Object(r.b)("inlineCode",{parentName:"p"},"k6 run")," command inside our GitHub Actions workflow. Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),' run-e2e-tests:\n if: ${{ github.event.label.name == \'e2e\' }}\n runs-on: ubuntu-latest\n needs: create-e2e-environment\n permissions:\n pull-requests: write\n steps:\n - name: Checkout code\n uses: actions/checkout@v3\n\n - id: run-e2e\n name: Run E2E tests\n env:\n QOVERY_CLI_ACCESS_TOKEN: ${{ secrets.QOVERY_CLI_ACCESS_TOKEN }}\n run: |\n # Download and install Qovery CLI\n curl -s https://get.qovery.com | bash\n\n sudo gpg -k\n sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69\n echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list\n sudo apt-get update\n sudo apt-get install k6\n\n new_environment_name="${GITHUB_HEAD_REF}"\n\n api_domain=`qovery container domain list \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n --container "${{ vars.QOVERY_APPLICATION_NAME }}" | grep "BUILT_IN_DOMAIN" | head -1 | awk \'{print $5}\' | sed -e \'s/\\x1b\\[[0-9;]*m//g\'`\n\n echo "api_domain: $api_domain"\n\n api_host="https://$api_domain"\n echo "API_HOST: $api_host"\n\n e2e_report=`k6 --no-color -q -e API_HOST=$api_host run e2e/e2e.js`\n\n echo "E2E_REPORT<> $GITHUB_OUTPUT\n echo "$e2e_report" >> $GITHUB_OUTPUT\n echo "EOF" >> $GITHUB_OUTPUT\n')),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete file is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-run-e2e-tests.yml"}),"here"))),Object(r.b)("p",null,"We use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery container domain list")," command to get the domain of our application. Then, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"k6")," command to run our E2E tests. We store the result of the tests in a GitHub output variable."),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"The ",Object(r.b)("inlineCode",{parentName:"p"},"qovery container domain list")," command returns ANSI color codes. We use the ",Object(r.b)("inlineCode",{parentName:"p"},"sed -e 's/\\x1b\\[[0-9;]*m//g'")," command to remove them.")),Object(r.b)("h3",{id:"5-display-test-results-in-pull-request"},"5. Display test results in Pull Request"),Object(r.b)("p",null,"In this step, we will display the result of our E2E tests in the Pull Request. We will use the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-output-parameter"}),"GitHub Actions output variables")," to do that. Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"})," - name: Display E2E Report\n uses: mshick/add-pr-comment@v2\n with:\n message-id: e2e-report\n message: |\n E2E Tests Report\n\n --\n\n ```\n ${{ steps.run-e2e.outputs.E2E_REPORT }}\n ```\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete file is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-run-e2e-tests.yml#L109C1-L120C16"}),"here"))),Object(r.b)("p",null,"You can see the result of this step in the Pull Request:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/4.png",alt:"E2E report in Pull Request"})),Object(r.b)("h3",{id:"6-destroy-ephemeral-environment-and-clean-up-resources"},"6. Destroy Ephemeral Environment and clean up resources"),Object(r.b)("p",null,"Now we will destroy the ephemeral environment and clean up the resources when the Pull Request is closed or merged. Here is the yaml:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'name: Destroy and clean up E2E Tests Environment\n\non:\n pull_request:\n types: [ closed ]\n\njobs:\n delete-e2e-environment:\n runs-on: ubuntu-latest\n steps:\n - id: delete-environment\n name: Delete Qovery E2E environment\n env:\n QOVERY_CLI_ACCESS_TOKEN: ${{ secrets.QOVERY_CLI_ACCESS_TOKEN }}\n run: |\n # Download and install Qovery CLI\n curl -s https://get.qovery.com | bash\n\n echo "Organization name: ${{ vars.QOVERY_ORGANIZATION_NAME }}"\n echo "Project name: ${{ vars.QOVERY_PROJECT_NAME }}"\n echo "Blueprint name: ${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}"\n\n new_environment_name="${GITHUB_HEAD_REF}"\n\n echo "Let\'s delete \'$new_environment_name\' environment and release its resources"\n\n qovery environment delete \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n -w\n')),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete file is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-destroy-e2e-environment.yml"}),"here"))),Object(r.b)("p",null,"We just use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery environment delete")," command to delete the ephemeral environment. The option ",Object(r.b)("inlineCode",{parentName:"p"},"-w")," is used to wait for the deletion to be completed. Qovery will automatically release the resources used by the environment."),Object(r.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(r.b)("p",null,"Congratulations! You've successfully built an automated E2E testing pipeline with GitHub Actions and Qovery. You can now run your tests in a fully isolated environment, provisioned and de-provisioned automatically, and integrated with your GitHub repository."),Object(r.b)("p",null,"Some resources:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://semaphoreci.com/blog/e2e-testing"}),"https://semaphoreci.com/blog/e2e-testing")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.loom.com/share/1be8d4229cb74ed7b0526cc2acbca8ad"}),"Webinar record"))))}p.isMDXComponent=!0},421:function(e,t,n){"use strict";n(423);var a=n(0),o=n.n(a),r=n(420),i=n.n(r);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,r=e.icon,l=e.type,s=null;switch(l){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return o.a.createElement("div",{className:i()(n,"alert","alert--"+l,{"alert--fill":a,"alert--icon":!1!==r}),role:"alert"},!1!==r&&o.a.createElement("i",{className:i()("feather","icon-"+(r||s))}),t)}},425:function(e,t,n){var a=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&a(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),o=n.n(a),r=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},434:function(e,t,n){"use strict";var a=n(1),o=(n(439),n(436),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(446),l=n(420),s=n.n(l),c=n(428),b=n.n(c),u=n(445),p=37,m=39;function d(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,o=e.className,i=e.handleKeydown,l=e.style,c=e.values,b=e.selectedValue,u=e.tabRefs;return r.a.createElement("div",{className:n?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:s()("tabs",o,{"tabs--block":t}),style:l},c.map((function(e){var t=e.value,n=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:s()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return i(u,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function h(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,o=e.size,l=e.values,s=l;if(s[0].group){var c=_.groupBy(s,"group");s=Object.keys(c).map((function(e){return{label:e,options:c[e]}}))}return r.a.createElement(i.a,{className:"react-select-container react-select--"+o,classNamePrefix:"react-select",options:s,isClearable:n,placeholder:t,value:l.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,i=e.groupId,l=e.label,s=e.placeholder,c=e.select,O=e.size,v=(e.style,e.values),g=e.urlKey,j=Object(u.a)(),E=j.tabGroupChoices,y=j.setTabGroupChoices,f=Object(o.useState)(n),N=f[0],w=f[1];if(null!=i){var _=E[i];null!=_&&_!==N&&w(_)}var T=function(e){w(e),null!=i&&y(i,e)},R=[],A=function(e,t,n){switch(n.keyCode){case m:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(o.useEffect)((function(){if("undefined"!=typeof window&&window.location&&g){var e=b.a.parse(window.location.search);e[g]&&w(e[g])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(O||"md")},l&&r.a.createElement("div",{className:"margin-vert--sm"},l),v.length>1&&(c?r.a.createElement(h,Object(a.a)({changeSelectedValue:T,handleKeydown:A,placeholder:s,selectedValue:N,size:O,tabRefs:R},e)):r.a.createElement(d,Object(a.a)({changeSelectedValue:T,handleKeydown:A,selectedValue:N,tabRefs:R},e)))),o.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[41],{193:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return p}));var a=n(1),o=n(9),r=(n(0),n(425)),i=n(424),l=(n(437),n(429)),s={last_modified_on:"2023-09-08",$schema:"/.meta/.schemas/guides.json",title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",description:"Step-by-step guide to build e2e testing ephemeral environments with GitHub Actions and Qovery",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",description:"Step-by-step guide to build e2e testing ephemeral environments with GitHub Actions and Qovery",permalink:"/guides/tutorial/build-e2e-testing-ephemeral-environments",readingTime:"12 min read",source:"@site/guides/tutorial/build-e2e-testing-ephemeral-environments.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",truncated:!1,prevItem:{title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",permalink:"/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws"},nextItem:{title:"Continuous Integration",permalink:"/guides/advanced/continuous-integration"}},b=[{value:"Why E2E Testing?",id:"why-e2e-testing",children:[]},{value:"The Importance of Ephemeral Environments",id:"the-importance-of-ephemeral-environments",children:[]},{value:"GitHub Actions and Qovery: A Perfect Match",id:"github-actions-and-qovery-a-perfect-match",children:[]},{value:"What You'll Learn",id:"what-youll-learn",children:[]},{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Tools",id:"tools",children:[]},{value:"7 Steps to build E2E testing ephemeral environments with GitHub Actions and Qovery",id:"7-steps-to-build-e2e-testing-ephemeral-environments-with-github-actions-and-qovery",children:[{value:"1. Prepare Qovery blueprint environment",id:"1-prepare-qovery-blueprint-environment",children:[]},{value:"2. Build and push container image",id:"2-build-and-push-container-image",children:[]},{value:"3. Create an Ephemeral Environment with GitHub Actions and Qovery",id:"3-create-an-ephemeral-environment-with-github-actions-and-qovery",children:[]},{value:"4. Run E2E tests with K6",id:"4-run-e2e-tests-with-k6",children:[]},{value:"5. Display test results in Pull Request",id:"5-display-test-results-in-pull-request",children:[]},{value:"6. Destroy Ephemeral Environment and clean up resources",id:"6-destroy-ephemeral-environment-and-clean-up-resources",children:[]}]},{value:"Wrapping up",id:"wrapping-up",children:[]}],u={rightToc:b};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Welcome to this comprehensive step-by-step guide on building End-to-End (E2E) testing ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/ephemeral-environments"}),"ephemeral environments")," using ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/features/actions"}),"GitHub Actions")," and ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com"}),"Qovery"),". If you've been seeking ways to automate your testing processes, reduce operational overhead, and improve the efficiency of your development cycle, then you're in the right place."),Object(r.b)("p",null,Object(r.b)("em",{parentName:"p"},"This article is available in the webinar format as well")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/1be8d4229cb74ed7b0526cc2acbca8ad",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"why-e2e-testing"},"Why E2E Testing?"),Object(r.b)("p",null,"End-to-End testing is a critical phase in the software development lifecycle. It validates that your application works cohesively from start to finish, mimicking real-world scenarios."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/e2e-pyramid.png",alt:"E2E vs UI Tests vs Integation Tests vs Unit Tests - from SemaphoreCI"})),Object(r.b)("p",null,"While unit tests and integration tests offer valuable insights, they do not replicate how multiple components interact in a live production environment. E2E testing fills that gap and ensures that your application performs as expected when it goes live."),Object(r.b)("h2",{id:"the-importance-of-ephemeral-environments"},"The Importance of Ephemeral Environments"),Object(r.b)("p",null,"In the world of DevOps and CI/CD, ephemeral environments (aka ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/blog/why-preview-environments-are-the-new-thing-in-devops"}),"Preview Environments"),") serve as temporary, isolated setups where you can test your applications. These environments are increasingly vital in agile development frameworks where frequent changes are the norm. They can be provisioned quickly, teared down when no longer needed, and replicated easily. This means you can push your changes more rapidly into production with confidence."),Object(r.b)("h2",{id:"github-actions-and-qovery-a-perfect-match"},"GitHub Actions and Qovery: A Perfect Match"),Object(r.b)("p",null,"GitHub Actions offers a powerful platform for automating workflows, allowing you to build, test, and deploy your code right from GitHub. Qovery, on the other hand, simplifies the provisioning and management of cloud resources, making it incredibly straightforward to set up ephemeral environments. When used in tandem, these tools provide a seamless, automated pipeline for E2E testing."),Object(r.b)("h2",{id:"what-youll-learn"},"What You'll Learn"),Object(r.b)("p",null,"This guide is designed to walk you through the entire process of setting up an automated E2E testing pipeline. We'll start by setting up GitHub Actions, move on to configuring ephemeral environments with Qovery, and finally, integrate these components into a cohesive, automated testing solution."),Object(r.b)("p",null,"By the end of this guide, you'll have a fully operational E2E testing pipeline that will allow you to:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Automate your testing process"),Object(r.b)("li",{parentName:"ol"},"Quickly provision and de-provision environments"),Object(r.b)("li",{parentName:"ol"},"Integrate closely with your GitHub repository"),Object(r.b)("li",{parentName:"ol"},"Save both time and operational costs")),Object(r.b)("p",null,"So, whether you are a developer, a DevOps engineer, a QA specialist, an engineering manager, or even a CTO, this guide offers valuable insights for anyone involved in the software development process."),Object(r.b)("p",null,"Let's dive in!"),Object(r.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(r.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://start.qovery.com"}),"sign in on Qovery")),Object(r.b)("li",{parentName:"ul"},"You have a GitHub account"))),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Contact us via ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum")," if you have any questions concerning Qovery")),Object(r.b)("h2",{id:"tools"},"Tools"),Object(r.b)("p",null,"Here are the tools we will use in this guide:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.qovery.com"}),"Qovery")," for the infrastructure and the ephemeral environment"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/features/actions"}),"GitHub Actions")," for the CI/CD pipeline"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://k6.io/"}),"K6")," for the e2e tests")),Object(r.b)("h2",{id:"7-steps-to-build-e2e-testing-ephemeral-environments-with-github-actions-and-qovery"},"7 Steps to build E2E testing ephemeral environments with GitHub Actions and Qovery"),Object(r.b)("p",null,"Here is the big picture of what we will build:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/1.png",alt:"e2e testing Workflow with github actions and Qovery"})),Object(r.b)("p",null,"We will focus on the most important parts of the workflow - from label number 2 to 11. I assume that you already know GitHub and how to create a Pull Request :)"),Object(r.b)("p",null,"Let's go!"),Object(r.b)("h3",{id:"1-prepare-qovery-blueprint-environment"},"1. Prepare Qovery blueprint environment"),Object(r.b)("p",null,"If you are not already familiar with Qovery, I recommend you to ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/getting-started/what-is-qovery/"}),"What's Qovery"),". In this guide, we will use Qovery to provision our ephemeral environments composed of a Java application (",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app"}),"TODO app"),") and a PostgreSQL database. For this, we will create a blueprint environment that will be used as a template to create ephemeral environments."),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can skip this part if you already have an environment that you want to use as a base for your ephemeral environments.")),Object(r.b)("p",null,"Here are the steps I did to create my blueprint environment:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Connect to ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://console.qovery.com"}),"Qovery"),"."),Object(r.b)("li",{parentName:"ol"},"Create a new project."),Object(r.b)("li",{parentName:"ol"},"Create a new environment named ",Object(r.b)("inlineCode",{parentName:"li"},"blueprint"),"."),Object(r.b)("li",{parentName:"ol"},"Add a ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"/guides/getting-started/create-a-database/"}),"PostgreSQL database")," inside your ",Object(r.b)("inlineCode",{parentName:"li"},"blueprint")," environment."),Object(r.b)("li",{parentName:"ol"},"Add a ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/application/#create-an-application"}),"TODO app")," by using my ECR container registry where I push my image from GitHub Actions (cf next step).")),Object(r.b)("p",null,"At the end of those steps, you should have something like this:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/2.png",alt:"Blueprint environment"})),Object(r.b)("p",null,"If you want to use my ",Object(r.b)("inlineCode",{parentName:"p"},"TODO app")," as an example, you need to properly configure the environment variables of the application. Here is a table with the environment variables you need to set:"),Object(r.b)("details",null,Object(r.b)("summary",null,"Environment Variables"),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Name"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Is Alias?"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Scope"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Value"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Comment"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_DB_NAME")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._DEFAULT_DATABASE_NAME")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database name")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_HOST")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._HOST_INTERNAL")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database host")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_PORT")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._PORT")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database port")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_DATASOURCE_USERNAME")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._LOGIN")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database login")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_DATASOURCE_PASSWORD")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._PASSWORD")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database password")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"QUARKUS_DATASOURCE_JDBC_URL")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"No"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"jdbc:postgresql://{{POSTGRES_HOST}}:{{POSTGRES_PORT}}/{{POSTGRES_DB_NAME}}"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Connection string to the PostgreSQL database"))))),Object(r.b)("p",null,"You're good to go! Now, let's move on to the next step."),Object(r.b)("h3",{id:"2-build-and-push-container-image"},"2. Build and push container image"),Object(r.b)("p",null,"In this step, we will build and push the container image of our application to our ECR container registry. We will use GitHub Actions to do that."),Object(r.b)("p",null,"Create your GitHub Actions workflow inside ",Object(r.b)("inlineCode",{parentName:"p"},".github/workflows")," folder. I named mine ",Object(r.b)("inlineCode",{parentName:"p"},"build-and-push-image.yml"),". Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"...\n build-and-push-container:\n runs-on: ubuntu-latest\n needs: run-unit-tests\n steps:\n - name: Checkout code\n uses: actions/checkout@v3\n\n - name: Configure AWS credentials\n uses: aws-actions/configure-aws-credentials@v2\n with:\n aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}\n aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}\n aws-region: eu-west-3\n\n - name: Login to Amazon ECR\n id: login-ecr\n uses: aws-actions/amazon-ecr-login@v1\n with:\n mask-password: 'true'\n\n - name: Build, Tag, and push image to Amazon ECR\n env:\n ECR_REGISTRY: 687975725498.dkr.ecr.eu-west-3.amazonaws.com\n ECR_REPOSITORY: todo-app\n IMAGE_TAG: ${{ github.sha }}\n run: |\n docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .\n docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest\n docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Find my complete file ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/build-and-push-image.yml"}),"here"))),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"AWS_ACCESS_KEY_ID")," and ",Object(r.b)("inlineCode",{parentName:"p"},"AWS_SECRET_ACCESS_KEY")," are stored as ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.github.com/en/actions/reference/encrypted-secrets"}),"GitHub secrets"),"."),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"The ECR registry is also connected to my Qovery account - so I can pull the pushed image from Qovery as well.")),Object(r.b)("h3",{id:"3-create-an-ephemeral-environment-with-github-actions-and-qovery"},"3. Create an Ephemeral Environment with GitHub Actions and Qovery"),Object(r.b)("p",null,"In this step, we will create an ephemeral environment with GitHub Actions and Qovery. We will use the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI")," inside our GitHub Actions workflow to do that."),Object(r.b)("p",null,"Create your GitHub Actions workflow inside ",Object(r.b)("inlineCode",{parentName:"p"},".github/workflows")," folder. I named mine ",Object(r.b)("inlineCode",{parentName:"p"},"pull-request-run-e2e-tests.yml"),". Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'...\njobs:\n create-e2e-environment:\n if: ${{ github.event.label.name == \'e2e\' }}\n runs-on: ubuntu-latest\n permissions:\n pull-requests: write\n steps:\n - id: create-environment\n name: Create and deploy Qovery E2E environment\n env:\n QOVERY_CLI_ACCESS_TOKEN: ${{ secrets.QOVERY_CLI_ACCESS_TOKEN }}\n run: |\n # Download and install Qovery CLI\n curl -s https://get.qovery.com | bash\n\n echo "Organization name: ${{ vars.QOVERY_ORGANIZATION_NAME }}"\n echo "Project name: ${{ vars.QOVERY_PROJECT_NAME }}"\n echo "Blueprint name: ${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}"\n\n new_environment_name="${GITHUB_HEAD_REF}"\n\n echo "Let\'s clone \'${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}\' environment into \'$new_environment_name\' environment"\n\n qovery environment clone \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}" \\\n --new-environment-name "$new_environment_name"\n\n qovery container update \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}" \\\n --container "${{ vars.QOVERY_APPLICATION_NAME }}" \\\n --tag ${{ github.sha }}\n\n qovery environment deploy \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n -w\n\n qovery_status_markdown_output=`qovery service list \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n --markdown`\n\n echo "QOVERY_STATUS_MARKDOWN_OUTPUT<> "$GITHUB_OUTPUT"\n echo "$qovery_status_markdown_output" >> "$GITHUB_OUTPUT"\n echo "EOF" >> "$GITHUB_OUTPUT"\n')),Object(r.b)("p",null,"Basically, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery environment clone")," command to clone our blueprint environment into a new environment. Then, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery container update")," command to update the container tag of our application. Finally, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery environment deploy")," command to deploy our application. The option ",Object(r.b)("inlineCode",{parentName:"p"},"-w")," is used to wait for the deployment to be completed. We also use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery service list")," command to get the status of our environment and store it in a GitHub output variable. This variable will be used in the next step to display the status of the environment in the Pull Request."),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"...\n - name: PR Comment with URL\n uses: mshick/add-pr-comment@v2\n with:\n message-id: qovery-e2e-environment-status\n message: |\n ${{ steps.create-environment.outputs.QOVERY_STATUS_MARKDOWN_OUTPUT }}\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Find my complete file ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-run-e2e-tests.yml"}),"here"))),Object(r.b)("p",null,"You can see the result of this step in the Pull Request:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/3.png",alt:"Ephemeral environment status in Pull Request"})),Object(r.b)("h3",{id:"4-run-e2e-tests-with-k6"},"4. Run E2E tests with K6"),Object(r.b)("p",null,"In this step, we will run our E2E tests with ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://k6.io"}),"K6"),". K6 is a modern load testing tool that allows you to write tests in JavaScript. It's a great tool to run E2E tests as well. Here is the script we will use:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"import http from 'k6/http';\nimport {check, group, sleep, fail} from 'k6';\nimport {uuidv4} from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';\n\nconst api_host = `${__ENV.API_HOST}/api`;\nexport const options = {\n stages: [\n {duration: '5m', target: 100}, // traffic ramp-up from 1 to 100 users over 5 minutes.\n //{ duration: '30m', target: 100 }, // stay at 100 users for 30 minutes\n {duration: '1m', target: 50}, // ramp-down to 50 users\n ]\n}\n\nexport function setup() {\n // add some data\n const params = {\n headers: {\n 'Content-Type': 'application/json',\n },\n };\n\n for (let i = 0; i < 20; i++) {\n const res = http.post(api_host, JSON.stringify({title: uuidv4()}), params);\n check(res, {'item added': (r) => r.status === 201});\n }\n}\n\nexport default function () {\n http.get(api_host);\n}\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete script is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/e2e/e2e.js"}),"here"))),Object(r.b)("p",null,"We will use the ",Object(r.b)("inlineCode",{parentName:"p"},"setup")," function to add some data to our database. Then, we will use the ",Object(r.b)("inlineCode",{parentName:"p"},"default")," function to get the list of items from our API. We will use the ",Object(r.b)("inlineCode",{parentName:"p"},"options")," variable to define the number of users we want to simulate. In this example, we will simulate 100 users for 5 minutes. You can find more information about the ",Object(r.b)("inlineCode",{parentName:"p"},"options")," variable ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://k6.io/docs/using-k6/options"}),"here"),"."),Object(r.b)("p",null,"To run our E2E tests, we will use the ",Object(r.b)("inlineCode",{parentName:"p"},"k6 run")," command inside our GitHub Actions workflow. Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),' run-e2e-tests:\n if: ${{ github.event.label.name == \'e2e\' }}\n runs-on: ubuntu-latest\n needs: create-e2e-environment\n permissions:\n pull-requests: write\n steps:\n - name: Checkout code\n uses: actions/checkout@v3\n\n - id: run-e2e\n name: Run E2E tests\n env:\n QOVERY_CLI_ACCESS_TOKEN: ${{ secrets.QOVERY_CLI_ACCESS_TOKEN }}\n run: |\n # Download and install Qovery CLI\n curl -s https://get.qovery.com | bash\n\n sudo gpg -k\n sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69\n echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list\n sudo apt-get update\n sudo apt-get install k6\n\n new_environment_name="${GITHUB_HEAD_REF}"\n\n api_domain=`qovery container domain list \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n --container "${{ vars.QOVERY_APPLICATION_NAME }}" | grep "BUILT_IN_DOMAIN" | head -1 | awk \'{print $5}\' | sed -e \'s/\\x1b\\[[0-9;]*m//g\'`\n\n echo "api_domain: $api_domain"\n\n api_host="https://$api_domain"\n echo "API_HOST: $api_host"\n\n e2e_report=`k6 --no-color -q -e API_HOST=$api_host run e2e/e2e.js`\n\n echo "E2E_REPORT<> $GITHUB_OUTPUT\n echo "$e2e_report" >> $GITHUB_OUTPUT\n echo "EOF" >> $GITHUB_OUTPUT\n')),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete file is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-run-e2e-tests.yml"}),"here"))),Object(r.b)("p",null,"We use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery container domain list")," command to get the domain of our application. Then, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"k6")," command to run our E2E tests. We store the result of the tests in a GitHub output variable."),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"The ",Object(r.b)("inlineCode",{parentName:"p"},"qovery container domain list")," command returns ANSI color codes. We use the ",Object(r.b)("inlineCode",{parentName:"p"},"sed -e 's/\\x1b\\[[0-9;]*m//g'")," command to remove them.")),Object(r.b)("h3",{id:"5-display-test-results-in-pull-request"},"5. Display test results in Pull Request"),Object(r.b)("p",null,"In this step, we will display the result of our E2E tests in the Pull Request. We will use the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-output-parameter"}),"GitHub Actions output variables")," to do that. Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"})," - name: Display E2E Report\n uses: mshick/add-pr-comment@v2\n with:\n message-id: e2e-report\n message: |\n E2E Tests Report\n\n --\n\n ```\n ${{ steps.run-e2e.outputs.E2E_REPORT }}\n ```\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete file is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-run-e2e-tests.yml#L109C1-L120C16"}),"here"))),Object(r.b)("p",null,"You can see the result of this step in the Pull Request:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/4.png",alt:"E2E report in Pull Request"})),Object(r.b)("h3",{id:"6-destroy-ephemeral-environment-and-clean-up-resources"},"6. Destroy Ephemeral Environment and clean up resources"),Object(r.b)("p",null,"Now we will destroy the ephemeral environment and clean up the resources when the Pull Request is closed or merged. Here is the yaml:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'name: Destroy and clean up E2E Tests Environment\n\non:\n pull_request:\n types: [ closed ]\n\njobs:\n delete-e2e-environment:\n runs-on: ubuntu-latest\n steps:\n - id: delete-environment\n name: Delete Qovery E2E environment\n env:\n QOVERY_CLI_ACCESS_TOKEN: ${{ secrets.QOVERY_CLI_ACCESS_TOKEN }}\n run: |\n # Download and install Qovery CLI\n curl -s https://get.qovery.com | bash\n\n echo "Organization name: ${{ vars.QOVERY_ORGANIZATION_NAME }}"\n echo "Project name: ${{ vars.QOVERY_PROJECT_NAME }}"\n echo "Blueprint name: ${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}"\n\n new_environment_name="${GITHUB_HEAD_REF}"\n\n echo "Let\'s delete \'$new_environment_name\' environment and release its resources"\n\n qovery environment delete \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n -w\n')),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete file is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-destroy-e2e-environment.yml"}),"here"))),Object(r.b)("p",null,"We just use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery environment delete")," command to delete the ephemeral environment. The option ",Object(r.b)("inlineCode",{parentName:"p"},"-w")," is used to wait for the deletion to be completed. Qovery will automatically release the resources used by the environment."),Object(r.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(r.b)("p",null,"Congratulations! You've successfully built an automated E2E testing pipeline with GitHub Actions and Qovery. You can now run your tests in a fully isolated environment, provisioned and de-provisioned automatically, and integrated with your GitHub repository."),Object(r.b)("p",null,"Some resources:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://semaphoreci.com/blog/e2e-testing"}),"https://semaphoreci.com/blog/e2e-testing")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.loom.com/share/1be8d4229cb74ed7b0526cc2acbca8ad"}),"Webinar record"))))}p.isMDXComponent=!0},424:function(e,t,n){"use strict";n(426);var a=n(0),o=n.n(a),r=n(423),i=n.n(r);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,r=e.icon,l=e.type,s=null;switch(l){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return o.a.createElement("div",{className:i()(n,"alert","alert--"+l,{"alert--fill":a,"alert--icon":!1!==r}),role:"alert"},!1!==r&&o.a.createElement("i",{className:i()("feather","icon-"+(r||s))}),t)}},428:function(e,t,n){var a=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&a(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),o=n.n(a),r=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},437:function(e,t,n){"use strict";var a=n(1),o=(n(442),n(439),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(449),l=n(423),s=n.n(l),c=n(433),b=n.n(c),u=n(448),p=37,m=39;function d(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,o=e.className,i=e.handleKeydown,l=e.style,c=e.values,b=e.selectedValue,u=e.tabRefs;return r.a.createElement("div",{className:n?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:s()("tabs",o,{"tabs--block":t}),style:l},c.map((function(e){var t=e.value,n=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:s()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return i(u,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function h(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,o=e.size,l=e.values,s=l;if(s[0].group){var c=_.groupBy(s,"group");s=Object.keys(c).map((function(e){return{label:e,options:c[e]}}))}return r.a.createElement(i.a,{className:"react-select-container react-select--"+o,classNamePrefix:"react-select",options:s,isClearable:n,placeholder:t,value:l.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,i=e.groupId,l=e.label,s=e.placeholder,c=e.select,O=e.size,v=(e.style,e.values),g=e.urlKey,j=Object(u.a)(),E=j.tabGroupChoices,y=j.setTabGroupChoices,f=Object(o.useState)(n),N=f[0],w=f[1];if(null!=i){var _=E[i];null!=_&&_!==N&&w(_)}var T=function(e){w(e),null!=i&&y(i,e)},R=[],A=function(e,t,n){switch(n.keyCode){case m:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(o.useEffect)((function(){if("undefined"!=typeof window&&window.location&&g){var e=b.a.parse(window.location.search);e[g]&&w(e[g])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(O||"md")},l&&r.a.createElement("div",{className:"margin-vert--sm"},l),v.length>1&&(c?r.a.createElement(h,Object(a.a)({changeSelectedValue:T,handleKeydown:A,placeholder:s,selectedValue:N,size:O,tabRefs:R},e)):r.a.createElement(d,Object(a.a)({changeSelectedValue:T,handleKeydown:A,selectedValue:N,tabRefs:R},e)))),o.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}}}]); \ No newline at end of file diff --git a/41961c76.baf8530b.js b/228c86a3.2db86ee8.js similarity index 90% rename from 41961c76.baf8530b.js rename to 228c86a3.2db86ee8.js index b9707ee121..a2cdda7c1e 100644 --- a/41961c76.baf8530b.js +++ b/228c86a3.2db86ee8.js @@ -1,2 +1,2 @@ -/*! For license information please see 41961c76.baf8530b.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[73],{225:function(e,n,r){"use strict";r.r(n),r.d(n,"frontMatter",(function(){return c})),r.d(n,"metadata",(function(){return s})),r.d(n,"rightToc",(function(){return u})),r.d(n,"default",(function(){return p}));var t=r(1),a=r(9),o=(r(0),r(422)),l=r(421),i=r(426),c={last_modified_on:"2023-11-25",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",author_github:"https://github.com/evoxmusic",tags:["type: guide","provider: kubernetes"]},s={categories:[{name:"provider",title:"Provider",description:null,permalink:"/guides/provider"}],coverLabel:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",permalink:"/guides/provider/guide-kubernetes",readingTime:"2 min read",source:"@site/guides/provider/guide-kubernetes.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"provider: kubernetes",permalink:"/guides/tags/provider-kubernetes"}],title:"Install Qovery on your Kubernetes cluster",truncated:!1,prevItem:{title:"Install Qovery on your Amazon Web Services account",permalink:"/guides/cloud-provider/guide-amazon-web-services"},nextItem:{title:"Install Qovery on your Microsoft Azure account",permalink:"/guides/cloud-provider/guide-microsoft-azure"}},u=[{value:"Install Qovery",id:"install-qovery",children:[]},{value:"Configure",id:"configure",children:[{value:"Qovery",id:"qovery",children:[]},{value:"Nginx",id:"nginx",children:[]},{value:"External DNS",id:"external-dns",children:[]}]}],b={rightToc:u};function p(e){var n=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(t.a)({},b,r,{components:n,mdxType:"MDXLayout"}),Object(o.b)(l.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Installing Qovery on your Kubernetes cluster is currently in beta. ",Object(o.b)("a",Object(t.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/bring-your-own-kubernetes"}),"You need to request your access here"),".")),Object(o.b)("p",null,"In this guide, I'll explain step-by-step how to install Qovery on your Kubernetes cluster."),Object(o.b)(i.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Qovery account"),Object(o.b)("li",{parentName:"ul"},"You have a running Kubernetes cluster"),Object(o.b)("li",{parentName:"ul"},"You have basic knowledge in Kubernetes"),Object(o.b)("li",{parentName:"ul"},"You have installed Helm on your local machine"))),Object(o.b)("h2",{id:"install-qovery"},"Install Qovery"),Object(o.b)("p",null,Object(o.b)("inlineCode",{parentName:"p"},"helm install qovery")),Object(o.b)("h2",{id:"configure"},"Configure"),Object(o.b)("p",null,"To configure Qovery you need to override your Helm ",Object(o.b)("inlineCode",{parentName:"p"},"values.yaml")," file. Here is the simple example of the configuration:"),Object(o.b)("pre",null,Object(o.b)("code",Object(t.a)({parentName:"pre"},{className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'}),"qovery:\n clusterId: set-by-customer\n apkKey: set-by-customer\n jwtToken: set-by-customer\n qovery-cluster-agent:\n enabled: true\n override_chart: qovery-cluster-agent\n qovery-shell-agent:\n enabled: true\n override_chart: qovery-shell-agent\n qovery-engine:\n enabled: false\n override_chart: qovery-engine\ningress:\n ingress-nginx:\n enabled: false\ndns:\n external-dns:\n enabled: false\nlogging:\n promtail:\n enabled: false\n loki:\n enabled: false\ncertificates:\n cert-manager:\n enabled: false\n qovery-cert-manager-webhook:\n enabled: false\n cert-manager-configs:\n enabled: false\naws:\n q-storageclass:\n enabled: false\nobersavability:\n metrics-server:\n enabled: false\n")),Object(o.b)("h3",{id:"qovery"},"Qovery"),Object(o.b)("p",null,"TODO"),Object(o.b)("h3",{id:"nginx"},"Nginx"),Object(o.b)("p",null,"TODO"),Object(o.b)("h3",{id:"external-dns"},"External DNS"),Object(o.b)("p",null,"TODO"))}p.isMDXComponent=!0},420:function(e,n,r){var t;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],n=0;n=0||(a[r]=e[r]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=a.a.createContext({}),u=function(e){var n=a.a.useContext(s),r=n;return e&&(r="function"==typeof e?e(n):i({},n,{},e)),r},b=function(e){var n=u(e.components);return a.a.createElement(s.Provider,{value:n},e.children)},p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.a.createElement(a.a.Fragment,{},n)}},d=Object(t.forwardRef)((function(e,n){var r=e.components,t=e.mdxType,o=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),b=u(r),d=t,f=b["".concat(l,".").concat(d)]||b[d]||p[d]||o;return r?a.a.createElement(f,i({ref:n},s,{components:r})):a.a.createElement(f,i({ref:n},s))}));function f(e,n){var r=arguments,t=n&&n.mdxType;if("string"==typeof e||t){var o=r.length,l=new Array(o);l[0]=d;var i={};for(var c in n)hasOwnProperty.call(n,c)&&(i[c]=n[c]);i.originalType=e,i.mdxType="string"==typeof e?e:t,l[1]=i;for(var s=2;s1?arguments[1]:void 0,r),c=l>2?arguments[2]:void 0,s=void 0===c?r:a(c,r);s>i;)n[i++]=e;return n}},425:function(e,n,r){var t=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&t(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,n,r){"use strict";r(425);var t=r(0),a=r.n(t),o=r(421);n.a=function(e){var n=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),n)}}}]); \ No newline at end of file +/*! For license information please see 228c86a3.2db86ee8.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[42],{194:function(e,n,r){"use strict";r.r(n),r.d(n,"frontMatter",(function(){return c})),r.d(n,"metadata",(function(){return s})),r.d(n,"rightToc",(function(){return u})),r.d(n,"default",(function(){return p}));var t=r(1),a=r(9),o=(r(0),r(425)),l=r(424),i=r(429),c={last_modified_on:"2023-11-25",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",author_github:"https://github.com/evoxmusic",tags:["type: guide","provider: kubernetes"]},s={categories:[{name:"provider",title:"Provider",description:null,permalink:"/guides/provider"}],coverLabel:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",permalink:"/guides/provider/guide-kubernetes",readingTime:"2 min read",source:"@site/guides/provider/guide-kubernetes.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"provider: kubernetes",permalink:"/guides/tags/provider-kubernetes"}],title:"Install Qovery on your Kubernetes cluster",truncated:!1,prevItem:{title:"Install Qovery on your Amazon Web Services account",permalink:"/guides/cloud-provider/guide-amazon-web-services"},nextItem:{title:"Install Qovery on your Microsoft Azure account",permalink:"/guides/cloud-provider/guide-microsoft-azure"}},u=[{value:"Install Qovery",id:"install-qovery",children:[]},{value:"Configure",id:"configure",children:[{value:"Qovery",id:"qovery",children:[]},{value:"Nginx",id:"nginx",children:[]},{value:"External DNS",id:"external-dns",children:[]}]}],b={rightToc:u};function p(e){var n=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(t.a)({},b,r,{components:n,mdxType:"MDXLayout"}),Object(o.b)(l.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Installing Qovery on your Kubernetes cluster is currently in beta. ",Object(o.b)("a",Object(t.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/bring-your-own-kubernetes"}),"You need to request your access here"),".")),Object(o.b)("p",null,"In this guide, I'll explain step-by-step how to install Qovery on your Kubernetes cluster."),Object(o.b)(i.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Qovery account"),Object(o.b)("li",{parentName:"ul"},"You have a running Kubernetes cluster"),Object(o.b)("li",{parentName:"ul"},"You have basic knowledge in Kubernetes"),Object(o.b)("li",{parentName:"ul"},"You have installed Helm on your local machine"))),Object(o.b)("h2",{id:"install-qovery"},"Install Qovery"),Object(o.b)("p",null,Object(o.b)("inlineCode",{parentName:"p"},"helm install qovery")),Object(o.b)("h2",{id:"configure"},"Configure"),Object(o.b)("p",null,"To configure Qovery you need to override your Helm ",Object(o.b)("inlineCode",{parentName:"p"},"values.yaml")," file. Here is the simple example of the configuration:"),Object(o.b)("pre",null,Object(o.b)("code",Object(t.a)({parentName:"pre"},{className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'}),"qovery:\n clusterId: set-by-customer\n apkKey: set-by-customer\n jwtToken: set-by-customer\n qovery-cluster-agent:\n enabled: true\n override_chart: qovery-cluster-agent\n qovery-shell-agent:\n enabled: true\n override_chart: qovery-shell-agent\n qovery-engine:\n enabled: false\n override_chart: qovery-engine\ningress:\n ingress-nginx:\n enabled: false\ndns:\n external-dns:\n enabled: false\nlogging:\n promtail:\n enabled: false\n loki:\n enabled: false\ncertificates:\n cert-manager:\n enabled: false\n qovery-cert-manager-webhook:\n enabled: false\n cert-manager-configs:\n enabled: false\naws:\n q-storageclass:\n enabled: false\nobersavability:\n metrics-server:\n enabled: false\n")),Object(o.b)("h3",{id:"qovery"},"Qovery"),Object(o.b)("p",null,"TODO"),Object(o.b)("h3",{id:"nginx"},"Nginx"),Object(o.b)("p",null,"TODO"),Object(o.b)("h3",{id:"external-dns"},"External DNS"),Object(o.b)("p",null,"TODO"))}p.isMDXComponent=!0},423:function(e,n,r){var t;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],n=0;n=0||(a[r]=e[r]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=a.a.createContext({}),u=function(e){var n=a.a.useContext(s),r=n;return e&&(r="function"==typeof e?e(n):i({},n,{},e)),r},b=function(e){var n=u(e.components);return a.a.createElement(s.Provider,{value:n},e.children)},p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.a.createElement(a.a.Fragment,{},n)}},d=Object(t.forwardRef)((function(e,n){var r=e.components,t=e.mdxType,o=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),b=u(r),d=t,f=b["".concat(l,".").concat(d)]||b[d]||p[d]||o;return r?a.a.createElement(f,i({ref:n},s,{components:r})):a.a.createElement(f,i({ref:n},s))}));function f(e,n){var r=arguments,t=n&&n.mdxType;if("string"==typeof e||t){var o=r.length,l=new Array(o);l[0]=d;var i={};for(var c in n)hasOwnProperty.call(n,c)&&(i[c]=n[c]);i.originalType=e,i.mdxType="string"==typeof e?e:t,l[1]=i;for(var s=2;s1?arguments[1]:void 0,r),c=l>2?arguments[2]:void 0,s=void 0===c?r:a(c,r);s>i;)n[i++]=e;return n}},428:function(e,n,r){var t=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&t(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,n,r){"use strict";r(428);var t=r(0),a=r.n(t),o=r(424);n.a=function(e){var n=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),n)}}}]); \ No newline at end of file diff --git a/2309a9c8.be503e47.js.LICENSE.txt b/228c86a3.2db86ee8.js.LICENSE.txt similarity index 100% rename from 2309a9c8.be503e47.js.LICENSE.txt rename to 228c86a3.2db86ee8.js.LICENSE.txt diff --git a/2309a9c8.be503e47.js b/2309a9c8.ecbe7f13.js similarity index 91% rename from 2309a9c8.be503e47.js rename to 2309a9c8.ecbe7f13.js index b68553d6fc..98244f8fcc 100644 --- a/2309a9c8.be503e47.js +++ b/2309a9c8.ecbe7f13.js @@ -1,2 +1,2 @@ -/*! For license information please see 2309a9c8.be503e47.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[42],{194:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return c})),a.d(t,"rightToc",(function(){return s})),a.d(t,"default",(function(){return l}));var r=a(1),n=a(9),o=(a(0),a(422)),i=(a(431),a(426),a(421),{last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Seed Database",description:"Learn how to seed your database with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),c={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Seed Database",description:"Learn how to seed your database with Qovery",permalink:"/guides/advanced/seed-database",readingTime:"2 min read",source:"@site/guides/advanced/seed-database.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Seed Database",truncated:!1,prevItem:{title:"Production",permalink:"/guides/advanced/production"},nextItem:{title:"Setting up Cloudflare and Custom Domain on Qovery",permalink:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery"}},s=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],u={rightToc:s};function l(e){var t=e.components,a=Object(n.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Seeding a database is a common task when developing an application. It allows you to populate your database with some data to test your application.\nQovery provides multiple ways to seed your database."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to seed your database with Qovery."),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/data-seeding-in-postgres/"}),"Seed your database with a SQL script (simple)")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/data-seeding-in-postgres/"}),"Seed your database with a SQL script and a Docker ENTRYPOINT instruction")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-postgres-database-with-sql-script"}),"Seed your database with a SQL script (advanced)")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-postgres-database-with-sql-script"}),"Seed your database with a SQL script and a Lifecycle Job")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-database-with-replibyte"}),"Seed your database with Replibyte (advanced)")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-database-with-replibyte"}),"Seed your database with Replibyte and a Lifecycle Job")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"Migrate your database schema")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"Migrate your database schema with a Docker ENTRYPOINT instruction")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=seed%20database"}),"Forum")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=seed%20database"}),'List "Seed Database" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}l.isMDXComponent=!0},420:function(e,t,a){var r;!function(){"use strict";var a={}.hasOwnProperty;function n(){for(var e=[],t=0;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var u=n.a.createContext({}),l=function(e){var t=n.a.useContext(u),a=t;return e&&(a="function"==typeof e?e(t):c({},t,{},e)),a},b=function(e){var t=l(e.components);return n.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},p=Object(r.forwardRef)((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),b=l(a),p=r,m=b["".concat(i,".").concat(p)]||b[p]||d[p]||o;return a?n.a.createElement(m,c({ref:t},u,{components:a})):n.a.createElement(m,c({ref:t},u))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=p;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,a),s=i>2?arguments[2]:void 0,u=void 0===s?a:n(s,a);u>c;)t[c++]=e;return t}},425:function(e,t,a){var r=a(28).f,n=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in n||a(10)&&r(n,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var r=a(0),n=a.n(r),o=a(421);t.a=function(e){var t=e.children,a=e.name;return n.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},428:function(e,t,a){"use strict";var r=a(432),n=a(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var a=function(e){var t;switch(e.arrayFormat){case"index":return function(e,a,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=a):r[e]=a};case"bracket":return function(e,a,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],a):r[e]=[a]:r[e]=a};default:return function(e,t,a){void 0!==a[e]?a[e]=[].concat(a[e],t):a[e]=t}}}(t=n({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),n=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),a(decodeURIComponent(n),o,r)})),Object.keys(r).sort().reduce((function(e,t){var a=r[t];return Boolean(a)&&"object"==typeof a&&!Array.isArray(a)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(a):e[t]=a,e}),Object.create(null))):r},t.stringify=function(e,t){var a=function(e){switch(e.arrayFormat){case"index":return function(t,a,r){return null===a?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(a,e)].join("")};case"bracket":return function(t,a){return null===a?o(t,e):[o(t,e),"[]=",o(a,e)].join("")};default:return function(t,a){return null===a?o(t,e):[o(t,e),"=",o(a,e)].join("")}}}(t=n({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var n=e[r];if(void 0===n)return"";if(null===n)return o(r,t);if(Array.isArray(n)){var i=[];return n.slice().forEach((function(e){void 0!==e&&i.push(a(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(n,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=(a(420),a(428)),i=a.n(o);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),b=l[0],d=l[1];return n.a.createElement("div",{className:"steps steps--h"+a},t,!o&&!b&&n.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",n.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",n.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&n.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",n.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,a){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 2309a9c8.ecbe7f13.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[43],{195:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return c})),a.d(t,"rightToc",(function(){return s})),a.d(t,"default",(function(){return l}));var r=a(1),n=a(9),o=(a(0),a(425)),i=(a(434),a(429),a(424),{last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Seed Database",description:"Learn how to seed your database with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),c={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Seed Database",description:"Learn how to seed your database with Qovery",permalink:"/guides/advanced/seed-database",readingTime:"2 min read",source:"@site/guides/advanced/seed-database.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Seed Database",truncated:!1,prevItem:{title:"Production",permalink:"/guides/advanced/production"},nextItem:{title:"Setting up Cloudflare and Custom Domain on Qovery",permalink:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery"}},s=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],u={rightToc:s};function l(e){var t=e.components,a=Object(n.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Seeding a database is a common task when developing an application. It allows you to populate your database with some data to test your application.\nQovery provides multiple ways to seed your database."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to seed your database with Qovery."),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/data-seeding-in-postgres/"}),"Seed your database with a SQL script (simple)")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/data-seeding-in-postgres/"}),"Seed your database with a SQL script and a Docker ENTRYPOINT instruction")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-postgres-database-with-sql-script"}),"Seed your database with a SQL script (advanced)")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-postgres-database-with-sql-script"}),"Seed your database with a SQL script and a Lifecycle Job")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-database-with-replibyte"}),"Seed your database with Replibyte (advanced)")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-database-with-replibyte"}),"Seed your database with Replibyte and a Lifecycle Job")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"Migrate your database schema")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"Migrate your database schema with a Docker ENTRYPOINT instruction")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=seed%20database"}),"Forum")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=seed%20database"}),'List "Seed Database" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}l.isMDXComponent=!0},423:function(e,t,a){var r;!function(){"use strict";var a={}.hasOwnProperty;function n(){for(var e=[],t=0;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var u=n.a.createContext({}),l=function(e){var t=n.a.useContext(u),a=t;return e&&(a="function"==typeof e?e(t):c({},t,{},e)),a},b=function(e){var t=l(e.components);return n.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},p=Object(r.forwardRef)((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),b=l(a),p=r,m=b["".concat(i,".").concat(p)]||b[p]||d[p]||o;return a?n.a.createElement(m,c({ref:t},u,{components:a})):n.a.createElement(m,c({ref:t},u))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=p;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,a),s=i>2?arguments[2]:void 0,u=void 0===s?a:n(s,a);u>c;)t[c++]=e;return t}},428:function(e,t,a){var r=a(28).f,n=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in n||a(10)&&r(n,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var r=a(0),n=a.n(r),o=a(424);t.a=function(e){var t=e.children,a=e.name;return n.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},433:function(e,t,a){"use strict";var r=a(435),n=a(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var a=function(e){var t;switch(e.arrayFormat){case"index":return function(e,a,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=a):r[e]=a};case"bracket":return function(e,a,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],a):r[e]=[a]:r[e]=a};default:return function(e,t,a){void 0!==a[e]?a[e]=[].concat(a[e],t):a[e]=t}}}(t=n({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),n=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),a(decodeURIComponent(n),o,r)})),Object.keys(r).sort().reduce((function(e,t){var a=r[t];return Boolean(a)&&"object"==typeof a&&!Array.isArray(a)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(a):e[t]=a,e}),Object.create(null))):r},t.stringify=function(e,t){var a=function(e){switch(e.arrayFormat){case"index":return function(t,a,r){return null===a?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(a,e)].join("")};case"bracket":return function(t,a){return null===a?o(t,e):[o(t,e),"[]=",o(a,e)].join("")};default:return function(t,a){return null===a?o(t,e):[o(t,e),"=",o(a,e)].join("")}}}(t=n({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var n=e[r];if(void 0===n)return"";if(null===n)return o(r,t);if(Array.isArray(n)){var i=[];return n.slice().forEach((function(e){void 0!==e&&i.push(a(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(n,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=(a(423),a(433)),i=a.n(o);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),b=l[0],d=l[1];return n.a.createElement("div",{className:"steps steps--h"+a},t,!o&&!b&&n.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",n.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",n.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&n.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",n.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,a){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/24e60f8a.4ecb2c65.js.LICENSE.txt b/2309a9c8.ecbe7f13.js.LICENSE.txt similarity index 100% rename from 24e60f8a.4ecb2c65.js.LICENSE.txt rename to 2309a9c8.ecbe7f13.js.LICENSE.txt diff --git a/2486bcfc.81faccc8.js b/2486bcfc.0771cfad.js similarity index 95% rename from 2486bcfc.81faccc8.js rename to 2486bcfc.0771cfad.js index b679fdc5f3..bdfb538b66 100644 --- a/2486bcfc.81faccc8.js +++ b/2486bcfc.0771cfad.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[43],{195:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return o})),n.d(t,"metadata",(function(){return i})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),c=(n(0),n(422)),o={last_modified_on:"2021-06-19",title:"Encryption",description:"End to end encryption for safe data transit and storage"},i={id:"security-and-compliance/encryption",title:"Encryption",description:"End to end encryption for safe data transit and storage",source:"@site/docs/security-and-compliance/encryption.md",permalink:"/docs/security-and-compliance/encryption",sidebar:"docs",previous:{title:"Backup and Restore",permalink:"/docs/security-and-compliance/backup-and-restore"},next:{title:"GDPR",permalink:"/docs/security-and-compliance/gdpr"}},s=[{value:"Data in transit",id:"data-in-transit",children:[]},{value:"Data storage",id:"data-storage",children:[]},{value:"Secrets",id:"secrets",children:[]}],p={rightToc:s};function l(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(c.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(c.b)("h2",{id:"data-in-transit"},"Data in transit"),Object(c.b)("p",null,"Data in transit between the World and Qovery is always encrypted, as all of the services which Qovery supports. Services include the Qovery CLI, management console, Documentation, Landing Page, and Back Office."),Object(c.b)("p",null,"Data in transit between the World and customer applications is encrypted. By default, HTTPS connections use an automatically generated Let's Encrypt certificate, or users may provide their own TLS certificate (Enterprise only)."),Object(c.b)("p",null,"Data in transit on Qovery controlled networks (e.g., between the application and a database) use end-to-end encryption and private networking rules."),Object(c.b)("h2",{id:"data-storage"},"Data storage"),Object(c.b)("p",null,"All application data is encrypted by using encrypted storage (typically using an AES-256 block cipher). If you have specific audit requirements surrounding data at rest encryption, please ",Object(c.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/contact"}),"contact us"),"."),Object(c.b)("h2",{id:"secrets"},"Secrets"),Object(c.b)("p",null,"All secrets data is encrypted by using salted AES-256."))}l.isMDXComponent=!0},422:function(e,t,n){"use strict";n.d(t,"a",(function(){return u})),n.d(t,"b",(function(){return f}));var r=n(0),a=n.n(r);function c(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=a.a.createContext({}),l=function(e){var t=a.a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},u=function(e){var t=l(e.components);return a.a.createElement(p.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},y=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,c=e.originalType,o=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),y=r,f=u["".concat(o,".").concat(y)]||u[y]||d[y]||c;return n?a.a.createElement(f,i({ref:t},p,{components:n})):a.a.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var c=n.length,o=new Array(c);o[0]=y;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:r,o[1]=i;for(var p=2;p=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=a.a.createContext({}),l=function(e){var t=a.a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},u=function(e){var t=l(e.components);return a.a.createElement(p.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},y=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,c=e.originalType,o=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),y=r,f=u["".concat(o,".").concat(y)]||u[y]||d[y]||c;return n?a.a.createElement(f,i({ref:t},p,{components:n})):a.a.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var c=n.length,o=new Array(c);o[0]=y;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:r,o[1]=i;for(var p=2;p=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),b=r,f=p["".concat(i,".").concat(b)]||p[b]||d[b]||o;return n?a.a.createElement(f,c({ref:t},l,{components:n})):a.a.createElement(f,c({ref:t},l))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:a(s,n);l>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),u=Object(r.useState)(null),p=u[0],d=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 24e60f8a.6873997d.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[45],{197:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var r=n(1),a=n(9),o=(n(0),n(425)),i=n(434),c=n(429),s=(n(424),{last_modified_on:"2023-02-22",$schema:"/.meta/.schemas/guides.json",title:"Create a database",description:"How to create a database to your application",series_position:2,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),l={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Create a database",description:"How to create a database to your application",permalink:"/guides/getting-started/create-a-database",readingTime:"2 min read",seriesPosition:2,source:"@site/guides/getting-started/create-a-database.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Create a database",truncated:!1,prevItem:{title:"Hello World. Deploy your first application.",permalink:"/guides/getting-started/deploy-your-first-application"},nextItem:{title:"Custom domain",permalink:"/guides/getting-started/setting-custom-domain"}},u=[{value:"Tutorial",id:"tutorial",children:[{value:"Create a PostgreSQL database",id:"create-a-postgresql-database",children:[]},{value:"Connect your application",id:"connect-your-application",children:[]}]},{value:"Next Steps",id:"next-steps",children:[]}],p={rightToc:u};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Every application needs to store data in a database at some point. You'll learn how to get a production-grade database from Qovery in just a\nfew seconds in this guide."),Object(o.b)(c.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have already deployed an application with Qovery"))),Object(o.b)("h2",{id:"tutorial"},"Tutorial"),Object(o.b)("p",null,"Qovery supports most popular SQL and NoSQL databases (You can see the complete list ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/"}),"here"),"). In this guide we will deploy a\nPostgreSQL database and connect it to our NodeJS app."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h3",{id:"create-a-postgresql-database"},"Create a PostgreSQL database"),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/a76f72ede22c47048009fe874c2c6b03",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0})))),Object(o.b)("li",null,Object(o.b)("h3",{id:"connect-your-application"},"Connect your application"),Object(o.b)("p",null,"Now, we need to connect our application to our database. The credentials (URI, Username, Password ...) are available\nthrough ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"environment variables"),". They are injected by Qovery when your application runs."),Object(o.b)("p",null,"To connect our NodeJS application to our PostgreSQL database, we only have to:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Use the NodeJS PostgreSQL client (",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://node-postgres.com/features/connecting"}),"pg"),")"),Object(o.b)("li",{parentName:"ul"},"Use ",Object(o.b)("inlineCode",{parentName:"li"},"QOVERY_DATABASE_MY_DB_CONNECTION_URI")," into our code")),Object(o.b)("p",null,"Add the ",Object(o.b)("inlineCode",{parentName:"p"},"pg")," dependency into ",Object(o.b)("inlineCode",{parentName:"p"},"package.json")),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-json"}),'{\n /* ... */\n "dependencies": {\n /* ... */\n "pg": "^7.17.0"\n }\n}\n')),Object(o.b)("p",null,"Connect our application to PostgreSQL (",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://node-postgres.com/features/connecting"}),"see documentation"),")"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-javascript"}),"const { Pool } = require('pg')\n\nconst pool = new Pool({\n connectionString: process.env.QOVERY_DATABASE_MY_DB_CONNECTION_URI,\n})\n\n// your can use your connection pool now ...\n")),Object(o.b)("p",null,"Nothing more, well done! You can now be able to use your database.")))),Object(o.b)("h2",{id:"next-steps"},"Next Steps"),Object(o.b)("p",null,"Congratulations, your application has access to your PostgreSQL database. Now we will see how to add your custom domain to your service."))}d.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),b=r,f=p["".concat(i,".").concat(b)]||p[b]||d[b]||o;return n?a.a.createElement(f,c({ref:t},l,{components:n})):a.a.createElement(f,c({ref:t},l))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:a(s,n);l>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),u=Object(r.useState)(null),p=u[0],d=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/267.e1665369.js.LICENSE.txt b/24e60f8a.6873997d.js.LICENSE.txt similarity index 100% rename from 267.e1665369.js.LICENSE.txt rename to 24e60f8a.6873997d.js.LICENSE.txt diff --git a/25b7c3f2.9f2b0167.js b/25b7c3f2.10c8ef93.js similarity index 54% rename from 25b7c3f2.9f2b0167.js rename to 25b7c3f2.10c8ef93.js index 0ca167e6dd..7745ebad46 100644 --- a/25b7c3f2.9f2b0167.js +++ b/25b7c3f2.10c8ef93.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[45],{197:function(n,t,e){"use strict";e.r(t);var r=e(0),u=e.n(r),c=e(469);t.default=function(){return u.a.createElement(c.a,{to:"/docs/getting-started/what-is-qovery/"})}},469:function(n,t,e){"use strict";var r=e(39);e.d(t,"a",(function(){return r.c})),e.d(t,"b",(function(){return r.d})),e.d(t,"c",(function(){return r.e})),e.d(t,"d",(function(){return r.f}))}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[46],{198:function(n,t,e){"use strict";e.r(t);var r=e(0),u=e.n(r),c=e(472);t.default=function(){return u.a.createElement(c.a,{to:"/docs/getting-started/what-is-qovery/"})}},472:function(n,t,e){"use strict";var r=e(39);e.d(t,"a",(function(){return r.c})),e.d(t,"b",(function(){return r.d})),e.d(t,"c",(function(){return r.e})),e.d(t,"d",(function(){return r.f}))}}]); \ No newline at end of file diff --git a/266.a42def44.js b/269.b39b55d3.js similarity index 93% rename from 266.a42def44.js rename to 269.b39b55d3.js index a3b684a81d..f80af35dcb 100644 --- a/266.a42def44.js +++ b/269.b39b55d3.js @@ -1,2 +1,2 @@ -/*! For license information please see 266.a42def44.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[266],{474:function(t,e,n){"use strict";var r,i=n(479);function s(t){return t.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}t.exports={isArray:null,isFunction:null,isObject:null,bind:null,each:null,map:null,mixin:null,isMsie:function(t){if(void 0===t&&(t=navigator.userAgent),/(msie|trident)/i.test(t)){var e=t.match(/(msie |rv:)(\d+(.\d+)?)/i);if(e)return e[2]}return!1},escapeRegExChars:function(t){return t.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},isNumber:function(t){return"number"==typeof t},toStr:function(t){return null==t?"":t+""},cloneDeep:function(t){var e=this.mixin({},t),n=this;return this.each(e,(function(t,r){t&&(n.isArray(t)?e[r]=[].concat(t):n.isObject(t)&&(e[r]=n.cloneDeep(t)))})),e},error:function(t){throw new Error(t)},every:function(t,e){var n=!0;return t?(this.each(t,(function(r,i){n&&(n=e.call(null,r,i,t)&&n)})),!!n):n},any:function(t,e){var n=!1;return t?(this.each(t,(function(r,i){if(e.call(null,r,i,t))return n=!0,!1})),n):n},getUniqueId:(r=0,function(){return r++}),templatify:function(t){if(this.isFunction(t))return t;var e=i.element(t);return"SCRIPT"===e.prop("tagName")?function(){return e.text()}:function(){return String(t)}},defer:function(t){setTimeout(t,0)},noop:function(){},formatPrefix:function(t,e){return e?"":t+"-"},className:function(t,e,n){return(n?"":".")+t+e},escapeHighlightedString:function(t,e,n){e=e||"";var r=document.createElement("div");r.appendChild(document.createTextNode(e)),n=n||"";var i=document.createElement("div");i.appendChild(document.createTextNode(n));var o=document.createElement("div");return o.appendChild(document.createTextNode(t)),o.innerHTML.replace(RegExp(s(r.innerHTML),"g"),e).replace(RegExp(s(i.innerHTML),"g"),n)}}},476:function(t,e){var n,r,i=t.exports={};function s(){throw new Error("setTimeout has not been defined")}function o(){throw new Error("clearTimeout has not been defined")}function a(t){if(n===setTimeout)return setTimeout(t,0);if((n===s||!n)&&setTimeout)return n=setTimeout,setTimeout(t,0);try{return n(t,0)}catch(e){try{return n.call(null,t,0)}catch(e){return n.call(this,t,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:s}catch(t){n=s}try{r="function"==typeof clearTimeout?clearTimeout:o}catch(t){r=o}}();var u,c=[],l=!1,h=-1;function p(){l&&u&&(l=!1,u.length?c=u.concat(c):h=-1,c.length&&f())}function f(){if(!l){var t=a(p);l=!0;for(var e=c.length;e;){for(u=c,c=[];++h1)for(var n=1;n was loaded but did not call our provided callback"),ValidUntilNotFound:s("ValidUntilNotFound","The SecuredAPIKey does not have a validUntil parameter."),JSONPScriptError:s("JSONPScriptError"," + - + - + diff --git a/40a919e7.3d87340d.js b/40a919e7.99078f4e.js similarity index 93% rename from 40a919e7.3d87340d.js rename to 40a919e7.99078f4e.js index b40c333640..6e0ad62f9b 100644 --- a/40a919e7.3d87340d.js +++ b/40a919e7.99078f4e.js @@ -1,2 +1,2 @@ -/*! For license information please see 40a919e7.3d87340d.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[70],{222:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),o=(n(0),n(422)),c=n(431),i=(n(421),{last_modified_on:"2023-03-30",title:"Slack",description:"Learn how to connect Qovery to your Slack workspace"}),l={id:"using-qovery/integration/slack",title:"Slack",description:"Learn how to connect Qovery to your Slack workspace",source:"@site/docs/using-qovery/integration/slack.md",permalink:"/docs/using-qovery/integration/slack",sidebar:"docs",previous:{title:"API",permalink:"/docs/using-qovery/integration/api-integration"},next:{title:"Configuration",permalink:"/docs/using-qovery/configuration"}},s=[{value:"1. Create a Slack App",id:"1-create-a-slack-app",children:[]},{value:"2. Create a Webhook",id:"2-create-a-webhook",children:[]},{value:"3. Create a Webhook in Qovery",id:"3-create-a-webhook-in-qovery",children:[{value:"Considerations",id:"considerations",children:[]}]},{value:"4. Try it!",id:"4-try-it",children:[]}],u={rightToc:s};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"If you'd like to automatically notify your team on a Slack workspace whenever a change has occurred on your apps, this integration will help you out. You can choose which actions should trigger messages on your Slack workspace."),Object(o.b)("p",null,"Here are the steps that we are going through:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"#1-create-a-slack-app"}),"Create a Slack App")),Object(o.b)("li",{parentName:"ol"},Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"#2-create-webhook"}),"Create a Webhook")),Object(o.b)("li",{parentName:"ol"},Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"#3-create-webhook-in-qovery"}),"Setup a Webhook in Qovery")),Object(o.b)("li",{parentName:"ol"},Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"#4-try-it"}),"Try it!"))),Object(o.b)("h2",{id:"1-create-a-slack-app"},"1. Create a Slack App"),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Go to the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api.slack.com/apps?new_app=1"}),"Slack page to create apps")," and create a new app:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-app-slack-1.png",alt:"Create a slack app - step 1"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Create a Slack app from scratch:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-app-slack-2.png",alt:"Create a slack app - step 2"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Call it ",Object(o.b)("inlineCode",{parentName:"p"},"Qovery")," and connect it to the workspace of your choice:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-app-slack-3.png",alt:"Create a slack app - step 3"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Feel free to use an image from ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://raw.githubusercontent.com/Qovery/public-resources/master/qovery_square_new_logo_with_margin.png"}),"here")," as the app's logo:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-app-slack-4.png",alt:"Create a slack app - step 4"}))))),Object(o.b)("h2",{id:"2-create-a-webhook"},"2. Create a Webhook"),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Go to the ",Object(o.b)("inlineCode",{parentName:"p"},"Incoming Webhooks")," page for your newly-created app and toggle ",Object(o.b)("inlineCode",{parentName:"p"},"Activate Incoming Webhooks")," to turn it on:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-webhook-1.png",alt:"Create a webhook integration on Slack - step 1"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Click on ",Object(o.b)("inlineCode",{parentName:"p"},"Add New Webhook to Workspace"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-webhook-2.png",alt:"Create a webhook integration on Slack - step 2"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Select the channel that the notifications will be posted to:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-webhook-3.png",alt:"Create a webhook integration on Slack - step 3"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Copy the webhook URL:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-webhook-4.png",alt:"Create a webhook integration on Slack - step 4"}))))),Object(o.b)("h2",{id:"3-create-a-webhook-in-qovery"},"3. Create a Webhook in Qovery"),Object(o.b)("p",null,"To create a webhook in Qovery, have a look at ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/integration/webhook/#creating-a-webhook"}),"this section"),". For the URL, use the Slack Webhook URL that you got from the previous step. "),Object(o.b)("h3",{id:"considerations"},"Considerations"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You can have multiple webhooks targeting different Slack channels."),Object(o.b)("li",{parentName:"ul"},"You can specify the events that you want to receive. E.g. if you just want to be notified when a deployment failed, then use ",Object(o.b)("inlineCode",{parentName:"li"},'"events": ["DEPLOYMENT_FAILURE"]'),". All the events and the description are available ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/integration/webhook/"}),"on our Webhook section"),"."),Object(o.b)("li",{parentName:"ul"},"You can turn off or delete your webhooks at any time from the webhook section.")),Object(o.b)("p",null,"Check out ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/integration/webhook/"}),"this page")," for further details on how to use and configure the WebHook."),Object(o.b)("h2",{id:"4-try-it"},"4. Try it!"),Object(o.b)("p",null,"Launch a deployment with Qovery, and you will see a message like the one below appearing in your Slack channel \ud83c\udf89"),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/903ef59767ad4f95a59219d631a66d59",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("p",null,"Open a thread on ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum")," if you have any questions."))}b.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},h=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),h=r,f=b["".concat(c,".").concat(h)]||b[h]||p[h]||o;return n?a.a.createElement(f,i({ref:t},s,{components:n})):a.a.createElement(f,i({ref:t},s))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,c=new Array(o);c[0]=h;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var s=2;s1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>i;)t[i++]=e;return t}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var c=[];return a.slice().forEach((function(e){void 0!==e&&c.push(n(r,e,c.length))})),c.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),c=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),u=Object(r.useState)(null),b=u[0],p=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 40a919e7.99078f4e.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[72],{224:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),o=(n(0),n(425)),c=n(434),i=(n(424),{last_modified_on:"2023-03-30",title:"Slack",description:"Learn how to connect Qovery to your Slack workspace"}),l={id:"using-qovery/integration/slack",title:"Slack",description:"Learn how to connect Qovery to your Slack workspace",source:"@site/docs/using-qovery/integration/slack.md",permalink:"/docs/using-qovery/integration/slack",sidebar:"docs",previous:{title:"API",permalink:"/docs/using-qovery/integration/api-integration"},next:{title:"Configuration",permalink:"/docs/using-qovery/configuration"}},s=[{value:"1. Create a Slack App",id:"1-create-a-slack-app",children:[]},{value:"2. Create a Webhook",id:"2-create-a-webhook",children:[]},{value:"3. Create a Webhook in Qovery",id:"3-create-a-webhook-in-qovery",children:[{value:"Considerations",id:"considerations",children:[]}]},{value:"4. Try it!",id:"4-try-it",children:[]}],u={rightToc:s};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"If you'd like to automatically notify your team on a Slack workspace whenever a change has occurred on your apps, this integration will help you out. You can choose which actions should trigger messages on your Slack workspace."),Object(o.b)("p",null,"Here are the steps that we are going through:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"#1-create-a-slack-app"}),"Create a Slack App")),Object(o.b)("li",{parentName:"ol"},Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"#2-create-webhook"}),"Create a Webhook")),Object(o.b)("li",{parentName:"ol"},Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"#3-create-webhook-in-qovery"}),"Setup a Webhook in Qovery")),Object(o.b)("li",{parentName:"ol"},Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"#4-try-it"}),"Try it!"))),Object(o.b)("h2",{id:"1-create-a-slack-app"},"1. Create a Slack App"),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Go to the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api.slack.com/apps?new_app=1"}),"Slack page to create apps")," and create a new app:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-app-slack-1.png",alt:"Create a slack app - step 1"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Create a Slack app from scratch:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-app-slack-2.png",alt:"Create a slack app - step 2"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Call it ",Object(o.b)("inlineCode",{parentName:"p"},"Qovery")," and connect it to the workspace of your choice:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-app-slack-3.png",alt:"Create a slack app - step 3"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Feel free to use an image from ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://raw.githubusercontent.com/Qovery/public-resources/master/qovery_square_new_logo_with_margin.png"}),"here")," as the app's logo:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-app-slack-4.png",alt:"Create a slack app - step 4"}))))),Object(o.b)("h2",{id:"2-create-a-webhook"},"2. Create a Webhook"),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Go to the ",Object(o.b)("inlineCode",{parentName:"p"},"Incoming Webhooks")," page for your newly-created app and toggle ",Object(o.b)("inlineCode",{parentName:"p"},"Activate Incoming Webhooks")," to turn it on:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-webhook-1.png",alt:"Create a webhook integration on Slack - step 1"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Click on ",Object(o.b)("inlineCode",{parentName:"p"},"Add New Webhook to Workspace"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-webhook-2.png",alt:"Create a webhook integration on Slack - step 2"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Select the channel that the notifications will be posted to:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-webhook-3.png",alt:"Create a webhook integration on Slack - step 3"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Copy the webhook URL:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/slack/create-webhook-4.png",alt:"Create a webhook integration on Slack - step 4"}))))),Object(o.b)("h2",{id:"3-create-a-webhook-in-qovery"},"3. Create a Webhook in Qovery"),Object(o.b)("p",null,"To create a webhook in Qovery, have a look at ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/integration/webhook/#creating-a-webhook"}),"this section"),". For the URL, use the Slack Webhook URL that you got from the previous step. "),Object(o.b)("h3",{id:"considerations"},"Considerations"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You can have multiple webhooks targeting different Slack channels."),Object(o.b)("li",{parentName:"ul"},"You can specify the events that you want to receive. E.g. if you just want to be notified when a deployment failed, then use ",Object(o.b)("inlineCode",{parentName:"li"},'"events": ["DEPLOYMENT_FAILURE"]'),". All the events and the description are available ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/integration/webhook/"}),"on our Webhook section"),"."),Object(o.b)("li",{parentName:"ul"},"You can turn off or delete your webhooks at any time from the webhook section.")),Object(o.b)("p",null,"Check out ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/integration/webhook/"}),"this page")," for further details on how to use and configure the WebHook."),Object(o.b)("h2",{id:"4-try-it"},"4. Try it!"),Object(o.b)("p",null,"Launch a deployment with Qovery, and you will see a message like the one below appearing in your Slack channel \ud83c\udf89"),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/903ef59767ad4f95a59219d631a66d59",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("p",null,"Open a thread on ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum")," if you have any questions."))}b.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},h=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),h=r,f=b["".concat(c,".").concat(h)]||b[h]||p[h]||o;return n?a.a.createElement(f,i({ref:t},s,{components:n})):a.a.createElement(f,i({ref:t},s))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,c=new Array(o);c[0]=h;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var s=2;s1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>i;)t[i++]=e;return t}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var c=[];return a.slice().forEach((function(e){void 0!==e&&c.push(n(r,e,c.length))})),c.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),c=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),u=Object(r.useState)(null),b=u[0],p=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/41961c76.baf8530b.js.LICENSE.txt b/40a919e7.99078f4e.js.LICENSE.txt similarity index 100% rename from 41961c76.baf8530b.js.LICENSE.txt rename to 40a919e7.99078f4e.js.LICENSE.txt diff --git a/40ec3bc1.79c53ed2.js b/40ec3bc1.600981f9.js similarity index 94% rename from 40ec3bc1.79c53ed2.js rename to 40ec3bc1.600981f9.js index f748866789..034dc1f54c 100644 --- a/40ec3bc1.79c53ed2.js +++ b/40ec3bc1.600981f9.js @@ -1,2 +1,2 @@ -/*! For license information please see 40ec3bc1.79c53ed2.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[71],{223:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return d}));var o=n(1),r=n(9),i=(n(0),n(422)),a=n(431),c=n(421),l=n(426),s={last_modified_on:"2023-09-27",$schema:"/.meta/.schemas/guides.json",title:"How to integrate Qovery with GitHub Actions",description:"Learn how to integrate Qovery with GitHub Actions",author_github:"https://github.com/l0ck3",tags:["type: tutorial","technology: github"],hide_pagination:!0},u={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to integrate Qovery with GitHub Actions",description:"Learn how to integrate Qovery with GitHub Actions",permalink:"/guides/tutorial/how-to-integrate-qovery-with-github-actions",readingTime:"6 min read",source:"@site/guides/tutorial/how-to-integrate-qovery-with-github-actions.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: github",permalink:"/guides/tags/technology-github"}],title:"How to integrate Qovery with GitHub Actions",truncated:!1,prevItem:{title:"How to deploy Helm charts",permalink:"/guides/tutorial/how-to-deploy-helm-charts"},nextItem:{title:"How to run commands before the application starts",permalink:"/guides/tutorial/how-to-run-commands-at-application-startup"}},p=[{value:"Goal",id:"goal",children:[]},{value:"Get your application ready",id:"get-your-application-ready",children:[]},{value:"Add your GitHub Actions Workflow",id:"add-your-github-actions-workflow",children:[{value:"Create the Workflows directory",id:"create-the-workflows-directory",children:[]},{value:"Add a Test and Deploy workflow",id:"add-a-test-and-deploy-workflow",children:[]},{value:"Get a Qovery API token",id:"get-a-qovery-api-token",children:[]},{value:"Add your token to your GitHub repository secrets",id:"add-your-token-to-your-github-repository-secrets",children:[]}]},{value:"Execute the GitHub Actions Pipeline",id:"execute-the-github-actions-pipeline",children:[]},{value:"Advanced use-cases",id:"advanced-use-cases",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],b={rightToc:p};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Getting started with Qovery is easy. Just plug your Git repository, and you can deploy your application directly.\nBut in some cases you will want a more advanced CI workflow where some steps need to happen before deployment."),Object(i.b)("p",null,"One of the CI tools you can use for that matter is GitHub Actions."),Object(i.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"You have a Qovery cluster running."),Object(i.b)("li",{parentName:"ul"},"You are using GitHub Actions as a CI server."),Object(i.b)("li",{parentName:"ul"},"You have a Qovery application deployed."),Object(i.b)("li",{parentName:"ul"},"You have the Qovery CLI installed and configured."))),Object(i.b)("p",null,"If you don't have an application running on Qovery yet, check ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/getting-started/deploy-my-app/"}),"the documentation")," to create one."),Object(i.b)("h2",{id:"goal"},"Goal"),Object(i.b)("p",null,"In this tutorial, we will deploy an application with GitHub Actions by using the Qovery CLI."),Object(i.b)("h2",{id:"get-your-application-ready"},"Get your application ready"),Object(i.b)("p",null,"The first thing we need to do, is to disable automatic deployments. By default, Qovery applications get re-deployed whenever you push some code to the configured branch.\nSince we want to trigger the deployment through GitHub Actions, we need to disable this behavior."),Object(i.b)("p",null,"Go to your application page, then click ",Object(i.b)("inlineCode",{parentName:"p"},"Settings"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/1.png",alt:""})),Object(i.b)("p",null,"Then on the ",Object(i.b)("inlineCode",{parentName:"p"},"General")," section go to the ",Object(i.b)("inlineCode",{parentName:"p"},"Auto-deploy")," field, select ",Object(i.b)("inlineCode",{parentName:"p"},"Off"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/2.png",alt:""})),Object(i.b)("p",null,"Click save."),Object(i.b)("h2",{id:"add-your-github-actions-workflow"},"Add your GitHub Actions Workflow"),Object(i.b)("p",null,"We will now add a GitHub Actions workflow to your application. Workflow are defined with YAML configuration files that are placed in the code directory of your application.\nAs an example we will define a workflow for a NodeJS application. We will first run our unit tests, then launch the Qovery deployment if the tests pass."),Object(i.b)("p",null,"You can adapt those steps for your own stack and needs. Read the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.github.com/en/actions"}),"GitHub Actions documentation")," to learn more."),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("h3",{id:"create-the-workflows-directory"},"Create the Workflows directory"),Object(i.b)("p",null,"All your workflows files must be stored in a specific ",Object(i.b)("inlineCode",{parentName:"p"},".github/workflows")," directory. Create this directory at the root of your project.")),Object(i.b)("li",null,Object(i.b)("h3",{id:"add-a-test-and-deploy-workflow"},"Add a Test and Deploy workflow"),Object(i.b)("p",null,"In your Workflows folder, create a ",Object(i.b)("inlineCode",{parentName:"p"},"test-and-deploy.yaml")," file with the following content:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-yaml",metastring:'title=".github/workflows/test-and-deploy.yaml"',title:'".github/workflows/test-and-deploy.yaml"'}),"name: Test And Deploy to Qovery\non:\n workflow_call:\n secrets:\n api-token:\n required: true\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v2\n - name: Install modules\n run: yarn\n - name: Run tests\n run: yarn test\n deploy:\n needs: test\n runs-on: ubuntu-latest\n name: Deploy on Qovery\n steps:\n - name: Deploy with Qovery\n uses: actions/checkout@v3\n env:\n QOVERY_CLI_ACCESS_TOKEN: ${{ secrets.QOVERY_CLI_ACCESS_TOKEN }}\n shell: bash\n run: |\n # Download and install Qovery CLI\n curl -s https://get.qovery.com | bash\n\n qovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id ${{ github.sha }} \\\n --watch\n")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"on")," section contains a ",Object(i.b)("inlineCode",{parentName:"li"},"workflow_call")," directive. It means that this workflow will be triggered when called from another workflow.\nWe're doing this because we won't use this workflow directly. Since we might have several environments to deploy to Qovery depending on the branch, we could have one workflow per environment, and we want to avoid repeating all the steps."),Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"inputs")," and ",Object(i.b)("inlineCode",{parentName:"li"},"secrets")," sections are defining the values that we will need to pass to our workflow"),Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"jobs")," section lists the ",Object(i.b)("inlineCode",{parentName:"li"},"jobs")," and the ",Object(i.b)("inlineCode",{parentName:"li"},"steps")," that in needs to accomplish. Here we have two jobs and five steps:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"test")," where we check out the code, we install Yarn modules, and we run tests through Jest"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"deploy")," where we check out the code and deploy to Qovery.")))),Object(i.b)("p",null,"Several things worth noting:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"The organization / project / environment / application are case-sensitive."),Object(i.b)("li",{parentName:"ul"},"Our ",Object(i.b)("inlineCode",{parentName:"li"},"deploy")," job has a ",Object(i.b)("inlineCode",{parentName:"li"},"needs")," instructions, telling GitHub Actions that this job can only run when the ",Object(i.b)("inlineCode",{parentName:"li"},"test")," job succeeds."),Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"with")," section of our last ",Object(i.b)("inlineCode",{parentName:"li"},"deploy")," step contains interpolated strings: ${{ inputs.xxxx }}. Those are values passed to our workflow, that our Qovery action needs. They will be passed from the calling workflow."))),Object(i.b)("li",null,Object(i.b)("h3",{id:"get-a-qovery-api-token"},"Get a Qovery API token"),Object(i.b)("p",null,"To get an API token, use the Qovery CLI:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"qovery token\n")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Select your organization. (tokens are valid for only one organization)."),Object(i.b)("li",{parentName:"ul"},"Enter a name for your token."),Object(i.b)("li",{parentName:"ul"},"Enter a description for your token.")),Object(i.b)("p",null,"You will get an output like this one:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{}),"qovery token Qovery: ---- Never share this authentication token and keep it secure ----\nQovery: qov_xxx....\nQovery: ---- Never share this authentication token and keep it secure ----\n")),Object(i.b)(c.a,{type:"warning",mdxType:"Alert"},"At the time of writing, we don't have a way to invalidate tokens. Store it carefully.")),Object(i.b)("li",null,Object(i.b)("h3",{id:"add-your-token-to-your-github-repository-secrets"},"Add your token to your GitHub repository secrets"),Object(i.b)("p",null,"Go to your GitHub repository then to the ",Object(i.b)("inlineCode",{parentName:"p"},"Settings"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/3.png",alt:""})),Object(i.b)("p",null,"Got to the ",Object(i.b)("inlineCode",{parentName:"p"},"Secrets/Actions")," section and click on ",Object(i.b)("inlineCode",{parentName:"p"},"New repository secret"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/4.png",alt:""})),Object(i.b)("p",null,"Add your secret with the name ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_API_TOKEN")," and save:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/5.png",alt:""}))))),Object(i.b)("h2",{id:"execute-the-github-actions-pipeline"},"Execute the GitHub Actions Pipeline"),Object(i.b)("p",null,"We're done with the setup. You can now push your code to the ",Object(i.b)("inlineCode",{parentName:"p"},"main")," branch. If you did it properly, under the ",Object(i.b)("inlineCode",{parentName:"p"},"Actions")," tab on your GitHub repository, you should see your job being run."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/6.png",alt:""})),Object(i.b)("p",null,"You can click on it to see the details of the jobs. Once the testing phase is green, it will start the deployment job."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/7.png",alt:""})),Object(i.b)("p",null,"As soon as the job is set up, and it starts actually deploying, go to the Qovery console and check that your application is actually being deployed."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/8.png",alt:""})),Object(i.b)("h2",{id:"advanced-use-cases"},"Advanced use-cases"),Object(i.b)("p",null,"It's possible to support any use cases by using the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI"),". Like cloning an environment, changing the branch of some applications and deploying only a subset of applications. Refers to the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI documentation")," to explore all the commands that you can use."),Object(i.b)("p",null,"Check out our ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"GitHub Actions integration page")," to check out more examples."),Object(i.b)("h2",{id:"conclusion"},"Conclusion"),Object(i.b)("p",null,"Integrating Qovery with GitHub Actions enables more complex workflows than just deploying on code push. You can make sure your test suite succeeds before deploying\nor anything else you need, without sacrificing the simplicity of deployment Qovery brings you."))}d.isMDXComponent=!0},420:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=o,h=p["".concat(a,".").concat(d)]||p[d]||b[d]||i;return n?r.a.createElement(h,c({ref:t},s,{components:n})):r.a.createElement(h,c({ref:t},s))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,a[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=a>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var o=n(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var o=n(0),r=n.n(o),i=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var o=n(432),r=n(51);function i(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(r),i,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[i(t,e),"[",o,"]"].join(""):[i(t,e),"[",i(o,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return i(o,t);if(Array.isArray(r)){var a=[];return r.slice().forEach((function(e){void 0!==e&&a.push(n(o,e,a.length))})),a.join("&")}return i(o,t)+"="+i(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(420),n(428)),a=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(l),u=Object(o.useState)(null),p=u[0],b=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!p&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 40ec3bc1.600981f9.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[73],{225:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return d}));var o=n(1),r=n(9),i=(n(0),n(425)),a=n(434),c=n(424),l=n(429),s={last_modified_on:"2023-09-27",$schema:"/.meta/.schemas/guides.json",title:"How to integrate Qovery with GitHub Actions",description:"Learn how to integrate Qovery with GitHub Actions",author_github:"https://github.com/l0ck3",tags:["type: tutorial","technology: github"],hide_pagination:!0},u={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to integrate Qovery with GitHub Actions",description:"Learn how to integrate Qovery with GitHub Actions",permalink:"/guides/tutorial/how-to-integrate-qovery-with-github-actions",readingTime:"6 min read",source:"@site/guides/tutorial/how-to-integrate-qovery-with-github-actions.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: github",permalink:"/guides/tags/technology-github"}],title:"How to integrate Qovery with GitHub Actions",truncated:!1,prevItem:{title:"How to deploy Helm charts",permalink:"/guides/tutorial/how-to-deploy-helm-charts"},nextItem:{title:"How to run commands before the application starts",permalink:"/guides/tutorial/how-to-run-commands-at-application-startup"}},p=[{value:"Goal",id:"goal",children:[]},{value:"Get your application ready",id:"get-your-application-ready",children:[]},{value:"Add your GitHub Actions Workflow",id:"add-your-github-actions-workflow",children:[{value:"Create the Workflows directory",id:"create-the-workflows-directory",children:[]},{value:"Add a Test and Deploy workflow",id:"add-a-test-and-deploy-workflow",children:[]},{value:"Get a Qovery API token",id:"get-a-qovery-api-token",children:[]},{value:"Add your token to your GitHub repository secrets",id:"add-your-token-to-your-github-repository-secrets",children:[]}]},{value:"Execute the GitHub Actions Pipeline",id:"execute-the-github-actions-pipeline",children:[]},{value:"Advanced use-cases",id:"advanced-use-cases",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],b={rightToc:p};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Getting started with Qovery is easy. Just plug your Git repository, and you can deploy your application directly.\nBut in some cases you will want a more advanced CI workflow where some steps need to happen before deployment."),Object(i.b)("p",null,"One of the CI tools you can use for that matter is GitHub Actions."),Object(i.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"You have a Qovery cluster running."),Object(i.b)("li",{parentName:"ul"},"You are using GitHub Actions as a CI server."),Object(i.b)("li",{parentName:"ul"},"You have a Qovery application deployed."),Object(i.b)("li",{parentName:"ul"},"You have the Qovery CLI installed and configured."))),Object(i.b)("p",null,"If you don't have an application running on Qovery yet, check ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/getting-started/deploy-my-app/"}),"the documentation")," to create one."),Object(i.b)("h2",{id:"goal"},"Goal"),Object(i.b)("p",null,"In this tutorial, we will deploy an application with GitHub Actions by using the Qovery CLI."),Object(i.b)("h2",{id:"get-your-application-ready"},"Get your application ready"),Object(i.b)("p",null,"The first thing we need to do, is to disable automatic deployments. By default, Qovery applications get re-deployed whenever you push some code to the configured branch.\nSince we want to trigger the deployment through GitHub Actions, we need to disable this behavior."),Object(i.b)("p",null,"Go to your application page, then click ",Object(i.b)("inlineCode",{parentName:"p"},"Settings"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/1.png",alt:""})),Object(i.b)("p",null,"Then on the ",Object(i.b)("inlineCode",{parentName:"p"},"General")," section go to the ",Object(i.b)("inlineCode",{parentName:"p"},"Auto-deploy")," field, select ",Object(i.b)("inlineCode",{parentName:"p"},"Off"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/2.png",alt:""})),Object(i.b)("p",null,"Click save."),Object(i.b)("h2",{id:"add-your-github-actions-workflow"},"Add your GitHub Actions Workflow"),Object(i.b)("p",null,"We will now add a GitHub Actions workflow to your application. Workflow are defined with YAML configuration files that are placed in the code directory of your application.\nAs an example we will define a workflow for a NodeJS application. We will first run our unit tests, then launch the Qovery deployment if the tests pass."),Object(i.b)("p",null,"You can adapt those steps for your own stack and needs. Read the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.github.com/en/actions"}),"GitHub Actions documentation")," to learn more."),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("h3",{id:"create-the-workflows-directory"},"Create the Workflows directory"),Object(i.b)("p",null,"All your workflows files must be stored in a specific ",Object(i.b)("inlineCode",{parentName:"p"},".github/workflows")," directory. Create this directory at the root of your project.")),Object(i.b)("li",null,Object(i.b)("h3",{id:"add-a-test-and-deploy-workflow"},"Add a Test and Deploy workflow"),Object(i.b)("p",null,"In your Workflows folder, create a ",Object(i.b)("inlineCode",{parentName:"p"},"test-and-deploy.yaml")," file with the following content:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-yaml",metastring:'title=".github/workflows/test-and-deploy.yaml"',title:'".github/workflows/test-and-deploy.yaml"'}),"name: Test And Deploy to Qovery\non:\n workflow_call:\n secrets:\n api-token:\n required: true\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v2\n - name: Install modules\n run: yarn\n - name: Run tests\n run: yarn test\n deploy:\n needs: test\n runs-on: ubuntu-latest\n name: Deploy on Qovery\n steps:\n - name: Deploy with Qovery\n uses: actions/checkout@v3\n env:\n QOVERY_CLI_ACCESS_TOKEN: ${{ secrets.QOVERY_CLI_ACCESS_TOKEN }}\n shell: bash\n run: |\n # Download and install Qovery CLI\n curl -s https://get.qovery.com | bash\n\n qovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id ${{ github.sha }} \\\n --watch\n")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"on")," section contains a ",Object(i.b)("inlineCode",{parentName:"li"},"workflow_call")," directive. It means that this workflow will be triggered when called from another workflow.\nWe're doing this because we won't use this workflow directly. Since we might have several environments to deploy to Qovery depending on the branch, we could have one workflow per environment, and we want to avoid repeating all the steps."),Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"inputs")," and ",Object(i.b)("inlineCode",{parentName:"li"},"secrets")," sections are defining the values that we will need to pass to our workflow"),Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"jobs")," section lists the ",Object(i.b)("inlineCode",{parentName:"li"},"jobs")," and the ",Object(i.b)("inlineCode",{parentName:"li"},"steps")," that in needs to accomplish. Here we have two jobs and five steps:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"test")," where we check out the code, we install Yarn modules, and we run tests through Jest"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"deploy")," where we check out the code and deploy to Qovery.")))),Object(i.b)("p",null,"Several things worth noting:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"The organization / project / environment / application are case-sensitive."),Object(i.b)("li",{parentName:"ul"},"Our ",Object(i.b)("inlineCode",{parentName:"li"},"deploy")," job has a ",Object(i.b)("inlineCode",{parentName:"li"},"needs")," instructions, telling GitHub Actions that this job can only run when the ",Object(i.b)("inlineCode",{parentName:"li"},"test")," job succeeds."),Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"with")," section of our last ",Object(i.b)("inlineCode",{parentName:"li"},"deploy")," step contains interpolated strings: ${{ inputs.xxxx }}. Those are values passed to our workflow, that our Qovery action needs. They will be passed from the calling workflow."))),Object(i.b)("li",null,Object(i.b)("h3",{id:"get-a-qovery-api-token"},"Get a Qovery API token"),Object(i.b)("p",null,"To get an API token, use the Qovery CLI:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"qovery token\n")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Select your organization. (tokens are valid for only one organization)."),Object(i.b)("li",{parentName:"ul"},"Enter a name for your token."),Object(i.b)("li",{parentName:"ul"},"Enter a description for your token.")),Object(i.b)("p",null,"You will get an output like this one:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{}),"qovery token Qovery: ---- Never share this authentication token and keep it secure ----\nQovery: qov_xxx....\nQovery: ---- Never share this authentication token and keep it secure ----\n")),Object(i.b)(c.a,{type:"warning",mdxType:"Alert"},"At the time of writing, we don't have a way to invalidate tokens. Store it carefully.")),Object(i.b)("li",null,Object(i.b)("h3",{id:"add-your-token-to-your-github-repository-secrets"},"Add your token to your GitHub repository secrets"),Object(i.b)("p",null,"Go to your GitHub repository then to the ",Object(i.b)("inlineCode",{parentName:"p"},"Settings"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/3.png",alt:""})),Object(i.b)("p",null,"Got to the ",Object(i.b)("inlineCode",{parentName:"p"},"Secrets/Actions")," section and click on ",Object(i.b)("inlineCode",{parentName:"p"},"New repository secret"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/4.png",alt:""})),Object(i.b)("p",null,"Add your secret with the name ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_API_TOKEN")," and save:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/5.png",alt:""}))))),Object(i.b)("h2",{id:"execute-the-github-actions-pipeline"},"Execute the GitHub Actions Pipeline"),Object(i.b)("p",null,"We're done with the setup. You can now push your code to the ",Object(i.b)("inlineCode",{parentName:"p"},"main")," branch. If you did it properly, under the ",Object(i.b)("inlineCode",{parentName:"p"},"Actions")," tab on your GitHub repository, you should see your job being run."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/6.png",alt:""})),Object(i.b)("p",null,"You can click on it to see the details of the jobs. Once the testing phase is green, it will start the deployment job."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/7.png",alt:""})),Object(i.b)("p",null,"As soon as the job is set up, and it starts actually deploying, go to the Qovery console and check that your application is actually being deployed."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/8.png",alt:""})),Object(i.b)("h2",{id:"advanced-use-cases"},"Advanced use-cases"),Object(i.b)("p",null,"It's possible to support any use cases by using the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI"),". Like cloning an environment, changing the branch of some applications and deploying only a subset of applications. Refers to the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI documentation")," to explore all the commands that you can use."),Object(i.b)("p",null,"Check out our ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"GitHub Actions integration page")," to check out more examples."),Object(i.b)("h2",{id:"conclusion"},"Conclusion"),Object(i.b)("p",null,"Integrating Qovery with GitHub Actions enables more complex workflows than just deploying on code push. You can make sure your test suite succeeds before deploying\nor anything else you need, without sacrificing the simplicity of deployment Qovery brings you."))}d.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=o,h=p["".concat(a,".").concat(d)]||p[d]||b[d]||i;return n?r.a.createElement(h,c({ref:t},s,{components:n})):r.a.createElement(h,c({ref:t},s))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,a[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=a>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var o=n(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var o=n(0),r=n.n(o),i=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var o=n(435),r=n(51);function i(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(r),i,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[i(t,e),"[",o,"]"].join(""):[i(t,e),"[",i(o,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return i(o,t);if(Array.isArray(r)){var a=[];return r.slice().forEach((function(e){void 0!==e&&a.push(n(o,e,a.length))})),a.join("&")}return i(o,t)+"="+i(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(423),n(433)),a=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(l),u=Object(o.useState)(null),p=u[0],b=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!p&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/4354960d.3839b40a.js.LICENSE.txt b/40ec3bc1.600981f9.js.LICENSE.txt similarity index 100% rename from 4354960d.3839b40a.js.LICENSE.txt rename to 40ec3bc1.600981f9.js.LICENSE.txt diff --git a/1a6d3985.bbd46e60.js b/410a9ba0.5c3bfd65.js similarity index 94% rename from 1a6d3985.bbd46e60.js rename to 410a9ba0.5c3bfd65.js index 76a709484d..53c78c1e2e 100644 --- a/1a6d3985.bbd46e60.js +++ b/410a9ba0.5c3bfd65.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[31],{180:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var a=n(1),o=n(9),r=(n(0),n(422)),i=n(421),l=(n(434),n(426)),c={last_modified_on:"2022-07-25",$schema:"/.meta/.schemas/guides.json",title:"Create your Staging environment from your Production environment on AWS",description:"Step-by-step guide to create your Staging environment from your Production environment on AWS",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Create your Staging environment from your Production environment on AWS",description:"Step-by-step guide to create your Staging environment from your Production environment on AWS",permalink:"/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws",readingTime:"4 min read",source:"@site/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Create your Staging environment from your Production environment on AWS",truncated:!1,prevItem:{title:"Create a Playground Environment on AWS",permalink:"/guides/tutorial/create-a-playground-environment-on-aws"},nextItem:{title:"Creating API clients using OpenAPI Tools",permalink:"/guides/tutorial/generate-qovery-api-client"}},u=[{value:"Create a Staging cluster",id:"create-a-staging-cluster",children:[]},{value:"Create your Staging environment from your Production environment",id:"create-your-staging-environment-from-your-production-environment",children:[]},{value:"Update your Staging applications",id:"update-your-staging-applications",children:[]},{value:"Override your environment variables and secrets",id:"override-your-environment-variables-and-secrets",children:[]},{value:"Deploy your Staging environment",id:"deploy-your-staging-environment",children:[]},{value:"Wrapping up",id:"wrapping-up",children:[]}],b={rightToc:u};function d(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Let's say you have your production environment deployed, and you want to create a staging environment. You have two options:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Create a staging environment from scratch."),Object(r.b)("li",{parentName:"ol"},"Clone your production environment and create a staging environment from it.")),Object(r.b)("p",null,"This is where the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#clone-environment"}),"Environment Clone")," feature of Qovery is useful. No need to create a new environment, just clone your production environment and create a staging environment from it."),Object(r.b)("p",null,"In this guide, we will go through the steps to create a staging environment from your production environment. While applying the best practices by isolating the staging and production environments on two separated clusters and VPCs."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/staging-from-production/complete_schema.jpg",alt:"Complete Production and Staging infrastructure"})),Object(r.b)(l.a,{mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You already have a production environment deployed with Qovery."))),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/5a76704a196341deb5384b2883113adf",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"create-a-staging-cluster"},"Create a Staging cluster"),Object(r.b)("p",null,"Isolating the staging and production environments on two separate clusters and VPCs is a good practice to avoid any potential issues on your production caused by your staging. This is not a mandatory step, but it is well recommended."),Object(r.b)("p",null,"To create your staging cluster it's also recommended creating a new AWS IAM access key and secret access key in a dedicated subaccount. Then you are sure that both environment are also isolated at the AWS level:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Go to your Organization cluster settings"),Object(r.b)("li",{parentName:"ol"},'Add a cluster with a name "staging"'),Object(r.b)("li",{parentName:"ol"},"Deploy your staging cluster")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/6f77172ae27f41a5a7c0e3114398b13c",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"create-your-staging-environment-from-your-production-environment"},"Create your Staging environment from your Production environment"),Object(r.b)("p",null,"Now, to create your staging environment from your production environment, you need to:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},'Go inside your production environment and click on the "Clone" button.'),Object(r.b)("li",{parentName:"ol"},'Give a name to your staging environment (E.g "staging")'),Object(r.b)("li",{parentName:"ol"},'Set the mode to "Staging"'),Object(r.b)("li",{parentName:"ol"},'Set the cluster to "staging"'),Object(r.b)("li",{parentName:"ol"},'Click on "Create"'),Object(r.b)("li",{parentName:"ol"},"That's it!")),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Cloning your database does not copy the data (yet). To copy your data in Staging consider using ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.replibyte.com"}),"Replibyte")," in standalone. It will be integrated in Qovery soon.")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/614844644cc34211853de19dafe79343",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Your environment has been created, but it's not deployed yet. Before we will make some adjustment to change the branch of our applications."),Object(r.b)("h2",{id:"update-your-staging-applications"},"Update your Staging applications"),Object(r.b)("p",null,"Your Staging applications have the same branch as your Production applications. To update your Staging applications branch, you need to:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Go into the settings of each of your applications."),Object(r.b)("li",{parentName:"ol"},"Update the branch to your Staging branch."),Object(r.b)("li",{parentName:"ol"},'Click on "Save"')),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/2f4f2a22062a4840ae077285a891e573",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"We are almost done, now we need to smartly change our environment variables and secrets to not use the one used in production."),Object(r.b)("h2",{id:"override-your-environment-variables-and-secrets"},"Override your environment variables and secrets"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Qovery makes the distinction between ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Environment Variables")," and ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Secrets")," even if for your app both will be used as Environment Variables. Check out ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"this documentation")," to learn more about Environment Variables and Secrets.")),Object(r.b)("p",null,"Let's say you have a production environment with the following environment variables:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"NODE_ENV=production"),Object(r.b)("li",{parentName:"ul"},"STRIPE_API_KEY=a-secret-production-key")),Object(r.b)("p",null,"You might need to keep the same keys but change the values. That's exactly what Qovery makes you do with the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#override-environment-variable"}),"Environment Variable Override feature"),". You can keep the same keys but change the values."),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/3d5d37dd9a954500aa559afead5b3981",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"deploy-your-staging-environment"},"Deploy your Staging environment"),Object(r.b)("p",null,'Finally, your Staging environment has been created and set up correctly. To deploy your Staging environment, you just need to go to your Staging environment and click on the "Deploy" button.'),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/04709bb4039447c699477ce01a1aa19b",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(r.b)("p",null,"In this guide, we have covered everything you need to know to create a secure staging environment from your production. Now, you can take a look at ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/data-seeding-in-postgres/"}),"how to seed your Staging database")," (Guide for Postgres but applicable for most databases)."))}d.isMDXComponent=!0},421:function(e,t,n){"use strict";n(423);var a=n(0),o=n.n(a),r=n(420),i=n.n(r);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,r=e.icon,l=e.type,c=null;switch(l){case"danger":c="alert-triangle";break;case"success":c="check-circle";break;case"warning":c="alert-triangle";break;default:c="info"}return o.a.createElement("div",{className:i()(n,"alert","alert--"+l,{"alert--fill":a,"alert--icon":!1!==r}),role:"alert"},!1!==r&&o.a.createElement("i",{className:i()("feather","icon-"+(r||c))}),t)}},425:function(e,t,n){var a=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&a(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),o=n.n(a),r=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},434:function(e,t,n){"use strict";var a=n(1),o=(n(439),n(436),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(446),l=n(420),c=n.n(l),s=n(428),u=n.n(s),b=n(445),d=37,m=39;function p(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,o=e.className,i=e.handleKeydown,l=e.style,s=e.values,u=e.selectedValue,b=e.tabRefs;return r.a.createElement("div",{className:n?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:c()("tabs",o,{"tabs--block":t}),style:l},s.map((function(e){var t=e.value,n=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":u===t,className:c()("tab-item",{"tab-item--active":u===t}),key:t,ref:function(e){return b.push(e)},onKeyDown:function(e){return i(b,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function g(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,o=e.size,l=e.values,c=l;if(c[0].group){var s=_.groupBy(c,"group");c=Object.keys(s).map((function(e){return{label:e,options:s[e]}}))}return r.a.createElement(i.a,{className:"react-select-container react-select--"+o,classNamePrefix:"react-select",options:c,isClearable:n,placeholder:t,value:l.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,i=e.groupId,l=e.label,c=e.placeholder,s=e.select,v=e.size,h=(e.style,e.values),y=e.urlKey,f=Object(b.a)(),w=f.tabGroupChoices,O=f.setTabGroupChoices,j=Object(o.useState)(n),k=j[0],S=j[1];if(null!=i){var N=w[i];null!=N&&N!==k&&S(N)}var C=function(e){S(e),null!=i&&O(i,e)},E=[],T=function(e,t,n){switch(n.keyCode){case m:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case d:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(o.useEffect)((function(){if("undefined"!=typeof window&&window.location&&y){var e=u.a.parse(window.location.search);e[y]&&S(e[y])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(v||"md")},l&&r.a.createElement("div",{className:"margin-vert--sm"},l),h.length>1&&(s?r.a.createElement(g,Object(a.a)({changeSelectedValue:C,handleKeydown:T,placeholder:c,selectedValue:k,size:v,tabRefs:E},e)):r.a.createElement(p,Object(a.a)({changeSelectedValue:C,handleKeydown:T,selectedValue:k,tabRefs:E},e)))),o.Children.toArray(t).filter((function(e){return e.props.value===k}))[0])}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[74],{226:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var a=n(1),o=n(9),r=(n(0),n(425)),i=n(424),l=(n(437),n(429)),c={last_modified_on:"2022-07-25",$schema:"/.meta/.schemas/guides.json",title:"Create your Staging environment from your Production environment on AWS",description:"Step-by-step guide to create your Staging environment from your Production environment on AWS",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Create your Staging environment from your Production environment on AWS",description:"Step-by-step guide to create your Staging environment from your Production environment on AWS",permalink:"/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws",readingTime:"4 min read",source:"@site/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Create your Staging environment from your Production environment on AWS",truncated:!1,prevItem:{title:"Create a Playground Environment on AWS",permalink:"/guides/tutorial/create-a-playground-environment-on-aws"},nextItem:{title:"Creating API clients using OpenAPI Tools",permalink:"/guides/tutorial/generate-qovery-api-client"}},u=[{value:"Create a Staging cluster",id:"create-a-staging-cluster",children:[]},{value:"Create your Staging environment from your Production environment",id:"create-your-staging-environment-from-your-production-environment",children:[]},{value:"Update your Staging applications",id:"update-your-staging-applications",children:[]},{value:"Override your environment variables and secrets",id:"override-your-environment-variables-and-secrets",children:[]},{value:"Deploy your Staging environment",id:"deploy-your-staging-environment",children:[]},{value:"Wrapping up",id:"wrapping-up",children:[]}],b={rightToc:u};function d(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Let's say you have your production environment deployed, and you want to create a staging environment. You have two options:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Create a staging environment from scratch."),Object(r.b)("li",{parentName:"ol"},"Clone your production environment and create a staging environment from it.")),Object(r.b)("p",null,"This is where the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#clone-environment"}),"Environment Clone")," feature of Qovery is useful. No need to create a new environment, just clone your production environment and create a staging environment from it."),Object(r.b)("p",null,"In this guide, we will go through the steps to create a staging environment from your production environment. While applying the best practices by isolating the staging and production environments on two separated clusters and VPCs."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/staging-from-production/complete_schema.jpg",alt:"Complete Production and Staging infrastructure"})),Object(r.b)(l.a,{mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You already have a production environment deployed with Qovery."))),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/5a76704a196341deb5384b2883113adf",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"create-a-staging-cluster"},"Create a Staging cluster"),Object(r.b)("p",null,"Isolating the staging and production environments on two separate clusters and VPCs is a good practice to avoid any potential issues on your production caused by your staging. This is not a mandatory step, but it is well recommended."),Object(r.b)("p",null,"To create your staging cluster it's also recommended creating a new AWS IAM access key and secret access key in a dedicated subaccount. Then you are sure that both environment are also isolated at the AWS level:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Go to your Organization cluster settings"),Object(r.b)("li",{parentName:"ol"},'Add a cluster with a name "staging"'),Object(r.b)("li",{parentName:"ol"},"Deploy your staging cluster")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/6f77172ae27f41a5a7c0e3114398b13c",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"create-your-staging-environment-from-your-production-environment"},"Create your Staging environment from your Production environment"),Object(r.b)("p",null,"Now, to create your staging environment from your production environment, you need to:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},'Go inside your production environment and click on the "Clone" button.'),Object(r.b)("li",{parentName:"ol"},'Give a name to your staging environment (E.g "staging")'),Object(r.b)("li",{parentName:"ol"},'Set the mode to "Staging"'),Object(r.b)("li",{parentName:"ol"},'Set the cluster to "staging"'),Object(r.b)("li",{parentName:"ol"},'Click on "Create"'),Object(r.b)("li",{parentName:"ol"},"That's it!")),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Cloning your database does not copy the data (yet). To copy your data in Staging consider using ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.replibyte.com"}),"Replibyte")," in standalone. It will be integrated in Qovery soon.")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/614844644cc34211853de19dafe79343",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Your environment has been created, but it's not deployed yet. Before we will make some adjustment to change the branch of our applications."),Object(r.b)("h2",{id:"update-your-staging-applications"},"Update your Staging applications"),Object(r.b)("p",null,"Your Staging applications have the same branch as your Production applications. To update your Staging applications branch, you need to:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Go into the settings of each of your applications."),Object(r.b)("li",{parentName:"ol"},"Update the branch to your Staging branch."),Object(r.b)("li",{parentName:"ol"},'Click on "Save"')),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/2f4f2a22062a4840ae077285a891e573",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"We are almost done, now we need to smartly change our environment variables and secrets to not use the one used in production."),Object(r.b)("h2",{id:"override-your-environment-variables-and-secrets"},"Override your environment variables and secrets"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Qovery makes the distinction between ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Environment Variables")," and ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Secrets")," even if for your app both will be used as Environment Variables. Check out ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"this documentation")," to learn more about Environment Variables and Secrets.")),Object(r.b)("p",null,"Let's say you have a production environment with the following environment variables:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"NODE_ENV=production"),Object(r.b)("li",{parentName:"ul"},"STRIPE_API_KEY=a-secret-production-key")),Object(r.b)("p",null,"You might need to keep the same keys but change the values. That's exactly what Qovery makes you do with the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#override-environment-variable"}),"Environment Variable Override feature"),". You can keep the same keys but change the values."),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/3d5d37dd9a954500aa559afead5b3981",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"deploy-your-staging-environment"},"Deploy your Staging environment"),Object(r.b)("p",null,'Finally, your Staging environment has been created and set up correctly. To deploy your Staging environment, you just need to go to your Staging environment and click on the "Deploy" button.'),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/04709bb4039447c699477ce01a1aa19b",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(r.b)("p",null,"In this guide, we have covered everything you need to know to create a secure staging environment from your production. Now, you can take a look at ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/data-seeding-in-postgres/"}),"how to seed your Staging database")," (Guide for Postgres but applicable for most databases)."))}d.isMDXComponent=!0},424:function(e,t,n){"use strict";n(426);var a=n(0),o=n.n(a),r=n(423),i=n.n(r);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,r=e.icon,l=e.type,c=null;switch(l){case"danger":c="alert-triangle";break;case"success":c="check-circle";break;case"warning":c="alert-triangle";break;default:c="info"}return o.a.createElement("div",{className:i()(n,"alert","alert--"+l,{"alert--fill":a,"alert--icon":!1!==r}),role:"alert"},!1!==r&&o.a.createElement("i",{className:i()("feather","icon-"+(r||c))}),t)}},428:function(e,t,n){var a=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&a(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),o=n.n(a),r=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},437:function(e,t,n){"use strict";var a=n(1),o=(n(442),n(439),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(449),l=n(423),c=n.n(l),s=n(433),u=n.n(s),b=n(448),d=37,m=39;function p(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,o=e.className,i=e.handleKeydown,l=e.style,s=e.values,u=e.selectedValue,b=e.tabRefs;return r.a.createElement("div",{className:n?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:c()("tabs",o,{"tabs--block":t}),style:l},s.map((function(e){var t=e.value,n=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":u===t,className:c()("tab-item",{"tab-item--active":u===t}),key:t,ref:function(e){return b.push(e)},onKeyDown:function(e){return i(b,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function g(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,o=e.size,l=e.values,c=l;if(c[0].group){var s=_.groupBy(c,"group");c=Object.keys(s).map((function(e){return{label:e,options:s[e]}}))}return r.a.createElement(i.a,{className:"react-select-container react-select--"+o,classNamePrefix:"react-select",options:c,isClearable:n,placeholder:t,value:l.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,i=e.groupId,l=e.label,c=e.placeholder,s=e.select,v=e.size,h=(e.style,e.values),y=e.urlKey,f=Object(b.a)(),w=f.tabGroupChoices,O=f.setTabGroupChoices,j=Object(o.useState)(n),k=j[0],S=j[1];if(null!=i){var N=w[i];null!=N&&N!==k&&S(N)}var C=function(e){S(e),null!=i&&O(i,e)},E=[],T=function(e,t,n){switch(n.keyCode){case m:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case d:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(o.useEffect)((function(){if("undefined"!=typeof window&&window.location&&y){var e=u.a.parse(window.location.search);e[y]&&S(e[y])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(v||"md")},l&&r.a.createElement("div",{className:"margin-vert--sm"},l),h.length>1&&(s?r.a.createElement(g,Object(a.a)({changeSelectedValue:C,handleKeydown:T,placeholder:c,selectedValue:k,size:v,tabRefs:E},e)):r.a.createElement(p,Object(a.a)({changeSelectedValue:C,handleKeydown:T,selectedValue:k,tabRefs:E},e)))),o.Children.toArray(t).filter((function(e){return e.props.value===k}))[0])}}}]); \ No newline at end of file diff --git a/228c86a3.fdea663b.js b/41961c76.0e79742a.js similarity index 90% rename from 228c86a3.fdea663b.js rename to 41961c76.0e79742a.js index c5c664d9b5..6c22ac8fb8 100644 --- a/228c86a3.fdea663b.js +++ b/41961c76.0e79742a.js @@ -1,2 +1,2 @@ -/*! For license information please see 228c86a3.fdea663b.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[41],{193:function(e,n,r){"use strict";r.r(n),r.d(n,"frontMatter",(function(){return c})),r.d(n,"metadata",(function(){return s})),r.d(n,"rightToc",(function(){return u})),r.d(n,"default",(function(){return p}));var t=r(1),a=r(9),o=(r(0),r(422)),l=r(421),i=r(426),c={last_modified_on:"2023-11-25",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",author_github:"https://github.com/evoxmusic",tags:["type: guide","provider: kubernetes"]},s={categories:[{name:"provider",title:"Provider",description:null,permalink:"/guides/provider"}],coverLabel:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",permalink:"/guides/provider/guide-kubernetes",readingTime:"2 min read",source:"@site/guides/provider/guide-kubernetes.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"provider: kubernetes",permalink:"/guides/tags/provider-kubernetes"}],title:"Install Qovery on your Kubernetes cluster",truncated:!1,prevItem:{title:"Install Qovery on your Amazon Web Services account",permalink:"/guides/cloud-provider/guide-amazon-web-services"},nextItem:{title:"Install Qovery on your Microsoft Azure account",permalink:"/guides/cloud-provider/guide-microsoft-azure"}},u=[{value:"Install Qovery",id:"install-qovery",children:[]},{value:"Configure",id:"configure",children:[{value:"Qovery",id:"qovery",children:[]},{value:"Nginx",id:"nginx",children:[]},{value:"External DNS",id:"external-dns",children:[]}]}],b={rightToc:u};function p(e){var n=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(t.a)({},b,r,{components:n,mdxType:"MDXLayout"}),Object(o.b)(l.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Installing Qovery on your Kubernetes cluster is currently in beta. ",Object(o.b)("a",Object(t.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/bring-your-own-kubernetes"}),"You need to request your access here"),".")),Object(o.b)("p",null,"In this guide, I'll explain step-by-step how to install Qovery on your Kubernetes cluster."),Object(o.b)(i.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Qovery account"),Object(o.b)("li",{parentName:"ul"},"You have a running Kubernetes cluster"),Object(o.b)("li",{parentName:"ul"},"You have basic knowledge in Kubernetes"),Object(o.b)("li",{parentName:"ul"},"You have installed Helm on your local machine"))),Object(o.b)("h2",{id:"install-qovery"},"Install Qovery"),Object(o.b)("p",null,Object(o.b)("inlineCode",{parentName:"p"},"helm install qovery")),Object(o.b)("h2",{id:"configure"},"Configure"),Object(o.b)("p",null,"To configure Qovery you need to override your Helm ",Object(o.b)("inlineCode",{parentName:"p"},"values.yaml")," file. Here is the simple example of the configuration:"),Object(o.b)("pre",null,Object(o.b)("code",Object(t.a)({parentName:"pre"},{className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'}),"qovery:\n clusterId: set-by-customer\n apkKey: set-by-customer\n jwtToken: set-by-customer\n qovery-cluster-agent:\n enabled: true\n override_chart: qovery-cluster-agent\n qovery-shell-agent:\n enabled: true\n override_chart: qovery-shell-agent\n qovery-engine:\n enabled: false\n override_chart: qovery-engine\ningress:\n ingress-nginx:\n enabled: false\ndns:\n external-dns:\n enabled: false\nlogging:\n promtail:\n enabled: false\n loki:\n enabled: false\ncertificates:\n cert-manager:\n enabled: false\n qovery-cert-manager-webhook:\n enabled: false\n cert-manager-configs:\n enabled: false\naws:\n q-storageclass:\n enabled: false\nobersavability:\n metrics-server:\n enabled: false\n")),Object(o.b)("h3",{id:"qovery"},"Qovery"),Object(o.b)("p",null,"TODO"),Object(o.b)("h3",{id:"nginx"},"Nginx"),Object(o.b)("p",null,"TODO"),Object(o.b)("h3",{id:"external-dns"},"External DNS"),Object(o.b)("p",null,"TODO"))}p.isMDXComponent=!0},420:function(e,n,r){var t;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],n=0;n=0||(a[r]=e[r]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=a.a.createContext({}),u=function(e){var n=a.a.useContext(s),r=n;return e&&(r="function"==typeof e?e(n):i({},n,{},e)),r},b=function(e){var n=u(e.components);return a.a.createElement(s.Provider,{value:n},e.children)},p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.a.createElement(a.a.Fragment,{},n)}},d=Object(t.forwardRef)((function(e,n){var r=e.components,t=e.mdxType,o=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),b=u(r),d=t,f=b["".concat(l,".").concat(d)]||b[d]||p[d]||o;return r?a.a.createElement(f,i({ref:n},s,{components:r})):a.a.createElement(f,i({ref:n},s))}));function f(e,n){var r=arguments,t=n&&n.mdxType;if("string"==typeof e||t){var o=r.length,l=new Array(o);l[0]=d;var i={};for(var c in n)hasOwnProperty.call(n,c)&&(i[c]=n[c]);i.originalType=e,i.mdxType="string"==typeof e?e:t,l[1]=i;for(var s=2;s1?arguments[1]:void 0,r),c=l>2?arguments[2]:void 0,s=void 0===c?r:a(c,r);s>i;)n[i++]=e;return n}},425:function(e,n,r){var t=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&t(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,n,r){"use strict";r(425);var t=r(0),a=r.n(t),o=r(421);n.a=function(e){var n=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),n)}}}]); \ No newline at end of file +/*! For license information please see 41961c76.0e79742a.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[75],{227:function(e,n,r){"use strict";r.r(n),r.d(n,"frontMatter",(function(){return c})),r.d(n,"metadata",(function(){return s})),r.d(n,"rightToc",(function(){return u})),r.d(n,"default",(function(){return p}));var t=r(1),a=r(9),o=(r(0),r(425)),l=r(424),i=r(429),c={last_modified_on:"2023-11-25",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",author_github:"https://github.com/evoxmusic",tags:["type: guide","provider: kubernetes"]},s={categories:[{name:"provider",title:"Provider",description:null,permalink:"/guides/provider"}],coverLabel:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",permalink:"/guides/provider/guide-kubernetes",readingTime:"2 min read",source:"@site/guides/provider/guide-kubernetes.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"provider: kubernetes",permalink:"/guides/tags/provider-kubernetes"}],title:"Install Qovery on your Kubernetes cluster",truncated:!1,prevItem:{title:"Install Qovery on your Amazon Web Services account",permalink:"/guides/cloud-provider/guide-amazon-web-services"},nextItem:{title:"Install Qovery on your Microsoft Azure account",permalink:"/guides/cloud-provider/guide-microsoft-azure"}},u=[{value:"Install Qovery",id:"install-qovery",children:[]},{value:"Configure",id:"configure",children:[{value:"Qovery",id:"qovery",children:[]},{value:"Nginx",id:"nginx",children:[]},{value:"External DNS",id:"external-dns",children:[]}]}],b={rightToc:u};function p(e){var n=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(t.a)({},b,r,{components:n,mdxType:"MDXLayout"}),Object(o.b)(l.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Installing Qovery on your Kubernetes cluster is currently in beta. ",Object(o.b)("a",Object(t.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/bring-your-own-kubernetes"}),"You need to request your access here"),".")),Object(o.b)("p",null,"In this guide, I'll explain step-by-step how to install Qovery on your Kubernetes cluster."),Object(o.b)(i.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Qovery account"),Object(o.b)("li",{parentName:"ul"},"You have a running Kubernetes cluster"),Object(o.b)("li",{parentName:"ul"},"You have basic knowledge in Kubernetes"),Object(o.b)("li",{parentName:"ul"},"You have installed Helm on your local machine"))),Object(o.b)("h2",{id:"install-qovery"},"Install Qovery"),Object(o.b)("p",null,Object(o.b)("inlineCode",{parentName:"p"},"helm install qovery")),Object(o.b)("h2",{id:"configure"},"Configure"),Object(o.b)("p",null,"To configure Qovery you need to override your Helm ",Object(o.b)("inlineCode",{parentName:"p"},"values.yaml")," file. Here is the simple example of the configuration:"),Object(o.b)("pre",null,Object(o.b)("code",Object(t.a)({parentName:"pre"},{className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'}),"qovery:\n clusterId: set-by-customer\n apkKey: set-by-customer\n jwtToken: set-by-customer\n qovery-cluster-agent:\n enabled: true\n override_chart: qovery-cluster-agent\n qovery-shell-agent:\n enabled: true\n override_chart: qovery-shell-agent\n qovery-engine:\n enabled: false\n override_chart: qovery-engine\ningress:\n ingress-nginx:\n enabled: false\ndns:\n external-dns:\n enabled: false\nlogging:\n promtail:\n enabled: false\n loki:\n enabled: false\ncertificates:\n cert-manager:\n enabled: false\n qovery-cert-manager-webhook:\n enabled: false\n cert-manager-configs:\n enabled: false\naws:\n q-storageclass:\n enabled: false\nobersavability:\n metrics-server:\n enabled: false\n")),Object(o.b)("h3",{id:"qovery"},"Qovery"),Object(o.b)("p",null,"TODO"),Object(o.b)("h3",{id:"nginx"},"Nginx"),Object(o.b)("p",null,"TODO"),Object(o.b)("h3",{id:"external-dns"},"External DNS"),Object(o.b)("p",null,"TODO"))}p.isMDXComponent=!0},423:function(e,n,r){var t;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],n=0;n=0||(a[r]=e[r]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=a.a.createContext({}),u=function(e){var n=a.a.useContext(s),r=n;return e&&(r="function"==typeof e?e(n):i({},n,{},e)),r},b=function(e){var n=u(e.components);return a.a.createElement(s.Provider,{value:n},e.children)},p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.a.createElement(a.a.Fragment,{},n)}},d=Object(t.forwardRef)((function(e,n){var r=e.components,t=e.mdxType,o=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),b=u(r),d=t,f=b["".concat(l,".").concat(d)]||b[d]||p[d]||o;return r?a.a.createElement(f,i({ref:n},s,{components:r})):a.a.createElement(f,i({ref:n},s))}));function f(e,n){var r=arguments,t=n&&n.mdxType;if("string"==typeof e||t){var o=r.length,l=new Array(o);l[0]=d;var i={};for(var c in n)hasOwnProperty.call(n,c)&&(i[c]=n[c]);i.originalType=e,i.mdxType="string"==typeof e?e:t,l[1]=i;for(var s=2;s1?arguments[1]:void 0,r),c=l>2?arguments[2]:void 0,s=void 0===c?r:a(c,r);s>i;)n[i++]=e;return n}},428:function(e,n,r){var t=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&t(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,n,r){"use strict";r(428);var t=r(0),a=r.n(t),o=r(424);n.a=function(e){var n=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),n)}}}]); \ No newline at end of file diff --git a/43a5f55b.643a0273.js.LICENSE.txt b/41961c76.0e79742a.js.LICENSE.txt similarity index 100% rename from 43a5f55b.643a0273.js.LICENSE.txt rename to 41961c76.0e79742a.js.LICENSE.txt diff --git a/4354960d.3839b40a.js b/4354960d.a5104efe.js similarity index 88% rename from 4354960d.3839b40a.js rename to 4354960d.a5104efe.js index e78c5e4c22..7a800b4145 100644 --- a/4354960d.3839b40a.js +++ b/4354960d.a5104efe.js @@ -1,2 +1,2 @@ -/*! For license information please see 4354960d.3839b40a.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[74],{226:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return s}));var r=n(1),a=n(9),o=(n(0),n(422)),c=n(429),i={last_modified_on:"2023-06-05",title:"Deploy my application",description:"How to deploy your application"},u={id:"getting-started/deploy-my-app",title:"Deploy my application",description:"How to deploy your application",source:"@site/docs/getting-started/deploy-my-app.md",permalink:"/docs/getting-started/deploy-my-app",sidebar:"docs",previous:{title:"Install Qovery",permalink:"/docs/getting-started/install-qovery"},next:{title:"What's next?",permalink:"/docs/getting-started/whats-next"}},l=[{value:"Advanced",id:"advanced",children:[]}],p={rightToc:l};function s(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Check our video tutorial to learn how to quickly deploy your application with Qovery!"),Object(o.b)(c.a,{to:"/guides/getting-started",mdxType:"Jump"},"Deploy your application"),Object(o.b)("h2",{id:"advanced"},"Advanced"),Object(o.b)("p",null,"Once you know how to deploy a simple application, take a look at how to go beyond with Qovery."),Object(o.b)(c.a,{to:"/guides/advanced",mdxType:"Jump"},"Advanced"))}s.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),p=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},s=function(e){var t=p(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),s=p(n),f=r,m=s["".concat(c,".").concat(f)]||s[f]||d[f]||o;return n?a.a.createElement(m,i({ref:t},l,{components:n})):a.a.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,c=new Array(o);c[0]=f;var i={};for(var u in t)hasOwnProperty.call(t,u)&&(i[u]=t[u]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var l=2;l0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:p})):o.a.createElement("a",Object(r.a)({},e,{href:p}))}},429:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(427),c=n(420),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,c=e.leftIcon,u=e.rightIcon,l=e.size,p=e.target,s=e.to,d=i()("jump-to","jump-to--"+l,n),f=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},c&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+c})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return p?a.a.createElement("a",{href:s,target:p,className:d},f):a.a.createElement(o.a,{to:s,className:d},f)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file +/*! For license information please see 4354960d.a5104efe.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[76],{228:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return s}));var r=n(1),a=n(9),o=(n(0),n(425)),c=n(431),i={last_modified_on:"2023-06-05",title:"Deploy my application",description:"How to deploy your application"},u={id:"getting-started/deploy-my-app",title:"Deploy my application",description:"How to deploy your application",source:"@site/docs/getting-started/deploy-my-app.md",permalink:"/docs/getting-started/deploy-my-app",sidebar:"docs",previous:{title:"Install Qovery",permalink:"/docs/getting-started/install-qovery"},next:{title:"What's next?",permalink:"/docs/getting-started/whats-next"}},l=[{value:"Advanced",id:"advanced",children:[]}],p={rightToc:l};function s(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Check our video tutorial to learn how to quickly deploy your application with Qovery!"),Object(o.b)(c.a,{to:"/guides/getting-started",mdxType:"Jump"},"Deploy your application"),Object(o.b)("h2",{id:"advanced"},"Advanced"),Object(o.b)("p",null,"Once you know how to deploy a simple application, take a look at how to go beyond with Qovery."),Object(o.b)(c.a,{to:"/guides/advanced",mdxType:"Jump"},"Advanced"))}s.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),p=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},s=function(e){var t=p(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),s=p(n),f=r,m=s["".concat(c,".").concat(f)]||s[f]||d[f]||o;return n?a.a.createElement(m,i({ref:t},l,{components:n})):a.a.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,c=new Array(o);c[0]=f;var i={};for(var u in t)hasOwnProperty.call(t,u)&&(i[u]=t[u]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var l=2;l0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:p})):o.a.createElement("a",Object(r.a)({},e,{href:p}))}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(430),c=n(423),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,c=e.leftIcon,u=e.rightIcon,l=e.size,p=e.target,s=e.to,d=i()("jump-to","jump-to--"+l,n),f=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},c&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+c})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return p?a.a.createElement("a",{href:s,target:p,className:d},f):a.a.createElement(o.a,{to:s,className:d},f)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/44b423be.dd56a64e.js.LICENSE.txt b/4354960d.a5104efe.js.LICENSE.txt similarity index 100% rename from 44b423be.dd56a64e.js.LICENSE.txt rename to 4354960d.a5104efe.js.LICENSE.txt diff --git a/43a5f55b.643a0273.js b/43a5f55b.5bcdf48c.js similarity index 97% rename from 43a5f55b.643a0273.js rename to 43a5f55b.5bcdf48c.js index 25de6b7acb..6a25323b9f 100644 --- a/43a5f55b.643a0273.js +++ b/43a5f55b.5bcdf48c.js @@ -1,2 +1,2 @@ -/*! For license information please see 43a5f55b.643a0273.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[75],{227:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),c=(n(0),n(422)),o=n(431),i=n(421),l=n(426),s={last_modified_on:"2023-11-28",title:"Amazon Web Services (AWS)",description:"Learn how to configure and plug your Amazon Web Services (AWS) account"},b={id:"using-qovery/configuration/cloud-service-provider/amazon-web-services",title:"Amazon Web Services (AWS)",description:"Learn how to configure and plug your Amazon Web Services (AWS) account",source:"@site/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services.md",permalink:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services",sidebar:"docs",previous:{title:"Cloud Service Provider",permalink:"/docs/using-qovery/configuration/cloud-service-provider"},next:{title:"Google Cloud Platform (GCP)",permalink:"/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform"}},u=[{value:"Getting started",id:"getting-started",children:[{value:"Connect your AWS account",id:"connect-your-aws-account",children:[]},{value:"Install a new cluster on Qovery",id:"install-a-new-cluster-on-qovery",children:[]},{value:"Deployed AWS components",id:"deployed-aws-components",children:[]},{value:"Remove Qovery from your AWS account",id:"remove-qovery-from-your-aws-account",children:[]},{value:"IAM permissions",id:"iam-permissions",children:[]}]},{value:"Regions",id:"regions",children:[]},{value:"Manually configure VPC subnet",id:"manually-configure-vpc-subnet",children:[]},{value:"Configure routing table",id:"configure-routing-table",children:[]},{value:"How Qovery works on AWS",id:"how-qovery-works-on-aws",children:[{value:"Kubernetes",id:"kubernetes",children:[]},{value:"Managed services",id:"managed-services",children:[]},{value:"Security and compliance",id:"security-and-compliance",children:[]}]},{value:"FAQ",id:"faq",children:[{value:"How to choose a region?",id:"how-to-choose-a-region",children:[]},{value:"I don't find a region that is provided by AWS",id:"i-dont-find-a-region-that-is-provided-by-aws",children:[]},{value:"Migrate between Cloud providers and regions",id:"migrate-between-cloud-providers-and-regions",children:[]}]}],d={rightToc:u};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(c.b)("wrapper",Object(a.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(c.b)(i.a,{type:"info",mdxType:"Alert"},Object(c.b)("p",null,"Please refer to ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/provider/kubernetes/"}),"this page")," if you want to install Qovery on your own Kubernetes cluster (BYOK).")),Object(c.b)("p",null,"Qovery lets you quickly deploy applications to your ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://aws.amazon.com"}),"Amazon Web Services (AWS)")," account. No knowledge needed, and it takes less than 20 minutes to install Qovery on your AWS account."),Object(c.b)("h2",{id:"getting-started"},"Getting started"),Object(c.b)(l.a,{mdxType:"Assumptions"},Object(c.b)("ul",null,Object(c.b)("li",{parentName:"ul"},"You have a ",Object(c.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/interface/"}),"Qovery")," account"),Object(c.b)("li",{parentName:"ul"},"You have created an ",Object(c.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization")),Object(c.b)("li",{parentName:"ul"},"You have an AWS account"))),Object(c.b)("h3",{id:"connect-your-aws-account"},"Connect your AWS account"),Object(c.b)("p",null,"To link your AWS account to Qovery you need to provide an AWS ",Object(c.b)("inlineCode",{parentName:"p"},"access key id")," and ",Object(c.b)("inlineCode",{parentName:"p"},"secret access key")," with the ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#iam-permissions"}),"required IAM permissions"),"."),Object(c.b)(i.a,{type:"info",mdxType:"Alert"},Object(c.b)("p",null,"You can link more than one AWS account. Qovery also support multiple Cloud providers within the same Organization. Meaning, you can balance your workload on different Cloud providers. ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/advanced/"}),"Read more"),".")),Object(c.b)("h4",{id:"create-your-aws-credentials---access-key-id-and-secret-access-key"},"Create your AWS credentials - ",Object(c.b)("inlineCode",{parentName:"h4"},"access key id")," and ",Object(c.b)("inlineCode",{parentName:"h4"},"secret access key")),Object(c.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(c.b)("ol",null,Object(c.b)("li",null,Object(c.b)("p",null,Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.aws.amazon.com"}),"Connect to your AWS console"))),Object(c.b)("li",null,Object(c.b)("p",null,"Go to ",Object(c.b)("inlineCode",{parentName:"p"},"IAM")),Object(c.b)("img",{src:"/img/aws/aws-my-security-credentials.png"})),Object(c.b)("li",null,Object(c.b)("p",null,"Create ",Object(c.b)("inlineCode",{parentName:"p"},"Admins")," group ",Object(c.b)("strong",{parentName:"p"},"without any permissions")),Object(c.b)(i.a,{type:"warning",mdxType:"Alert"},Object(c.b)("p",null,"The default name required by Qovery is Admins. If you want to use another name, you have to change the cluster advanced settings ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cluster-advanced-settings/#iam"}),"aws.iam.admin_group")," BEFORE launching the cluster installation process")),Object(c.b)("img",{src:"/img/aws/aws-create-group-1.jpg"}),Object(c.b)("img",{src:"/img/aws/aws-create-group-2.png"}),Object(c.b)("img",{src:"/img/aws/aws-create-group-3.png"})),Object(c.b)("li",null,Object(c.b)("p",null,"Create one IAM user called ",Object(c.b)("inlineCode",{parentName:"p"},"qovery"),"."),Object(c.b)("img",{src:"/img/aws/aws-create-user-1.jpg"}),Object(c.b)("img",{src:"/img/aws/aws-create-user-2.png"}),Object(c.b)("img",{src:"/img/aws/aws-create-user-3.jpg"}),Object(c.b)("img",{src:"/img/aws/aws-create-user-4.png"})),Object(c.b)("li",null,Object(c.b)("p",null,"Setup",Object(c.b)("a",{href:"/files/qovery-iam-aws.json"}," IAM permissions")," to the ",Object(c.b)("inlineCode",{parentName:"p"},"qovery")," user."),Object(c.b)(i.a,{type:"warning",mdxType:"Alert"},Object(c.b)("a",{href:"/files/qovery-iam-aws.json"},"Download IAM permissions JSON"),Object(c.b)("hr",null),Object(c.b)("p",null,"Or copy it from below:"),Object(c.b)("pre",null,Object(c.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "Statement": [\n {\n "Action": [\n "dynamodb:*",\n "iam:*",\n "ec2:*",\n "autoscaling:*",\n "application-autoscaling:*",\n "elasticloadbalancing:*",\n "ecr:*",\n "ecs:*",\n "eks:*",\n "rds:*",\n "elasticache:*",\n "kms:*",\n "logs:*",\n "cloudwatch:*",\n "cloudtrail:LookupEvents",\n "events:DescribeRule",\n "events:DeleteRule",\n "events:ListRuleNamesByTarget",\n "events:ListTargetsByRule",\n "events:PutRule",\n "events:PutTargets",\n "events:RemoveTargets",\n "es:AddTags",\n "es:RemoveTags",\n "es:ListTags",\n "es:DeleteElasticsearchDomain",\n "es:DescribeElasticsearchDomain",\n "es:CreateElasticsearchDomain",\n "s3:*",\n "tag:GetResources"\n ],\n "Effect": "Allow",\n "Resource": "*"\n }\n ],\n "Version": "2012-10-17"\n}\n'))),Object(c.b)("p",null,Object(c.b)("strong",{parentName:"p"},"Then, follow the arrows in AWS console to create AWS credentials with required IAM permissions:")),Object(c.b)("img",{src:"/img/aws/aws-add-policy-1.jpg"}),Object(c.b)("img",{src:"/img/aws/aws-add-policy-2.png"}),Object(c.b)("img",{src:"/img/aws/aws-add-policy-3.jpg"}),Object(c.b)("img",{src:"/img/aws/aws-add-policy-4.jpg"})),Object(c.b)("li",null,Object(c.b)("p",null,"To create an ",Object(c.b)("inlineCode",{parentName:"p"},"access key id")," and ",Object(c.b)("inlineCode",{parentName:"p"},"secret access key"),", go to the Security Credentials tab of the ",Object(c.b)("inlineCode",{parentName:"p"},"Qovery")," user and press ",Object(c.b)("inlineCode",{parentName:"p"},"Create access key")),Object(c.b)("img",{src:"/img/aws/aws-create-credentials-1.png"}),Object(c.b)("img",{src:"/img/aws/aws-create-credentials-2.png"}),Object(c.b)("img",{src:"/img/aws/aws-create-credentials-3.png"}),Object(c.b)("p",null,"You can now save the ",Object(c.b)("inlineCode",{parentName:"p"},"access key id")," and ",Object(c.b)("inlineCode",{parentName:"p"},"secret access key")),Object(c.b)("img",{src:"/img/aws/aws-create-credentials-4.png"})))),Object(c.b)("p",null,"Well done!! You now have your AWS ",Object(c.b)("inlineCode",{parentName:"p"},"access key id")," and ",Object(c.b)("inlineCode",{parentName:"p"},"secret access key")," and your permissions are setups; It is time to connect Qovery to your AWS account."),Object(c.b)("h3",{id:"install-a-new-cluster-on-qovery"},"Install a new cluster on Qovery"),Object(c.b)("p",null,"You will be able to use the credentials you just generated when creating a cluster via the Qovery console. This cluster will be linked to your Qovery organization.\nFollow ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"this documentation")," to create a new cluster on your organization."),Object(c.b)("h3",{id:"deployed-aws-components"},"Deployed AWS components"),Object(c.b)("img",{src:"/img/aws-deployed-infra.png"}),Object(c.b)("table",null,Object(c.b)("thead",{parentName:"table"},Object(c.b)("tr",{parentName:"thead"},Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Network Services"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Optional"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"A dedicated multi AZ VPC"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Everything Qovery will deploy, will be deployed inside this VPC")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Subnets, routing tables, subnet groups and security groups for RDS (multi AZ)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated network fand security rules for RDS")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Subnets, routing tables, subnet groups and security groups for DocumentDB (multi AZ)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated network fand security rules for DocumentDB")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Subnets, routing tables, subnet groups and security groups for Elasticache (multi AZ)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated network fand security rules for Elasticache")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"An internet gateway for the VPC"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Required to let containers having access to Internet")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated NLB to redirect 443 traffic to Nginx Ingress"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"High Availability network load balancer, pointing to Nginx Ingress inside EKS")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"NAT gateways (multi AZ) + EIP addresses (multi AZ) + subnet groups + routing table"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Useful to get outgoing static IP")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated VPC routes for VPC peering"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Useful to perform VPC peering with others VPC on the same or different account")))),Object(c.b)("table",null,Object(c.b)("thead",{parentName:"table"},Object(c.b)("tr",{parentName:"thead"},Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Kubernetes Services"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Optional"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"A dedicated EKS cluster (multi AZ) for this VPC"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated Kubernetes cluster managed by AWS with nodes (instances type) defined by the customer")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"IAM dedicated user for AWS EBS CSI to access EC2 volumes + a dedicated policy"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Required to allow EKS cluster having access to volume and mount them to containers")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"IAM dedicated user for AWS IAM User Sync + a dedicated policy"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Required to sync desired IAM account to EKS to let them connect directly ot Kubernetes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"IAM dedicated user for a Cluster Autoscaler+ a dedicated policy"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Required to let autoscaler having access to EC2 autoscaling groups")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"IAM dedicated policies for AWS EKS CNI, EC2 container registry + EKS worker nodes"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Required to let EKS having access to container registry and configure the Kubernetes network")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Security group for EKS remote access (dual authentication: TLS + IAM authenticator)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Required to have a secure remote access on the Kubernetes cluster")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Security group for 443 port pointing to Nginx ingress inside EKS"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"External access to web services inside the Kubernetes cluster")))),Object(c.b)("table",null,Object(c.b)("thead",{parentName:"table"},Object(c.b)("tr",{parentName:"thead"},Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Other Services"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Optional"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Cloudwatch log groups for the EKS cluster"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Kubernetes logs, useful for the AWS and EKS support to diagnose an issue")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated S3 bucket for application's logs + a dedicated IAM account"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Application's logs are stored in an KMS encrypted S3 pivate bucket")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated S3 bucket to store the kubeconfig"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Kubernetes Kubeconfig is stored in an KMS encrypted, private and versionned bucket, used by Qovery for application's deployment")))),Object(c.b)("h3",{id:"remove-qovery-from-your-aws-account"},"Remove Qovery from your AWS account"),Object(c.b)(i.a,{type:"warning",mdxType:"Alert"},Object(c.b)("p",null,"Your applications and your data will be deleted.")),Object(c.b)("p",null,"To delete Qovery from your AWS account you must be the owner of the Qovery Organization and you have to delete everything in this order:"),Object(c.b)("ul",null,Object(c.b)("li",{parentName:"ul"},"Environments"),Object(c.b)("li",{parentName:"ul"},"Clusters")),Object(c.b)(i.a,{type:"warning",mdxType:"Alert"},Object(c.b)("p",null,'If you remove the access to your AWS account before deleting all the resources on the Qovery platform, you will have to manually delete them by yourself by following the guide "I don\'t have Qovery access anymore, how could I delete Qovery deployed resources on my AWS account?" in ',Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/troubleshoot/"}),"this section"),".")),Object(c.b)("h3",{id:"iam-permissions"},"IAM permissions"),Object(c.b)("p",null,"Qovery required IAM permissions to create, update and managed the infrastructure."),Object(c.b)("ul",null,Object(c.b)("li",{parentName:"ul"},"IAM is used to create IAM roles"),Object(c.b)("li",{parentName:"ul"},"S3 is used to store our generated configuration files"),Object(c.b)("li",{parentName:"ul"},"Cloudwatch, for creating a group stream for each Kubernetes clusters"),Object(c.b)("li",{parentName:"ul"},"Autoscaling for RDS and autoscaling rules for the Kubernetes cluster"),Object(c.b)("li",{parentName:"ul"},"Elastic load-balancing for ELB / ALB / NLB."),Object(c.b)("li",{parentName:"ul"},"DynamoDB to have a distributed lock on infrastructure deployment."),Object(c.b)("li",{parentName:"ul"},"ECR for managing the container registry, create/update/delete repository."),Object(c.b)("li",{parentName:"ul"},"KMS to load and store keys (RDS, SSH, \u2026)"),Object(c.b)("li",{parentName:"ul"},"EKS to create and update the Kubernetes cluster.")),Object(c.b)("details",null,Object(c.b)("summary",null,"Minimum IAM permission set"),Object(c.b)("blockquote",null,"Last update: 2023-06-08"),Object(c.b)(i.a,{type:"alert",mdxType:"Alert"},Object(c.b)("p",null,"This is purely informative and we strongly recommend you to NOT use this configuration within your IAM permissions since it might not reflect the latest product update. Please use the one provided in the section above.")),Object(c.b)("p",null,"Below you can find the minimum permission set required by Qovery to run and deploy your applications."),Object(c.b)("p",null,"Policies lengths are limited regarding which object they\u2019re attached to but the one Qovery needs represent more than the maximum (~6000 characters)."),Object(c.b)("p",null,"In order to setup it up, you need to create two IAM groups, each one with one of the following policies."),Object(c.b)("p",null,"Then we must create a user added to each of the previously created groups."),Object(c.b)("p",null,"Once it\u2019s done, the user\u2019s access key and secret key can be used in Qovery."),Object(c.b)("pre",null,Object(c.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'\n{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Effect": "Allow",\n "Action": [\n "autoscaling:SuspendProcesses",\n "ec2:AllocateAddress",\n "ec2:AssociateAddress",\n "ec2:AssociateRouteTable",\n "ec2:AttachVolume",\n "ec2:AttachInternetGateway",\n "ec2:AuthorizeSecurityGroupEgress",\n "ec2:AuthorizeSecurityGroupIngress",\n "ec2:CreateInternetGateway",\n "ec2:CreateKeyPair",\n "ec2:CreateLaunchTemplate",\n "ec2:CreateLaunchTemplateVersion",\n "ec2:CreateNatGateway",\n "ec2:CreateRoute",\n "ec2:CreateRouteTable",\n "ec2:CreateSecurityGroup",\n "ec2:CreateSubnet",\n "ec2:CreateTags",\n "ec2:CreateVolume",\n "ec2:CreateVpc",\n "ec2:DeleteInternetGateway",\n "ec2:DeleteKeyPair",\n "ec2:DeleteLaunchTemplate",\n "ec2:DeleteNatGateway",\n "ec2:DeleteRouteTable",\n "ec2:DeleteSecurityGroup",\n "ec2:DeleteSubnet",\n "ec2:DeleteVolume",\n "ec2:DeleteVpc",\n "ec2:DescribeAddresses",\n "ec2:DescribeAvailabilityZones",\n "ec2:DescribeImages",\n "ec2:DescribeInstanceAttribute",\n "ec2:DescribeInstanceCreditSpecifications",\n "ec2:DescribeInstances",\n "ec2:DescribeInstanceTypes",\n "ec2:DescribeInternetGateways",\n "ec2:DescribeKeyPairs",\n "ec2:DescribeLaunchTemplateVersions",\n "ec2:DescribeLaunchTemplates",\n "ec2:DescribeNatGateways",\n "ec2:DescribeNetworkAcls",\n "ec2:DescribeNetworkInterfaces",\n "ec2:DescribeRouteTables",\n "ec2:DescribeSecurityGroupRules",\n "ec2:DescribeSecurityGroups",\n "ec2:DescribeSubnets",\n "ec2:DescribeTags",\n "ec2:DescribeVolumes",\n "ec2:DescribeVpcAttribute",\n "ec2:DescribeVpcClassicLink",\n "ec2:DescribeVpcClassicLinkDnsSupport",\n "ec2:DescribeVpcs",\n "ec2:DetachInternetGateway",\n "ec2:DetachVolume",\n "ec2:DisassociateAddress",\n "ec2:DisassociateRouteTable",\n "ec2:ImportKeyPair",\n "ec2:ModifySubnetAttribute",\n "ec2:ModifyVpcAttribute",\n "ec2:ReleaseAddress",\n "ec2:RevokeSecurityGroupEgress",\n "ec2:RevokeSecurityGroupIngress",\n "ec2:RunInstances",\n "ec2:StopInstances",\n "ec2:TerminateInstances",\n "ecr:BatchCheckLayerAvailability",\n "ecr:BatchGetImage",\n "ecr:CompleteLayerUpload",\n "ecr:CreateRepository",\n "ecr:DeleteRepository",\n "ecr:DescribeImages",\n "ecr:DescribeRepositories",\n "ecr:GetAuthorizationToken",\n "ecr:GetDownloadUrlForLayer",\n "ecr:InitiateLayerUpload",\n "ecr:PutImage",\n "ecr:PutLifecyclePolicy",\n "ecr:TagResource",\n "ecr:UploadLayerPart",\n "eks:CreateAddon",\n "eks:CreateCluster",\n "eks:CreateNodegroup",\n "eks:DeleteAddon",\n "eks:DeleteCluster",\n "eks:DeleteNodegroup",\n "eks:DescribeAddon",\n "eks:DescribeCluster",\n "eks:DescribeNodegroup",\n "eks:DescribeUpdate",\n "eks:ListClusters",\n "eks:ListNodegroups",\n "eks:TagResource",\n "eks:UpdateAddon",\n "eks:UpdateClusterConfig",\n "eks:UpdateClusterVersion",\n "eks:UpdateNodegroupConfig",\n "eks:UpdateNodegroupVersion",\n "elasticache:AddTagsToResource",\n "elasticache:CreateCacheSubnetGroup",\n "elasticache:CreateReplicationGroup",\n "elasticache:DeleteCacheSubnetGroup",\n "elasticache:DeleteReplicationGroup",\n "elasticache:DescribeCacheClusters",\n "elasticache:DescribeCacheSubnetGroups",\n "elasticache:DescribeReplicationGroups",\n "elasticache:ListTagsForResource",\n "elasticloadbalancing:DescribeLoadBalancers",\n "elasticloadbalancing:DescribeTags"\n ],\n "Resource": "*"\n }\n ]\n}\n\n')),Object(c.b)("pre",null,Object(c.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Effect": "Allow",\n "Action": [\n "iam:AddRoleToInstanceProfile",\n "iam:AttachRolePolicy",\n "iam:AttachUserPolicy",\n "iam:CreateAccessKey",\n "iam:CreateInstanceProfile",\n "iam:CreateOpenIDConnectProvider",\n "iam:CreatePolicy",\n "iam:CreateRole",\n "iam:CreateServiceLinkedRole",\n "iam:CreateUser",\n "iam:DeleteAccessKey",\n "iam:DeleteInstanceProfile",\n "iam:DeleteOpenIDConnectProvider",\n "iam:DeletePolicy",\n "iam:DeleteRole",\n "iam:DeleteRolePolicy",\n "iam:DeleteUser",\n "iam:DeleteUserPolicy",\n "iam:DetachRolePolicy",\n "iam:DetachUserPolicy",\n "iam:GetInstanceProfile",\n "iam:GetOpenIDConnectProvider",\n "iam:GetPolicy",\n "iam:GetPolicyVersion",\n "iam:GetRole",\n "iam:GetRolePolicy",\n "iam:GetUser",\n "iam:GetUserPolicy",\n "iam:ListAccessKeys",\n "iam:ListAttachedRolePolicies",\n "iam:ListAttachedUserPolicies",\n "iam:ListGroupsForUser",\n "iam:ListInstanceProfilesForRole",\n "iam:ListPolicyVersions",\n "iam:ListRolePolicies",\n "iam:PassRole",\n "iam:PutRolePolicy",\n "iam:PutUserPolicy",\n "iam:RemoveRoleFromInstanceProfile",\n "iam:TagInstanceProfile",\n "iam:TagOpenIDConnectProvider",\n "iam:TagRole",\n "iam:TagUser",\n "kms:CreateGrant",\n "kms:CreateKey",\n "kms:Decrypt",\n "kms:DescribeKey",\n "kms:GenerateDataKey",\n "kms:GetKeyPolicy",\n "kms:GetKeyRotationStatus",\n "kms:ListResourceTags",\n "kms:PutKeyPolicy",\n "kms:ScheduleKeyDeletion",\n "kms:TagResource",\n "logs:CreateLogGroup",\n "logs:DeleteLogGroup",\n "logs:DescribeLogGroups",\n "logs:ListTagsLogGroup",\n "logs:PutRetentionPolicy",\n "logs:TagLogGroup",\n "rds:AddTagsToResource",\n "rds:CreateDBCluster",\n "rds:CreateDBInstance",\n "rds:CreateDBParameterGroup",\n "rds:CreateDBSubnetGroup",\n "rds:DeleteDBCluster",\n "rds:DeleteDBInstance",\n "rds:DeleteDBParameterGroup",\n "rds:DeleteDBSubnetGroup",\n "rds:DescribeDBClusters",\n "rds:DescribeDBInstances",\n "rds:DescribeDBParameterGroups",\n "rds:DescribeDBParameters",\n "rds:DescribeDBSubnetGroups",\n "rds:DescribeGlobalClusters",\n "rds:ListTagsForResource",\n "rds:ModifyDBInstance",\n "rds:ModifyDBParameterGroup",\n "rds:StartDBCluster",\n "rds:StartDBInstance",\n "rds:StopDBCluster",\n "rds:StopDBInstance",\n "s3:CreateBucket",\n "s3:DeleteBucket",\n "s3:DeleteObject",\n "s3:DeleteObjectVersion",\n "s3:DeleteBucketPolicy",\n "s3:GetAccelerateConfiguration",\n "s3:GetBucketAcl",\n "s3:GetBucketCORS",\n "s3:GetBucketLogging",\n "s3:GetBucketObjectLockConfiguration",\n "s3:GetBucketOwnershipControls",\n "s3:GetBucketPolicy",\n "s3:GetBucketPublicAccessBlock",\n "s3:GetBucketRequestPayment",\n "s3:GetBucketTagging",\n "s3:GetBucketVersioning",\n "s3:GetBucketWebsite",\n "s3:GetEncryptionConfiguration",\n "s3:GetLifecycleConfiguration",\n "s3:GetObject",\n "s3:GetReplicationConfiguration",\n "s3:ListAccessPoints",\n "s3:ListAllMyBuckets",\n "s3:ListBucket",\n "s3:ListBucketMultipartUploads",\n "s3:ListBucketVersions",\n "s3:ListMultiRegionAccessPoints",\n "s3:ListMultipartUploadParts",\n "s3:ListStorageLensConfigurations",\n "s3:PutBucketAcl",\n "s3:PutBucketOwnershipControls",\n "s3:PutBucketPolicy",\n "s3:PutBucketPublicAccessBlock",\n "s3:PutBucketTagging",\n "s3:PutBucketVersioning",\n "s3:PutEncryptionConfiguration",\n "s3:PutLifecycleConfiguration",\n "s3:PutObject",\n "s3:PutObjectRetention",\n "secretsmanager:CreateSecret",\n "secretsmanager:TagResource",\n "sts:GetCallerIdentity"\n ],\n "Resource": "*"\n }\n ]\n}\n'))),Object(c.b)("h2",{id:"regions"},"Regions"),Object(c.b)("p",null,"Qovery supports the following AWS regions:"),Object(c.b)("table",null,Object(c.b)("thead",{parentName:"table"},Object(c.b)("tr",{parentName:"thead"},Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null})),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"name"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"description"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"supported"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddfa\ud83c\uddf8"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"us-west-2"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"US West (Oregon)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddfa\ud83c\uddf8"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"us-east-2"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"US East (Ohio)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddfa\ud83c\uddf8"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"us-east-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"US East (N. Virginia)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddfa\ud83c\uddf8"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"us-west-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"US West (N. California)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"No (Only 2 Availability Zone)")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddff\ud83c\udde6"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"af-south-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Africa (Cape Town)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udded\ud83c\uddf0"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ap-east-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Asia Pacific (Hong Kong)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddee\ud83c\uddf3"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ap-south-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Asia Pacific (Mumbai)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddef\ud83c\uddf5"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ap-northeast-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Asia Pacific (Tokyo)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddf0\ud83c\uddf7"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ap-northeast-2"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Asia Pacific (Seoul)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddef\ud83c\uddf5"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ap-northeast-3"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Asia Pacific (Osaka)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddf8\ud83c\uddec"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ap-southeast-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Asia Pacific (Singapore)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udde6\ud83c\uddfa"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ap-southeast-2"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Asia Pacific (Sydney)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udde8\ud83c\udde6"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ca-central-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Canada (Toronto)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udde8\ud83c\uddf3"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"cn-north-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"China (Beijing)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udde8\ud83c\uddf3"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"cn-northwest-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"China (Ningxia)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udde9\ud83c\uddea"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"eu-central-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Europe (Frankfurt)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddee\ud83c\uddea"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"eu-west-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Europe (Ireland)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"eu-west-2"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Europe (London)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddeb\ud83c\uddf7"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"eu-west-3"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Europe (Paris)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddee\ud83c\uddf9"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"eu-south-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Europe (Milan)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddf8\ud83c\uddea"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"eu-north-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Europe (Stockholm)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udde7\ud83c\udded"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"me-south-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Middle East (Bahrain)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udde7\ud83c\uddf7"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"sa-east-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"South America (S\xe3o Paulo)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")))),Object(c.b)("p",null,"Qovery supports regions where ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://aws.amazon.com/eks"}),"Amazon EKS")," is supported."),Object(c.b)("h2",{id:"manually-configure-vpc-subnet"},"Manually configure VPC subnet"),Object(c.b)("p",null,"VPC subnet is automatically defined by Qovery on cluster creation. However, you may want to choose your own VPC subnet, for example to perform VPC Peering."),Object(c.b)(i.a,{type:"info",mdxType:"Alert"},Object(c.b)("p",null,"If you want to perform VPC Peering with Qovery, please refer to our guide ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"VPC Peering with Qovery")," to be assisted step by step.")),Object(c.b)("p",null,"Have a look at ","[this section]","[docs.using-qovery.configuration.clusters#custom-vpc-subnet]","] to know more on how to set the VPC Subnet."),Object(c.b)("h2",{id:"configure-routing-table"},"Configure routing table"),Object(c.b)("p",null,"You may want to create and edit a network routing table to perform VPC peering. This can be done by accessing to the parameters of a cluster, in the settings of your organization."),Object(c.b)(i.a,{type:"info",mdxType:"Alert"},Object(c.b)("p",null,"If you want to perform VPC Peering with Qovery, please refer to our guide ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"VPC Peering with Qovery")," to be assisted step by step.")),Object(c.b)("p",null,"Have a look at ","[this section]","[docs.using-qovery.configuration.clusters#network]","] to know more on how to set the routing table."),Object(c.b)("h2",{id:"how-qovery-works-on-aws"},"How Qovery works on AWS"),Object(c.b)("p",null,"Qovery is an abstraction layer on top of AWS and Kubernetes. Qovery manages the configuration of AWS account, and helps you to deploy production ready apps in seconds.\nTo make it works, Qovery rely on Kubernetes for stateless apps (containers), and AWS for stateful apps (databases, storage...)."),Object(c.b)("p",null,Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/getting-started/how-qovery-works/"}),"Read more")," on how Qovery works behind the scene."),Object(c.b)("h3",{id:"kubernetes"},"Kubernetes"),Object(c.b)("p",null,"The first time you set up your AWS account, Qovery creates a Kubernetes cluster in your chosen region. Qovery managed it for you - no action required. It takes ~15 minutes to configure and bootstrap a Kubernetes cluster. Once bootstrapped, your Kubernetes cluster runs the Qovery app and is ready to deploy your applications."),Object(c.b)("h3",{id:"managed-services"},"Managed services"),Object(c.b)("p",null,"AWS provides managed services for ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/postgresql/"}),"PostgreSQL"),", ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/mysql/"}),"MySQL"),", ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/redis/"}),"Redis"),", ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/mongodb/"}),"MongoDB"),". Qovery gives you access to those services when you set the ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/deployment-rule/#environment-deployment-rules"}),"environment mode")," to ",Object(c.b)("inlineCode",{parentName:"p"},"Production"),". In ",Object(c.b)("inlineCode",{parentName:"p"},"Development")," mode, Qovery provides containers equivalent, which is cheaper and faster to start."),Object(c.b)("h3",{id:"security-and-compliance"},"Security and compliance"),Object(c.b)("p",null,"Qovery runs your Kubernetes cluster and is autonomous to manage your applications, which means:"),Object(c.b)("ul",null,Object(c.b)("li",{parentName:"ul"},"Your configuration are stored on your AWS account."),Object(c.b)("li",{parentName:"ul"},"Your configuration is encrypted on your AWS account."),Object(c.b)("li",{parentName:"ul"},"Qovery can't access to your data."),Object(c.b)("li",{parentName:"ul"},"Suppose Qovery stops to run, your applications are not impacted.")),Object(c.b)("h2",{id:"faq"},"FAQ"),Object(c.b)("h3",{id:"how-to-choose-a-region"},"How to choose a region?"),Object(c.b)("p",null,"Different datacenters are located in different geographic areas, and you may want to keep your site physically close to the bulk of your user base for reduced latency."),Object(c.b)("h3",{id:"i-dont-find-a-region-that-is-provided-by-aws"},"I don't find a region that is provided by AWS"),Object(c.b)("p",null,"We are probably testing the support of this region, please ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/contact"}),"contact us")," to know what's the status"),Object(c.b)("h3",{id:"migrate-between-cloud-providers-and-regions"},"Migrate between Cloud providers and regions"),Object(c.b)("p",null,"Today, you can't migrate an environment from one region to another after it has been created. Vote ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://roadmap.qovery.com/"}),"here")," if you need this feature."))}p.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),b=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},u=function(e){var t=b(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},p=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,c=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=b(n),p=a,m=u["".concat(o,".").concat(p)]||u[p]||d[p]||c;return n?r.a.createElement(m,i({ref:t},s,{components:n})):r.a.createElement(m,i({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var c=n.length,o=new Array(c);o[0]=p;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:a,o[1]=i;for(var s=2;s1?arguments[1]:void 0,n),l=o>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>i;)t[i++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,c=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(c)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),c=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(c.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var a=n(432),r=n(51);function c(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),c=t.length>0?t.join("="):void 0;c=void 0===c?null:decodeURIComponent(c),n(decodeURIComponent(r),c,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[c(t,e),"[",a,"]"].join(""):[c(t,e),"[",c(a,e),"]=",c(n,e)].join("")};case"bracket":return function(t,n){return null===n?c(t,e):[c(t,e),"[]=",c(n,e)].join("")};default:return function(t,n){return null===n?c(t,e):[c(t,e),"=",c(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return c(a,t);if(Array.isArray(r)){var o=[];return r.slice().forEach((function(e){void 0!==e&&o.push(n(a,e,o.length))})),o.join("&")}return c(a,t)+"="+c(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),c=(n(420),n(428)),o=n.n(c);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,c=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+o.a.stringify(l),b=Object(a.useState)(null),u=b[0],d=b[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!c&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 43a5f55b.5bcdf48c.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[77],{229:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),c=(n(0),n(425)),o=n(434),i=n(424),l=n(429),s={last_modified_on:"2023-11-28",title:"Amazon Web Services (AWS)",description:"Learn how to configure and plug your Amazon Web Services (AWS) account"},b={id:"using-qovery/configuration/cloud-service-provider/amazon-web-services",title:"Amazon Web Services (AWS)",description:"Learn how to configure and plug your Amazon Web Services (AWS) account",source:"@site/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services.md",permalink:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services",sidebar:"docs",previous:{title:"Cloud Service Provider",permalink:"/docs/using-qovery/configuration/cloud-service-provider"},next:{title:"Google Cloud Platform (GCP)",permalink:"/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform"}},u=[{value:"Getting started",id:"getting-started",children:[{value:"Connect your AWS account",id:"connect-your-aws-account",children:[]},{value:"Install a new cluster on Qovery",id:"install-a-new-cluster-on-qovery",children:[]},{value:"Deployed AWS components",id:"deployed-aws-components",children:[]},{value:"Remove Qovery from your AWS account",id:"remove-qovery-from-your-aws-account",children:[]},{value:"IAM permissions",id:"iam-permissions",children:[]}]},{value:"Regions",id:"regions",children:[]},{value:"Manually configure VPC subnet",id:"manually-configure-vpc-subnet",children:[]},{value:"Configure routing table",id:"configure-routing-table",children:[]},{value:"How Qovery works on AWS",id:"how-qovery-works-on-aws",children:[{value:"Kubernetes",id:"kubernetes",children:[]},{value:"Managed services",id:"managed-services",children:[]},{value:"Security and compliance",id:"security-and-compliance",children:[]}]},{value:"FAQ",id:"faq",children:[{value:"How to choose a region?",id:"how-to-choose-a-region",children:[]},{value:"I don't find a region that is provided by AWS",id:"i-dont-find-a-region-that-is-provided-by-aws",children:[]},{value:"Migrate between Cloud providers and regions",id:"migrate-between-cloud-providers-and-regions",children:[]}]}],d={rightToc:u};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(c.b)("wrapper",Object(a.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(c.b)(i.a,{type:"info",mdxType:"Alert"},Object(c.b)("p",null,"Please refer to ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/provider/kubernetes/"}),"this page")," if you want to install Qovery on your own Kubernetes cluster (BYOK).")),Object(c.b)("p",null,"Qovery lets you quickly deploy applications to your ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://aws.amazon.com"}),"Amazon Web Services (AWS)")," account. No knowledge needed, and it takes less than 20 minutes to install Qovery on your AWS account."),Object(c.b)("h2",{id:"getting-started"},"Getting started"),Object(c.b)(l.a,{mdxType:"Assumptions"},Object(c.b)("ul",null,Object(c.b)("li",{parentName:"ul"},"You have a ",Object(c.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/interface/"}),"Qovery")," account"),Object(c.b)("li",{parentName:"ul"},"You have created an ",Object(c.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization")),Object(c.b)("li",{parentName:"ul"},"You have an AWS account"))),Object(c.b)("h3",{id:"connect-your-aws-account"},"Connect your AWS account"),Object(c.b)("p",null,"To link your AWS account to Qovery you need to provide an AWS ",Object(c.b)("inlineCode",{parentName:"p"},"access key id")," and ",Object(c.b)("inlineCode",{parentName:"p"},"secret access key")," with the ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#iam-permissions"}),"required IAM permissions"),"."),Object(c.b)(i.a,{type:"info",mdxType:"Alert"},Object(c.b)("p",null,"You can link more than one AWS account. Qovery also support multiple Cloud providers within the same Organization. Meaning, you can balance your workload on different Cloud providers. ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/advanced/"}),"Read more"),".")),Object(c.b)("h4",{id:"create-your-aws-credentials---access-key-id-and-secret-access-key"},"Create your AWS credentials - ",Object(c.b)("inlineCode",{parentName:"h4"},"access key id")," and ",Object(c.b)("inlineCode",{parentName:"h4"},"secret access key")),Object(c.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(c.b)("ol",null,Object(c.b)("li",null,Object(c.b)("p",null,Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.aws.amazon.com"}),"Connect to your AWS console"))),Object(c.b)("li",null,Object(c.b)("p",null,"Go to ",Object(c.b)("inlineCode",{parentName:"p"},"IAM")),Object(c.b)("img",{src:"/img/aws/aws-my-security-credentials.png"})),Object(c.b)("li",null,Object(c.b)("p",null,"Create ",Object(c.b)("inlineCode",{parentName:"p"},"Admins")," group ",Object(c.b)("strong",{parentName:"p"},"without any permissions")),Object(c.b)(i.a,{type:"warning",mdxType:"Alert"},Object(c.b)("p",null,"The default name required by Qovery is Admins. If you want to use another name, you have to change the cluster advanced settings ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cluster-advanced-settings/#iam"}),"aws.iam.admin_group")," BEFORE launching the cluster installation process")),Object(c.b)("img",{src:"/img/aws/aws-create-group-1.jpg"}),Object(c.b)("img",{src:"/img/aws/aws-create-group-2.png"}),Object(c.b)("img",{src:"/img/aws/aws-create-group-3.png"})),Object(c.b)("li",null,Object(c.b)("p",null,"Create one IAM user called ",Object(c.b)("inlineCode",{parentName:"p"},"qovery"),"."),Object(c.b)("img",{src:"/img/aws/aws-create-user-1.jpg"}),Object(c.b)("img",{src:"/img/aws/aws-create-user-2.png"}),Object(c.b)("img",{src:"/img/aws/aws-create-user-3.jpg"}),Object(c.b)("img",{src:"/img/aws/aws-create-user-4.png"})),Object(c.b)("li",null,Object(c.b)("p",null,"Setup",Object(c.b)("a",{href:"/files/qovery-iam-aws.json"}," IAM permissions")," to the ",Object(c.b)("inlineCode",{parentName:"p"},"qovery")," user."),Object(c.b)(i.a,{type:"warning",mdxType:"Alert"},Object(c.b)("a",{href:"/files/qovery-iam-aws.json"},"Download IAM permissions JSON"),Object(c.b)("hr",null),Object(c.b)("p",null,"Or copy it from below:"),Object(c.b)("pre",null,Object(c.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "Statement": [\n {\n "Action": [\n "dynamodb:*",\n "iam:*",\n "ec2:*",\n "autoscaling:*",\n "application-autoscaling:*",\n "elasticloadbalancing:*",\n "ecr:*",\n "ecs:*",\n "eks:*",\n "rds:*",\n "elasticache:*",\n "kms:*",\n "logs:*",\n "cloudwatch:*",\n "cloudtrail:LookupEvents",\n "events:DescribeRule",\n "events:DeleteRule",\n "events:ListRuleNamesByTarget",\n "events:ListTargetsByRule",\n "events:PutRule",\n "events:PutTargets",\n "events:RemoveTargets",\n "es:AddTags",\n "es:RemoveTags",\n "es:ListTags",\n "es:DeleteElasticsearchDomain",\n "es:DescribeElasticsearchDomain",\n "es:CreateElasticsearchDomain",\n "s3:*",\n "tag:GetResources"\n ],\n "Effect": "Allow",\n "Resource": "*"\n }\n ],\n "Version": "2012-10-17"\n}\n'))),Object(c.b)("p",null,Object(c.b)("strong",{parentName:"p"},"Then, follow the arrows in AWS console to create AWS credentials with required IAM permissions:")),Object(c.b)("img",{src:"/img/aws/aws-add-policy-1.jpg"}),Object(c.b)("img",{src:"/img/aws/aws-add-policy-2.png"}),Object(c.b)("img",{src:"/img/aws/aws-add-policy-3.jpg"}),Object(c.b)("img",{src:"/img/aws/aws-add-policy-4.jpg"})),Object(c.b)("li",null,Object(c.b)("p",null,"To create an ",Object(c.b)("inlineCode",{parentName:"p"},"access key id")," and ",Object(c.b)("inlineCode",{parentName:"p"},"secret access key"),", go to the Security Credentials tab of the ",Object(c.b)("inlineCode",{parentName:"p"},"Qovery")," user and press ",Object(c.b)("inlineCode",{parentName:"p"},"Create access key")),Object(c.b)("img",{src:"/img/aws/aws-create-credentials-1.png"}),Object(c.b)("img",{src:"/img/aws/aws-create-credentials-2.png"}),Object(c.b)("img",{src:"/img/aws/aws-create-credentials-3.png"}),Object(c.b)("p",null,"You can now save the ",Object(c.b)("inlineCode",{parentName:"p"},"access key id")," and ",Object(c.b)("inlineCode",{parentName:"p"},"secret access key")),Object(c.b)("img",{src:"/img/aws/aws-create-credentials-4.png"})))),Object(c.b)("p",null,"Well done!! You now have your AWS ",Object(c.b)("inlineCode",{parentName:"p"},"access key id")," and ",Object(c.b)("inlineCode",{parentName:"p"},"secret access key")," and your permissions are setups; It is time to connect Qovery to your AWS account."),Object(c.b)("h3",{id:"install-a-new-cluster-on-qovery"},"Install a new cluster on Qovery"),Object(c.b)("p",null,"You will be able to use the credentials you just generated when creating a cluster via the Qovery console. This cluster will be linked to your Qovery organization.\nFollow ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"this documentation")," to create a new cluster on your organization."),Object(c.b)("h3",{id:"deployed-aws-components"},"Deployed AWS components"),Object(c.b)("img",{src:"/img/aws-deployed-infra.png"}),Object(c.b)("table",null,Object(c.b)("thead",{parentName:"table"},Object(c.b)("tr",{parentName:"thead"},Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Network Services"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Optional"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"A dedicated multi AZ VPC"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Everything Qovery will deploy, will be deployed inside this VPC")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Subnets, routing tables, subnet groups and security groups for RDS (multi AZ)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated network fand security rules for RDS")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Subnets, routing tables, subnet groups and security groups for DocumentDB (multi AZ)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated network fand security rules for DocumentDB")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Subnets, routing tables, subnet groups and security groups for Elasticache (multi AZ)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated network fand security rules for Elasticache")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"An internet gateway for the VPC"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Required to let containers having access to Internet")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated NLB to redirect 443 traffic to Nginx Ingress"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"High Availability network load balancer, pointing to Nginx Ingress inside EKS")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"NAT gateways (multi AZ) + EIP addresses (multi AZ) + subnet groups + routing table"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Useful to get outgoing static IP")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated VPC routes for VPC peering"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Useful to perform VPC peering with others VPC on the same or different account")))),Object(c.b)("table",null,Object(c.b)("thead",{parentName:"table"},Object(c.b)("tr",{parentName:"thead"},Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Kubernetes Services"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Optional"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"A dedicated EKS cluster (multi AZ) for this VPC"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated Kubernetes cluster managed by AWS with nodes (instances type) defined by the customer")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"IAM dedicated user for AWS EBS CSI to access EC2 volumes + a dedicated policy"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Required to allow EKS cluster having access to volume and mount them to containers")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"IAM dedicated user for AWS IAM User Sync + a dedicated policy"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Required to sync desired IAM account to EKS to let them connect directly ot Kubernetes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"IAM dedicated user for a Cluster Autoscaler+ a dedicated policy"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Required to let autoscaler having access to EC2 autoscaling groups")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"IAM dedicated policies for AWS EKS CNI, EC2 container registry + EKS worker nodes"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Required to let EKS having access to container registry and configure the Kubernetes network")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Security group for EKS remote access (dual authentication: TLS + IAM authenticator)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Required to have a secure remote access on the Kubernetes cluster")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Security group for 443 port pointing to Nginx ingress inside EKS"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"External access to web services inside the Kubernetes cluster")))),Object(c.b)("table",null,Object(c.b)("thead",{parentName:"table"},Object(c.b)("tr",{parentName:"thead"},Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Other Services"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Optional"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Cloudwatch log groups for the EKS cluster"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Kubernetes logs, useful for the AWS and EKS support to diagnose an issue")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated S3 bucket for application's logs + a dedicated IAM account"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Application's logs are stored in an KMS encrypted S3 pivate bucket")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Dedicated S3 bucket to store the kubeconfig"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Kubernetes Kubeconfig is stored in an KMS encrypted, private and versionned bucket, used by Qovery for application's deployment")))),Object(c.b)("h3",{id:"remove-qovery-from-your-aws-account"},"Remove Qovery from your AWS account"),Object(c.b)(i.a,{type:"warning",mdxType:"Alert"},Object(c.b)("p",null,"Your applications and your data will be deleted.")),Object(c.b)("p",null,"To delete Qovery from your AWS account you must be the owner of the Qovery Organization and you have to delete everything in this order:"),Object(c.b)("ul",null,Object(c.b)("li",{parentName:"ul"},"Environments"),Object(c.b)("li",{parentName:"ul"},"Clusters")),Object(c.b)(i.a,{type:"warning",mdxType:"Alert"},Object(c.b)("p",null,'If you remove the access to your AWS account before deleting all the resources on the Qovery platform, you will have to manually delete them by yourself by following the guide "I don\'t have Qovery access anymore, how could I delete Qovery deployed resources on my AWS account?" in ',Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/troubleshoot/"}),"this section"),".")),Object(c.b)("h3",{id:"iam-permissions"},"IAM permissions"),Object(c.b)("p",null,"Qovery required IAM permissions to create, update and managed the infrastructure."),Object(c.b)("ul",null,Object(c.b)("li",{parentName:"ul"},"IAM is used to create IAM roles"),Object(c.b)("li",{parentName:"ul"},"S3 is used to store our generated configuration files"),Object(c.b)("li",{parentName:"ul"},"Cloudwatch, for creating a group stream for each Kubernetes clusters"),Object(c.b)("li",{parentName:"ul"},"Autoscaling for RDS and autoscaling rules for the Kubernetes cluster"),Object(c.b)("li",{parentName:"ul"},"Elastic load-balancing for ELB / ALB / NLB."),Object(c.b)("li",{parentName:"ul"},"DynamoDB to have a distributed lock on infrastructure deployment."),Object(c.b)("li",{parentName:"ul"},"ECR for managing the container registry, create/update/delete repository."),Object(c.b)("li",{parentName:"ul"},"KMS to load and store keys (RDS, SSH, \u2026)"),Object(c.b)("li",{parentName:"ul"},"EKS to create and update the Kubernetes cluster.")),Object(c.b)("details",null,Object(c.b)("summary",null,"Minimum IAM permission set"),Object(c.b)("blockquote",null,"Last update: 2023-06-08"),Object(c.b)(i.a,{type:"alert",mdxType:"Alert"},Object(c.b)("p",null,"This is purely informative and we strongly recommend you to NOT use this configuration within your IAM permissions since it might not reflect the latest product update. Please use the one provided in the section above.")),Object(c.b)("p",null,"Below you can find the minimum permission set required by Qovery to run and deploy your applications."),Object(c.b)("p",null,"Policies lengths are limited regarding which object they\u2019re attached to but the one Qovery needs represent more than the maximum (~6000 characters)."),Object(c.b)("p",null,"In order to setup it up, you need to create two IAM groups, each one with one of the following policies."),Object(c.b)("p",null,"Then we must create a user added to each of the previously created groups."),Object(c.b)("p",null,"Once it\u2019s done, the user\u2019s access key and secret key can be used in Qovery."),Object(c.b)("pre",null,Object(c.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'\n{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Effect": "Allow",\n "Action": [\n "autoscaling:SuspendProcesses",\n "ec2:AllocateAddress",\n "ec2:AssociateAddress",\n "ec2:AssociateRouteTable",\n "ec2:AttachVolume",\n "ec2:AttachInternetGateway",\n "ec2:AuthorizeSecurityGroupEgress",\n "ec2:AuthorizeSecurityGroupIngress",\n "ec2:CreateInternetGateway",\n "ec2:CreateKeyPair",\n "ec2:CreateLaunchTemplate",\n "ec2:CreateLaunchTemplateVersion",\n "ec2:CreateNatGateway",\n "ec2:CreateRoute",\n "ec2:CreateRouteTable",\n "ec2:CreateSecurityGroup",\n "ec2:CreateSubnet",\n "ec2:CreateTags",\n "ec2:CreateVolume",\n "ec2:CreateVpc",\n "ec2:DeleteInternetGateway",\n "ec2:DeleteKeyPair",\n "ec2:DeleteLaunchTemplate",\n "ec2:DeleteNatGateway",\n "ec2:DeleteRouteTable",\n "ec2:DeleteSecurityGroup",\n "ec2:DeleteSubnet",\n "ec2:DeleteVolume",\n "ec2:DeleteVpc",\n "ec2:DescribeAddresses",\n "ec2:DescribeAvailabilityZones",\n "ec2:DescribeImages",\n "ec2:DescribeInstanceAttribute",\n "ec2:DescribeInstanceCreditSpecifications",\n "ec2:DescribeInstances",\n "ec2:DescribeInstanceTypes",\n "ec2:DescribeInternetGateways",\n "ec2:DescribeKeyPairs",\n "ec2:DescribeLaunchTemplateVersions",\n "ec2:DescribeLaunchTemplates",\n "ec2:DescribeNatGateways",\n "ec2:DescribeNetworkAcls",\n "ec2:DescribeNetworkInterfaces",\n "ec2:DescribeRouteTables",\n "ec2:DescribeSecurityGroupRules",\n "ec2:DescribeSecurityGroups",\n "ec2:DescribeSubnets",\n "ec2:DescribeTags",\n "ec2:DescribeVolumes",\n "ec2:DescribeVpcAttribute",\n "ec2:DescribeVpcClassicLink",\n "ec2:DescribeVpcClassicLinkDnsSupport",\n "ec2:DescribeVpcs",\n "ec2:DetachInternetGateway",\n "ec2:DetachVolume",\n "ec2:DisassociateAddress",\n "ec2:DisassociateRouteTable",\n "ec2:ImportKeyPair",\n "ec2:ModifySubnetAttribute",\n "ec2:ModifyVpcAttribute",\n "ec2:ReleaseAddress",\n "ec2:RevokeSecurityGroupEgress",\n "ec2:RevokeSecurityGroupIngress",\n "ec2:RunInstances",\n "ec2:StopInstances",\n "ec2:TerminateInstances",\n "ecr:BatchCheckLayerAvailability",\n "ecr:BatchGetImage",\n "ecr:CompleteLayerUpload",\n "ecr:CreateRepository",\n "ecr:DeleteRepository",\n "ecr:DescribeImages",\n "ecr:DescribeRepositories",\n "ecr:GetAuthorizationToken",\n "ecr:GetDownloadUrlForLayer",\n "ecr:InitiateLayerUpload",\n "ecr:PutImage",\n "ecr:PutLifecyclePolicy",\n "ecr:TagResource",\n "ecr:UploadLayerPart",\n "eks:CreateAddon",\n "eks:CreateCluster",\n "eks:CreateNodegroup",\n "eks:DeleteAddon",\n "eks:DeleteCluster",\n "eks:DeleteNodegroup",\n "eks:DescribeAddon",\n "eks:DescribeCluster",\n "eks:DescribeNodegroup",\n "eks:DescribeUpdate",\n "eks:ListClusters",\n "eks:ListNodegroups",\n "eks:TagResource",\n "eks:UpdateAddon",\n "eks:UpdateClusterConfig",\n "eks:UpdateClusterVersion",\n "eks:UpdateNodegroupConfig",\n "eks:UpdateNodegroupVersion",\n "elasticache:AddTagsToResource",\n "elasticache:CreateCacheSubnetGroup",\n "elasticache:CreateReplicationGroup",\n "elasticache:DeleteCacheSubnetGroup",\n "elasticache:DeleteReplicationGroup",\n "elasticache:DescribeCacheClusters",\n "elasticache:DescribeCacheSubnetGroups",\n "elasticache:DescribeReplicationGroups",\n "elasticache:ListTagsForResource",\n "elasticloadbalancing:DescribeLoadBalancers",\n "elasticloadbalancing:DescribeTags"\n ],\n "Resource": "*"\n }\n ]\n}\n\n')),Object(c.b)("pre",null,Object(c.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Effect": "Allow",\n "Action": [\n "iam:AddRoleToInstanceProfile",\n "iam:AttachRolePolicy",\n "iam:AttachUserPolicy",\n "iam:CreateAccessKey",\n "iam:CreateInstanceProfile",\n "iam:CreateOpenIDConnectProvider",\n "iam:CreatePolicy",\n "iam:CreateRole",\n "iam:CreateServiceLinkedRole",\n "iam:CreateUser",\n "iam:DeleteAccessKey",\n "iam:DeleteInstanceProfile",\n "iam:DeleteOpenIDConnectProvider",\n "iam:DeletePolicy",\n "iam:DeleteRole",\n "iam:DeleteRolePolicy",\n "iam:DeleteUser",\n "iam:DeleteUserPolicy",\n "iam:DetachRolePolicy",\n "iam:DetachUserPolicy",\n "iam:GetInstanceProfile",\n "iam:GetOpenIDConnectProvider",\n "iam:GetPolicy",\n "iam:GetPolicyVersion",\n "iam:GetRole",\n "iam:GetRolePolicy",\n "iam:GetUser",\n "iam:GetUserPolicy",\n "iam:ListAccessKeys",\n "iam:ListAttachedRolePolicies",\n "iam:ListAttachedUserPolicies",\n "iam:ListGroupsForUser",\n "iam:ListInstanceProfilesForRole",\n "iam:ListPolicyVersions",\n "iam:ListRolePolicies",\n "iam:PassRole",\n "iam:PutRolePolicy",\n "iam:PutUserPolicy",\n "iam:RemoveRoleFromInstanceProfile",\n "iam:TagInstanceProfile",\n "iam:TagOpenIDConnectProvider",\n "iam:TagRole",\n "iam:TagUser",\n "kms:CreateGrant",\n "kms:CreateKey",\n "kms:Decrypt",\n "kms:DescribeKey",\n "kms:GenerateDataKey",\n "kms:GetKeyPolicy",\n "kms:GetKeyRotationStatus",\n "kms:ListResourceTags",\n "kms:PutKeyPolicy",\n "kms:ScheduleKeyDeletion",\n "kms:TagResource",\n "logs:CreateLogGroup",\n "logs:DeleteLogGroup",\n "logs:DescribeLogGroups",\n "logs:ListTagsLogGroup",\n "logs:PutRetentionPolicy",\n "logs:TagLogGroup",\n "rds:AddTagsToResource",\n "rds:CreateDBCluster",\n "rds:CreateDBInstance",\n "rds:CreateDBParameterGroup",\n "rds:CreateDBSubnetGroup",\n "rds:DeleteDBCluster",\n "rds:DeleteDBInstance",\n "rds:DeleteDBParameterGroup",\n "rds:DeleteDBSubnetGroup",\n "rds:DescribeDBClusters",\n "rds:DescribeDBInstances",\n "rds:DescribeDBParameterGroups",\n "rds:DescribeDBParameters",\n "rds:DescribeDBSubnetGroups",\n "rds:DescribeGlobalClusters",\n "rds:ListTagsForResource",\n "rds:ModifyDBInstance",\n "rds:ModifyDBParameterGroup",\n "rds:StartDBCluster",\n "rds:StartDBInstance",\n "rds:StopDBCluster",\n "rds:StopDBInstance",\n "s3:CreateBucket",\n "s3:DeleteBucket",\n "s3:DeleteObject",\n "s3:DeleteObjectVersion",\n "s3:DeleteBucketPolicy",\n "s3:GetAccelerateConfiguration",\n "s3:GetBucketAcl",\n "s3:GetBucketCORS",\n "s3:GetBucketLogging",\n "s3:GetBucketObjectLockConfiguration",\n "s3:GetBucketOwnershipControls",\n "s3:GetBucketPolicy",\n "s3:GetBucketPublicAccessBlock",\n "s3:GetBucketRequestPayment",\n "s3:GetBucketTagging",\n "s3:GetBucketVersioning",\n "s3:GetBucketWebsite",\n "s3:GetEncryptionConfiguration",\n "s3:GetLifecycleConfiguration",\n "s3:GetObject",\n "s3:GetReplicationConfiguration",\n "s3:ListAccessPoints",\n "s3:ListAllMyBuckets",\n "s3:ListBucket",\n "s3:ListBucketMultipartUploads",\n "s3:ListBucketVersions",\n "s3:ListMultiRegionAccessPoints",\n "s3:ListMultipartUploadParts",\n "s3:ListStorageLensConfigurations",\n "s3:PutBucketAcl",\n "s3:PutBucketOwnershipControls",\n "s3:PutBucketPolicy",\n "s3:PutBucketPublicAccessBlock",\n "s3:PutBucketTagging",\n "s3:PutBucketVersioning",\n "s3:PutEncryptionConfiguration",\n "s3:PutLifecycleConfiguration",\n "s3:PutObject",\n "s3:PutObjectRetention",\n "secretsmanager:CreateSecret",\n "secretsmanager:TagResource",\n "sts:GetCallerIdentity"\n ],\n "Resource": "*"\n }\n ]\n}\n'))),Object(c.b)("h2",{id:"regions"},"Regions"),Object(c.b)("p",null,"Qovery supports the following AWS regions:"),Object(c.b)("table",null,Object(c.b)("thead",{parentName:"table"},Object(c.b)("tr",{parentName:"thead"},Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null})),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"name"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"description"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"supported"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddfa\ud83c\uddf8"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"us-west-2"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"US West (Oregon)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddfa\ud83c\uddf8"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"us-east-2"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"US East (Ohio)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddfa\ud83c\uddf8"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"us-east-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"US East (N. Virginia)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddfa\ud83c\uddf8"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"us-west-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"US West (N. California)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"No (Only 2 Availability Zone)")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddff\ud83c\udde6"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"af-south-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Africa (Cape Town)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udded\ud83c\uddf0"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ap-east-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Asia Pacific (Hong Kong)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddee\ud83c\uddf3"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ap-south-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Asia Pacific (Mumbai)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddef\ud83c\uddf5"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ap-northeast-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Asia Pacific (Tokyo)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddf0\ud83c\uddf7"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ap-northeast-2"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Asia Pacific (Seoul)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddef\ud83c\uddf5"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ap-northeast-3"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Asia Pacific (Osaka)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddf8\ud83c\uddec"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ap-southeast-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Asia Pacific (Singapore)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udde6\ud83c\uddfa"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ap-southeast-2"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Asia Pacific (Sydney)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udde8\ud83c\udde6"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ca-central-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Canada (Toronto)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udde8\ud83c\uddf3"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"cn-north-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"China (Beijing)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udde8\ud83c\uddf3"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"cn-northwest-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"China (Ningxia)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udde9\ud83c\uddea"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"eu-central-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Europe (Frankfurt)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddee\ud83c\uddea"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"eu-west-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Europe (Ireland)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"eu-west-2"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Europe (London)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddeb\ud83c\uddf7"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"eu-west-3"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Europe (Paris)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddee\ud83c\uddf9"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"eu-south-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Europe (Milan)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddf8\ud83c\uddea"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"eu-north-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Europe (Stockholm)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udde7\ud83c\udded"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"me-south-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Middle East (Bahrain)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\udde7\ud83c\uddf7"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"sa-east-1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"South America (S\xe3o Paulo)"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes")))),Object(c.b)("p",null,"Qovery supports regions where ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://aws.amazon.com/eks"}),"Amazon EKS")," is supported."),Object(c.b)("h2",{id:"manually-configure-vpc-subnet"},"Manually configure VPC subnet"),Object(c.b)("p",null,"VPC subnet is automatically defined by Qovery on cluster creation. However, you may want to choose your own VPC subnet, for example to perform VPC Peering."),Object(c.b)(i.a,{type:"info",mdxType:"Alert"},Object(c.b)("p",null,"If you want to perform VPC Peering with Qovery, please refer to our guide ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"VPC Peering with Qovery")," to be assisted step by step.")),Object(c.b)("p",null,"Have a look at ","[this section]","[docs.using-qovery.configuration.clusters#custom-vpc-subnet]","] to know more on how to set the VPC Subnet."),Object(c.b)("h2",{id:"configure-routing-table"},"Configure routing table"),Object(c.b)("p",null,"You may want to create and edit a network routing table to perform VPC peering. This can be done by accessing to the parameters of a cluster, in the settings of your organization."),Object(c.b)(i.a,{type:"info",mdxType:"Alert"},Object(c.b)("p",null,"If you want to perform VPC Peering with Qovery, please refer to our guide ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"VPC Peering with Qovery")," to be assisted step by step.")),Object(c.b)("p",null,"Have a look at ","[this section]","[docs.using-qovery.configuration.clusters#network]","] to know more on how to set the routing table."),Object(c.b)("h2",{id:"how-qovery-works-on-aws"},"How Qovery works on AWS"),Object(c.b)("p",null,"Qovery is an abstraction layer on top of AWS and Kubernetes. Qovery manages the configuration of AWS account, and helps you to deploy production ready apps in seconds.\nTo make it works, Qovery rely on Kubernetes for stateless apps (containers), and AWS for stateful apps (databases, storage...)."),Object(c.b)("p",null,Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/getting-started/how-qovery-works/"}),"Read more")," on how Qovery works behind the scene."),Object(c.b)("h3",{id:"kubernetes"},"Kubernetes"),Object(c.b)("p",null,"The first time you set up your AWS account, Qovery creates a Kubernetes cluster in your chosen region. Qovery managed it for you - no action required. It takes ~15 minutes to configure and bootstrap a Kubernetes cluster. Once bootstrapped, your Kubernetes cluster runs the Qovery app and is ready to deploy your applications."),Object(c.b)("h3",{id:"managed-services"},"Managed services"),Object(c.b)("p",null,"AWS provides managed services for ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/postgresql/"}),"PostgreSQL"),", ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/mysql/"}),"MySQL"),", ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/redis/"}),"Redis"),", ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/mongodb/"}),"MongoDB"),". Qovery gives you access to those services when you set the ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/deployment-rule/#environment-deployment-rules"}),"environment mode")," to ",Object(c.b)("inlineCode",{parentName:"p"},"Production"),". In ",Object(c.b)("inlineCode",{parentName:"p"},"Development")," mode, Qovery provides containers equivalent, which is cheaper and faster to start."),Object(c.b)("h3",{id:"security-and-compliance"},"Security and compliance"),Object(c.b)("p",null,"Qovery runs your Kubernetes cluster and is autonomous to manage your applications, which means:"),Object(c.b)("ul",null,Object(c.b)("li",{parentName:"ul"},"Your configuration are stored on your AWS account."),Object(c.b)("li",{parentName:"ul"},"Your configuration is encrypted on your AWS account."),Object(c.b)("li",{parentName:"ul"},"Qovery can't access to your data."),Object(c.b)("li",{parentName:"ul"},"Suppose Qovery stops to run, your applications are not impacted.")),Object(c.b)("h2",{id:"faq"},"FAQ"),Object(c.b)("h3",{id:"how-to-choose-a-region"},"How to choose a region?"),Object(c.b)("p",null,"Different datacenters are located in different geographic areas, and you may want to keep your site physically close to the bulk of your user base for reduced latency."),Object(c.b)("h3",{id:"i-dont-find-a-region-that-is-provided-by-aws"},"I don't find a region that is provided by AWS"),Object(c.b)("p",null,"We are probably testing the support of this region, please ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/contact"}),"contact us")," to know what's the status"),Object(c.b)("h3",{id:"migrate-between-cloud-providers-and-regions"},"Migrate between Cloud providers and regions"),Object(c.b)("p",null,"Today, you can't migrate an environment from one region to another after it has been created. Vote ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://roadmap.qovery.com/"}),"here")," if you need this feature."))}p.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),b=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},u=function(e){var t=b(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},p=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,c=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=b(n),p=a,m=u["".concat(o,".").concat(p)]||u[p]||d[p]||c;return n?r.a.createElement(m,i({ref:t},s,{components:n})):r.a.createElement(m,i({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var c=n.length,o=new Array(c);o[0]=p;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:a,o[1]=i;for(var s=2;s1?arguments[1]:void 0,n),l=o>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>i;)t[i++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,c=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(c)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),c=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(c.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var a=n(435),r=n(51);function c(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),c=t.length>0?t.join("="):void 0;c=void 0===c?null:decodeURIComponent(c),n(decodeURIComponent(r),c,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[c(t,e),"[",a,"]"].join(""):[c(t,e),"[",c(a,e),"]=",c(n,e)].join("")};case"bracket":return function(t,n){return null===n?c(t,e):[c(t,e),"[]=",c(n,e)].join("")};default:return function(t,n){return null===n?c(t,e):[c(t,e),"=",c(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return c(a,t);if(Array.isArray(r)){var o=[];return r.slice().forEach((function(e){void 0!==e&&o.push(n(a,e,o.length))})),o.join("&")}return c(a,t)+"="+c(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var a=n(0),r=n.n(a),c=(n(423),n(433)),o=n.n(c);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,c=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+o.a.stringify(l),b=Object(a.useState)(null),u=b[0],d=b[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!c&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/4592dbe6.d1e0e42f.js.LICENSE.txt b/43a5f55b.5bcdf48c.js.LICENSE.txt similarity index 100% rename from 4592dbe6.d1e0e42f.js.LICENSE.txt rename to 43a5f55b.5bcdf48c.js.LICENSE.txt diff --git a/44b423be.dd56a64e.js b/44b423be.6a20a9ec.js similarity index 90% rename from 44b423be.dd56a64e.js rename to 44b423be.6a20a9ec.js index 9945154644..164f508205 100644 --- a/44b423be.dd56a64e.js +++ b/44b423be.6a20a9ec.js @@ -1,2 +1,2 @@ -/*! For license information please see 44b423be.dd56a64e.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[76],{228:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var r=n(1),a=n(9),o=(n(0),n(422)),i=n(431),c=n(426),s=(n(421),{last_modified_on:"2023-02-22",$schema:"/.meta/.schemas/guides.json",title:"Create a database",description:"How to create a database to your application",series_position:2,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),l={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Create a database",description:"How to create a database to your application",permalink:"/guides/getting-started/create-a-database",readingTime:"2 min read",seriesPosition:2,source:"@site/guides/getting-started/create-a-database.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Create a database",truncated:!1,prevItem:{title:"Hello World. Deploy your first application.",permalink:"/guides/getting-started/deploy-your-first-application"},nextItem:{title:"Custom domain",permalink:"/guides/getting-started/setting-custom-domain"}},u=[{value:"Tutorial",id:"tutorial",children:[{value:"Create a PostgreSQL database",id:"create-a-postgresql-database",children:[]},{value:"Connect your application",id:"connect-your-application",children:[]}]},{value:"Next Steps",id:"next-steps",children:[]}],p={rightToc:u};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Every application needs to store data in a database at some point. You'll learn how to get a production-grade database from Qovery in just a\nfew seconds in this guide."),Object(o.b)(c.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have already deployed an application with Qovery"))),Object(o.b)("h2",{id:"tutorial"},"Tutorial"),Object(o.b)("p",null,"Qovery supports most popular SQL and NoSQL databases (You can see the complete list ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/"}),"here"),"). In this guide we will deploy a\nPostgreSQL database and connect it to our NodeJS app."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h3",{id:"create-a-postgresql-database"},"Create a PostgreSQL database"),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/a76f72ede22c47048009fe874c2c6b03",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0})))),Object(o.b)("li",null,Object(o.b)("h3",{id:"connect-your-application"},"Connect your application"),Object(o.b)("p",null,"Now, we need to connect our application to our database. The credentials (URI, Username, Password ...) are available\nthrough ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"environment variables"),". They are injected by Qovery when your application runs."),Object(o.b)("p",null,"To connect our NodeJS application to our PostgreSQL database, we only have to:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Use the NodeJS PostgreSQL client (",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://node-postgres.com/features/connecting"}),"pg"),")"),Object(o.b)("li",{parentName:"ul"},"Use ",Object(o.b)("inlineCode",{parentName:"li"},"QOVERY_DATABASE_MY_DB_CONNECTION_URI")," into our code")),Object(o.b)("p",null,"Add the ",Object(o.b)("inlineCode",{parentName:"p"},"pg")," dependency into ",Object(o.b)("inlineCode",{parentName:"p"},"package.json")),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-json"}),'{\n /* ... */\n "dependencies": {\n /* ... */\n "pg": "^7.17.0"\n }\n}\n')),Object(o.b)("p",null,"Connect our application to PostgreSQL (",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://node-postgres.com/features/connecting"}),"see documentation"),")"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-javascript"}),"const { Pool } = require('pg')\n\nconst pool = new Pool({\n connectionString: process.env.QOVERY_DATABASE_MY_DB_CONNECTION_URI,\n})\n\n// your can use your connection pool now ...\n")),Object(o.b)("p",null,"Nothing more, well done! You can now be able to use your database.")))),Object(o.b)("h2",{id:"next-steps"},"Next Steps"),Object(o.b)("p",null,"Congratulations, your application has access to your PostgreSQL database. Now we will see how to add your custom domain to your service."))}d.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),b=r,f=p["".concat(i,".").concat(b)]||p[b]||d[b]||o;return n?a.a.createElement(f,c({ref:t},l,{components:n})):a.a.createElement(f,c({ref:t},l))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:a(s,n);l>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),u=Object(r.useState)(null),p=u[0],d=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 44b423be.6a20a9ec.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[78],{230:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var r=n(1),a=n(9),o=(n(0),n(425)),i=n(434),c=n(429),s=(n(424),{last_modified_on:"2023-02-22",$schema:"/.meta/.schemas/guides.json",title:"Create a database",description:"How to create a database to your application",series_position:2,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),l={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Create a database",description:"How to create a database to your application",permalink:"/guides/getting-started/create-a-database",readingTime:"2 min read",seriesPosition:2,source:"@site/guides/getting-started/create-a-database.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Create a database",truncated:!1,prevItem:{title:"Hello World. Deploy your first application.",permalink:"/guides/getting-started/deploy-your-first-application"},nextItem:{title:"Custom domain",permalink:"/guides/getting-started/setting-custom-domain"}},u=[{value:"Tutorial",id:"tutorial",children:[{value:"Create a PostgreSQL database",id:"create-a-postgresql-database",children:[]},{value:"Connect your application",id:"connect-your-application",children:[]}]},{value:"Next Steps",id:"next-steps",children:[]}],p={rightToc:u};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Every application needs to store data in a database at some point. You'll learn how to get a production-grade database from Qovery in just a\nfew seconds in this guide."),Object(o.b)(c.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have already deployed an application with Qovery"))),Object(o.b)("h2",{id:"tutorial"},"Tutorial"),Object(o.b)("p",null,"Qovery supports most popular SQL and NoSQL databases (You can see the complete list ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/"}),"here"),"). In this guide we will deploy a\nPostgreSQL database and connect it to our NodeJS app."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h3",{id:"create-a-postgresql-database"},"Create a PostgreSQL database"),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/a76f72ede22c47048009fe874c2c6b03",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0})))),Object(o.b)("li",null,Object(o.b)("h3",{id:"connect-your-application"},"Connect your application"),Object(o.b)("p",null,"Now, we need to connect our application to our database. The credentials (URI, Username, Password ...) are available\nthrough ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"environment variables"),". They are injected by Qovery when your application runs."),Object(o.b)("p",null,"To connect our NodeJS application to our PostgreSQL database, we only have to:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Use the NodeJS PostgreSQL client (",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://node-postgres.com/features/connecting"}),"pg"),")"),Object(o.b)("li",{parentName:"ul"},"Use ",Object(o.b)("inlineCode",{parentName:"li"},"QOVERY_DATABASE_MY_DB_CONNECTION_URI")," into our code")),Object(o.b)("p",null,"Add the ",Object(o.b)("inlineCode",{parentName:"p"},"pg")," dependency into ",Object(o.b)("inlineCode",{parentName:"p"},"package.json")),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-json"}),'{\n /* ... */\n "dependencies": {\n /* ... */\n "pg": "^7.17.0"\n }\n}\n')),Object(o.b)("p",null,"Connect our application to PostgreSQL (",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://node-postgres.com/features/connecting"}),"see documentation"),")"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-javascript"}),"const { Pool } = require('pg')\n\nconst pool = new Pool({\n connectionString: process.env.QOVERY_DATABASE_MY_DB_CONNECTION_URI,\n})\n\n// your can use your connection pool now ...\n")),Object(o.b)("p",null,"Nothing more, well done! You can now be able to use your database.")))),Object(o.b)("h2",{id:"next-steps"},"Next Steps"),Object(o.b)("p",null,"Congratulations, your application has access to your PostgreSQL database. Now we will see how to add your custom domain to your service."))}d.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),b=r,f=p["".concat(i,".").concat(b)]||p[b]||d[b]||o;return n?a.a.createElement(f,c({ref:t},l,{components:n})):a.a.createElement(f,c({ref:t},l))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:a(s,n);l>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),u=Object(r.useState)(null),p=u[0],d=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/47a329cb.1274da3a.js.LICENSE.txt b/44b423be.6a20a9ec.js.LICENSE.txt similarity index 100% rename from 47a329cb.1274da3a.js.LICENSE.txt rename to 44b423be.6a20a9ec.js.LICENSE.txt diff --git a/4505e7dd.5f398fa0.js b/4505e7dd.46dff9a9.js similarity index 74% rename from 4505e7dd.5f398fa0.js rename to 4505e7dd.46dff9a9.js index 8ed7a57bc1..92cb37a215 100644 --- a/4505e7dd.5f398fa0.js +++ b/4505e7dd.46dff9a9.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[77],{229:function(e){e.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"cloud-provider-azure","name":"cloud_provider: azure","count":1,"permalink":"/guides/tags/cloud-provider-azure"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[79],{231:function(e){e.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"cloud-provider-azure","name":"cloud_provider: azure","count":1,"permalink":"/guides/tags/cloud-provider-azure"}')}}]); \ No newline at end of file diff --git a/454f50a3.1678056b.js b/454f50a3.9905f09f.js similarity index 95% rename from 454f50a3.1678056b.js rename to 454f50a3.9905f09f.js index 7c1cde944e..01fb7becbf 100644 --- a/454f50a3.1678056b.js +++ b/454f50a3.9905f09f.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[78],{230:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return i})),t.d(r,"metadata",(function(){return c})),t.d(r,"rightToc",(function(){return u})),t.d(r,"default",(function(){return p}));var n=t(1),o=t(9),a=(t(0),t(422)),i={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Amazon Web Services account",description:"Learn how to install Qovery on your Amazon Web Services (AWS) account",author_github:"https://github.com/evoxmusic",tags:["type: guide","cloud_provider: aws"]},c={categories:[{name:"cloud-provider",title:"Cloud Provider",description:"Install Qovery on your favorite cloud provider.",permalink:"/guides/cloud-provider"}],coverLabel:"Install Qovery on your Amazon Web Services account",description:"Learn how to install Qovery on your Amazon Web Services (AWS) account",permalink:"/guides/cloud-provider/guide-amazon-web-services",readingTime:"1 min read",source:"@site/guides/cloud-provider/guide-amazon-web-services.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Install Qovery on your Amazon Web Services account",truncated:!1,prevItem:{title:"Import your environment variables with the Qovery CLI",permalink:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli"},nextItem:{title:"Install Qovery on your Kubernetes cluster",permalink:"/guides/provider/guide-kubernetes"}},u=[],l={rightToc:u};function p(e){var r=e.components,t=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},l,t,{components:r,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Eager to know how to deploy your apps on your AWS account with Qovery?\nClick \ud83d\udc49 ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes/"}),"here")," \ud83d\udc48 to follow the white rabbit \ud83d\udc07"))}p.isMDXComponent=!0},422:function(e,r,t){"use strict";t.d(r,"a",(function(){return s})),t.d(r,"b",(function(){return y}));var n=t(0),o=t.n(n);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function c(e){for(var r=1;r=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=o.a.createContext({}),p=function(e){var r=o.a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},s=function(e){var r=p(e.components);return o.a.createElement(l.Provider,{value:r},e.children)},d={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},m=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),s=p(t),m=n,y=s["".concat(i,".").concat(m)]||s[m]||d[m]||a;return t?o.a.createElement(y,c({ref:r},l,{components:t})):o.a.createElement(y,c({ref:r},l))}));function y(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var a=t.length,i=new Array(a);i[0]=m;var c={};for(var u in r)hasOwnProperty.call(r,u)&&(c[u]=r[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=o.a.createContext({}),p=function(e){var r=o.a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},s=function(e){var r=p(e.components);return o.a.createElement(l.Provider,{value:r},e.children)},d={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},m=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),s=p(t),m=n,y=s["".concat(i,".").concat(m)]||s[m]||d[m]||a;return t?o.a.createElement(y,c({ref:r},l,{components:t})):o.a.createElement(y,c({ref:r},l))}));function y(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var a=t.length,i=new Array(a);i[0]=m;var c={};for(var u in r)hasOwnProperty.call(r,u)&&(c[u]=r[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l {\n console.log(err, res)\n console.log('Seeding Completed!')\n pool.end()\n })\n}\n")),Object(o.b)("p",null,"The script connects to our Postgres instance, reads the seeding SQL, and makes the required updates. It does it only for non-prod environments thanks to the ",Object(o.b)("inlineCode",{parentName:"p"},"NODE_ENV")," environment variable."),Object(o.b)("p",null,"To make our life easier, we can declare the seeding command in our ",Object(o.b)("inlineCode",{parentName:"p"},"package.json"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{}),'...\n"seed": "node db/index.js"\n...\n')),Object(o.b)("h2",{id:"seeding"},"Seeding"),Object(o.b)("p",null,"To seed the data, we\u2019ll use ",Object(o.b)("inlineCode",{parentName:"p"},"ENTRYPOINT")," in our ",Object(o.b)("inlineCode",{parentName:"p"},"Dockerfile"),". For more details, you can read ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"our guide"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-docker"}),'FROM node:16\n\n# Create app directory\nWORKDIR /usr/src/app\n\n# Install app dependencies\n# A wildcard is used to ensure both package.json AND package-lock.json are copied\n# where available (npm@5+)\nCOPY package*.json ./\n\nRUN npm install\n# If you are building your code for production\n# RUN npm ci --only=production\n\n# Bundle app source\nCOPY . .\n\nEXPOSE 3000\n\nENTRYPOINT ["./entrypoint.sh"]\n\nCMD [ "node", "bin/www" ]\n\n')),Object(o.b)("p",null,"Add ",Object(o.b)("inlineCode",{parentName:"p"},"entrypoint.sh")," file to be executed on each environment where the app container runs:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'#! /bin/sh\n\nnode db/index.js\n\n# Execute the given or default command:\n\nexec "$@"\n')),Object(o.b)("h2",{id:"example"},"Example"),Object(o.b)("p",null,"The following examples will show the application of seeding the data in dev environments after cloning an environment and using the Preview Environment feature."),Object(o.b)("h3",{id:"clone-environment"},"Clone Environment"),Object(o.b)("p",null,"Clone environment feature allows you to make a complete clone of a chosen environment, including its all applications, services, and their configs. In the example we will clone a new environment and have our seed data injected automatically."),Object(o.b)("p",null,"First, we make a clone of our production environment:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/1.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"Then, we deploy the new environment:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/2.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"After navigating to deployment logs, we will notice our seed data inserts logged:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/3.png",alt:"Seeding Postgres Database"})),Object(o.b)("h3",{id:"preview-environment"},"Preview Environment"),Object(o.b)("p",null,"Preview Environment feature allows you to automatically create new development environments to validate new changes before merging them to your production branch."),Object(o.b)("p",null,"First, we open a pull request:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/4.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"Then, in list of environments, we get a new environment automatically created for the pull request:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/5.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"When you open the logs of the deployment, you\u2019ll see the seed data injection logs:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/6.png",alt:"Seeding Postgres Database"})))}p.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),u=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},b=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),b=a,m=p["".concat(i,".").concat(b)]||p[b]||d[b]||o;return n?r.a.createElement(m,c({ref:t},l,{components:n})):r.a.createElement(m,c({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:r(s,n);l>c;)t[c++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(430),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,p=Object(c.a)(u),d=Object(r.useRef)(!1),b=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!b&&p&&window.docusaurus.prefetch(u),function(){b&&t&&t.disconnect()}}),[u,b,p]),u&&p?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(u),d.current=!0)},innerRef:function(e){var n,a;b&&e&&p&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,d=c()("jump-to","jump-to--"+l,n),b=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:p,target:u,className:d},b):r.a.createElement(o.a,{to:p,className:d},b)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see 4592dbe6.38d26532.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[81],{233:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),o=(n(0),n(425)),i=n(424),c=(n(429),n(431),{last_modified_on:"2023-04-24",$schema:"/.meta/.schemas/guides.json",title:"How to seed a Postgres database on a dev environment",description:"How to automatically inject data into your development Postgres databases",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to seed a Postgres database on a dev environment",description:"How to automatically inject data into your development Postgres databases",permalink:"/guides/tutorial/data-seeding-in-postgres",readingTime:"4 min read",source:"@site/guides/tutorial/data-seeding-in-postgres.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to seed a Postgres database on a dev environment",truncated:!1,prevItem:{title:"How to run commands before the application starts",permalink:"/guides/tutorial/how-to-run-commands-at-application-startup"},nextItem:{title:"How to use CloudFront with a React frontend application on Qovery",permalink:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery"}},l=[{value:"Seeding SQL",id:"seeding-sql",children:[]},{value:"Migration Script",id:"migration-script",children:[]},{value:"Seeding",id:"seeding",children:[]},{value:"Example",id:"example",children:[{value:"Clone Environment",id:"clone-environment",children:[]},{value:"Preview Environment",id:"preview-environment",children:[]}]}],u={rightToc:l};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Consider using ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.replibyte.com"}),"Replibyte")," to seed your development database with real data")),Object(o.b)("p",null,"The goal of this article is to go through the process of seeding data into development environments on Qovery. Seeding the data into dev environments may help you set up clean development environments and thus speed up the development lifecycle in your team. It can be extremely useful for cloning and creating new environments or using the ",Object(o.b)("inlineCode",{parentName:"p"},"Preview Environment")," feature on Qovery."),Object(o.b)("p",null,"In this guide, we\u2019ll use a ",Object(o.b)("inlineCode",{parentName:"p"},"Node.js")," backend and ",Object(o.b)("inlineCode",{parentName:"p"},"Postgres")," database."),Object(o.b)("h2",{id:"seeding-sql"},"Seeding SQL"),Object(o.b)("p",null,"In the first step, let\u2019s create an idempotent script that will seed our development databases. During the development process, we should expect that the state of the database will be synced with the content of this script."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-sql"}),"DROP TABLE IF EXISTS _USER;\n\nCREATE TABLE _USER(\n ID INT PRIMARY KEY NOT NULL,\n FIRST_NAME VARCHAR(255) NOT NULL,\n LAST_NAME VARCHAR(50) NOT NULL\n);\n\nINSERT INTO _USER (ID, FIRST_NAME, LAST_NAME)\nVALUES (1, 'John', 'Doe');\n\nINSERT INTO _USER (ID, FIRST_NAME, LAST_NAME)\nVALUES (2, 'Alice', 'Wonderland');\n")),Object(o.b)("p",null,"The example above contains only a single table - the SQL script is specific to your application, so you\u2019ll have to create your own that reflects the schema and database state you would expect in the dev environment."),Object(o.b)("p",null,"Keep in mind that the script should be idempotent as there are chances it will be executed more than once against a single database during your development process."),Object(o.b)("h2",{id:"migration-script"},"Migration Script"),Object(o.b)("p",null,"In the next step, we\u2019ll create a script that will be used to connect to the database and seed the data."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const fs = require('fs')\nconst { Pool } = require('pg')\n\nrequire(\"dotenv\").config()\nconst databaseUrl = process.env.DATABASE_URL || 'postgresql://localhost:5432/test';\nconst pool = new Pool({\n connectionString: databaseUrl,\n})\n\nif (process.env.NODE_ENV !== 'production') {\n const seedQuery = fs.readFileSync('db/seeding.sql', { encoding: 'utf8' })\n pool.query(seedQuery, (err, res) => {\n console.log(err, res)\n console.log('Seeding Completed!')\n pool.end()\n })\n}\n")),Object(o.b)("p",null,"The script connects to our Postgres instance, reads the seeding SQL, and makes the required updates. It does it only for non-prod environments thanks to the ",Object(o.b)("inlineCode",{parentName:"p"},"NODE_ENV")," environment variable."),Object(o.b)("p",null,"To make our life easier, we can declare the seeding command in our ",Object(o.b)("inlineCode",{parentName:"p"},"package.json"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{}),'...\n"seed": "node db/index.js"\n...\n')),Object(o.b)("h2",{id:"seeding"},"Seeding"),Object(o.b)("p",null,"To seed the data, we\u2019ll use ",Object(o.b)("inlineCode",{parentName:"p"},"ENTRYPOINT")," in our ",Object(o.b)("inlineCode",{parentName:"p"},"Dockerfile"),". For more details, you can read ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"our guide"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-docker"}),'FROM node:16\n\n# Create app directory\nWORKDIR /usr/src/app\n\n# Install app dependencies\n# A wildcard is used to ensure both package.json AND package-lock.json are copied\n# where available (npm@5+)\nCOPY package*.json ./\n\nRUN npm install\n# If you are building your code for production\n# RUN npm ci --only=production\n\n# Bundle app source\nCOPY . .\n\nEXPOSE 3000\n\nENTRYPOINT ["./entrypoint.sh"]\n\nCMD [ "node", "bin/www" ]\n\n')),Object(o.b)("p",null,"Add ",Object(o.b)("inlineCode",{parentName:"p"},"entrypoint.sh")," file to be executed on each environment where the app container runs:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'#! /bin/sh\n\nnode db/index.js\n\n# Execute the given or default command:\n\nexec "$@"\n')),Object(o.b)("h2",{id:"example"},"Example"),Object(o.b)("p",null,"The following examples will show the application of seeding the data in dev environments after cloning an environment and using the Preview Environment feature."),Object(o.b)("h3",{id:"clone-environment"},"Clone Environment"),Object(o.b)("p",null,"Clone environment feature allows you to make a complete clone of a chosen environment, including its all applications, services, and their configs. In the example we will clone a new environment and have our seed data injected automatically."),Object(o.b)("p",null,"First, we make a clone of our production environment:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/1.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"Then, we deploy the new environment:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/2.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"After navigating to deployment logs, we will notice our seed data inserts logged:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/3.png",alt:"Seeding Postgres Database"})),Object(o.b)("h3",{id:"preview-environment"},"Preview Environment"),Object(o.b)("p",null,"Preview Environment feature allows you to automatically create new development environments to validate new changes before merging them to your production branch."),Object(o.b)("p",null,"First, we open a pull request:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/4.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"Then, in list of environments, we get a new environment automatically created for the pull request:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/5.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"When you open the logs of the deployment, you\u2019ll see the seed data injection logs:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/6.png",alt:"Seeding Postgres Database"})))}p.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),u=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},b=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),b=a,m=p["".concat(i,".").concat(b)]||p[b]||d[b]||o;return n?r.a.createElement(m,c({ref:t},l,{components:n})):r.a.createElement(m,c({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:r(s,n);l>c;)t[c++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(432),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,p=Object(c.a)(u),d=Object(r.useRef)(!1),b=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!b&&p&&window.docusaurus.prefetch(u),function(){b&&t&&t.disconnect()}}),[u,b,p]),u&&p?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(u),d.current=!0)},innerRef:function(e){var n,a;b&&e&&p&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,d=c()("jump-to","jump-to--"+l,n),b=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:p,target:u,className:d},b):r.a.createElement(o.a,{to:p,className:d},b)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/48764d63.b8a58ccc.js.LICENSE.txt b/4592dbe6.38d26532.js.LICENSE.txt similarity index 100% rename from 48764d63.b8a58ccc.js.LICENSE.txt rename to 4592dbe6.38d26532.js.LICENSE.txt diff --git a/47a329cb.1274da3a.js b/47a329cb.9d1daa0a.js similarity index 84% rename from 47a329cb.1274da3a.js rename to 47a329cb.9d1daa0a.js index 3d5da2e4f2..f7b72c73cf 100644 --- a/47a329cb.1274da3a.js +++ b/47a329cb.9d1daa0a.js @@ -1,2 +1,2 @@ -/*! For license information please see 47a329cb.1274da3a.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[80],{232:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return u}));var r=n(1),a=n(9),o=(n(0),n(422)),i=(n(429),n(421),n(426),{last_modified_on:"2023-04-13",title:"Deployment History",description:"Learn how to access the deployment history"}),c={id:"using-qovery/deployment/deployment-history",title:"Deployment History",description:"Learn how to access the deployment history",source:"@site/docs/using-qovery/deployment/deployment-history.md",permalink:"/docs/using-qovery/deployment/deployment-history",sidebar:"docs",previous:{title:"Deployment Actions",permalink:"/docs/using-qovery/deployment/deployment-actions"},next:{title:"Running and Deployment Statuses",permalink:"/docs/using-qovery/deployment/running-and-deployment-statuses"}},s=[],l={rightToc:s};function u(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"You can access the deployments history of your environment or service by opening the ",Object(o.b)("inlineCode",{parentName:"p"},"Deployments")," tab on either the environment or service page."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deployment/deployment_history.png",alt:"Deployment history access"})),Object(o.b)("p",null,"For each deployment triggered in the past, you will find "),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The execution id: an internal id assigned to each deployment. You can share this id with the Qovery team in case of errors in one of your deployments"),Object(o.b)("li",{parentName:"ul"},"Each service that has been deployed during this deployment together with their deployment status and the version that has been deployed")))}u.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),f=r,d=p["".concat(i,".").concat(f)]||p[f]||m[f]||o;return n?a.a.createElement(d,c({ref:t},l,{components:n})):a.a.createElement(d,c({ref:t},l))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:a(s,n);l>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(430),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,p=Object(c.a)(u),m=Object(a.useRef)(!1),f=l.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!f&&p&&window.docusaurus.prefetch(u),function(){f&&t&&t.disconnect()}}),[u,f,p]),u&&p?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(u),m.current=!0)},innerRef:function(e){var n,r;f&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(r.a)({},e,{href:u}))}},429:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,m=c()("jump-to","jump-to--"+l,n),f=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?a.a.createElement("a",{href:p,target:u,className:m},f):a.a.createElement(o.a,{to:p,className:m},f)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file +/*! For license information please see 47a329cb.9d1daa0a.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[82],{234:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return u}));var r=n(1),a=n(9),o=(n(0),n(425)),i=(n(431),n(424),n(429),{last_modified_on:"2023-04-13",title:"Deployment History",description:"Learn how to access the deployment history"}),c={id:"using-qovery/deployment/deployment-history",title:"Deployment History",description:"Learn how to access the deployment history",source:"@site/docs/using-qovery/deployment/deployment-history.md",permalink:"/docs/using-qovery/deployment/deployment-history",sidebar:"docs",previous:{title:"Deployment Actions",permalink:"/docs/using-qovery/deployment/deployment-actions"},next:{title:"Running and Deployment Statuses",permalink:"/docs/using-qovery/deployment/running-and-deployment-statuses"}},s=[],l={rightToc:s};function u(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"You can access the deployments history of your environment or service by opening the ",Object(o.b)("inlineCode",{parentName:"p"},"Deployments")," tab on either the environment or service page."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deployment/deployment_history.png",alt:"Deployment history access"})),Object(o.b)("p",null,"For each deployment triggered in the past, you will find "),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The execution id: an internal id assigned to each deployment. You can share this id with the Qovery team in case of errors in one of your deployments"),Object(o.b)("li",{parentName:"ul"},"Each service that has been deployed during this deployment together with their deployment status and the version that has been deployed")))}u.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),f=r,d=p["".concat(i,".").concat(f)]||p[f]||m[f]||o;return n?a.a.createElement(d,c({ref:t},l,{components:n})):a.a.createElement(d,c({ref:t},l))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:a(s,n);l>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(432),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,p=Object(c.a)(u),m=Object(a.useRef)(!1),f=l.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!f&&p&&window.docusaurus.prefetch(u),function(){f&&t&&t.disconnect()}}),[u,f,p]),u&&p?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(u),m.current=!0)},innerRef:function(e){var n,r;f&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(r.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,m=c()("jump-to","jump-to--"+l,n),f=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?a.a.createElement("a",{href:p,target:u,className:m},f):a.a.createElement(o.a,{to:p,className:m},f)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/498daee8.6c30e0e2.js.LICENSE.txt b/47a329cb.9d1daa0a.js.LICENSE.txt similarity index 100% rename from 498daee8.6c30e0e2.js.LICENSE.txt rename to 47a329cb.9d1daa0a.js.LICENSE.txt diff --git a/48764d63.b8a58ccc.js b/48764d63.c4c3de41.js similarity index 91% rename from 48764d63.b8a58ccc.js rename to 48764d63.c4c3de41.js index 07cccb8b2a..d7b3f43699 100644 --- a/48764d63.b8a58ccc.js +++ b/48764d63.c4c3de41.js @@ -1,2 +1,2 @@ -/*! For license information please see 48764d63.b8a58ccc.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[81],{233:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),a=(n(0),n(422)),i=(n(431),n(426)),c=(n(421),{last_modified_on:"2023-04-13",$schema:"/.meta/.schemas/guides.json",title:"Debugging",description:"How to debug your application",series_position:5,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),s={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Debugging",description:"How to debug your application",permalink:"/guides/getting-started/debugging",readingTime:"3 min read",seriesPosition:5,source:"@site/guides/getting-started/debugging.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Debugging",truncated:!1,prevItem:{title:"Environment variables",permalink:"/guides/getting-started/managing-environment-variables"},nextItem:{title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",permalink:"/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws"}},u=[{value:"Check the status of your app",id:"check-the-status-of-your-app",children:[]},{value:"Live Logs",id:"live-logs",children:[]},{value:"Deployment Logs",id:"deployment-logs",children:[]},{value:"Monitoring",id:"monitoring",children:[]},{value:"Alerting",id:"alerting",children:[]}],l={rightToc:u};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Your application is running, but something goes wrong? In this guide, you'll learn how to debug your application and solve your problem to\nmake it running smoothly."),Object(a.b)(i.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have already deployed an application with Qovery"))),Object(a.b)("p",null,"Your application is running, but for some reason, it is not working as expected. Here are a few tips to find out what's going on."),Object(a.b)("h2",{id:"check-the-status-of-your-app"},"Check the status of your app"),Object(a.b)("p",null,"Qovery expose in the interface the running status of your application which provides you some highlevel information of its healthiness. You can look ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/running-and-deployment-statuses/"}),"in this section")," to know more about the ",Object(a.b)("inlineCode",{parentName:"p"},"Running Status")),Object(a.b)("p",null,"If the service crashes, its ",Object(a.b)("inlineCode",{parentName:"p"},"Running Status")," will be displayed as a red dot. If that's the case, you can have a look at the logs to investigate the reason behind."),Object(a.b)("h2",{id:"live-logs"},"Live Logs"),Object(a.b)("p",null,"If you need to see the log output of your application while it's running, qovery expose them to you in real-time thanks to the Logs interface. You can have a look at ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#live-logs"}),"this section")," to know more."),Object(a.b)("p",null,"You can use this information to find out what causes your application to behave incorrectly."),Object(a.b)("h2",{id:"deployment-logs"},"Deployment Logs"),Object(a.b)("p",null,"If your application fails to start, you can check what's the cause in its deployment logs. You can have a look at ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#deployment-logs"}),"this section")," to have more information on the deployment logs and how to access them."),Object(a.b)("p",null,"This view provides insight into the build and deployment process. If anything goes wrong, you can see all the required information to fix the problem here."),Object(a.b)("p",null,"You can check the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/troubleshoot/"}),"Troubleshoot section")," to investigate any issue you might encounter during the deployment of your services."),Object(a.b)("h2",{id:"monitoring"},"Monitoring"),Object(a.b)("p",null,"If you need more information about the resources consumed by your application, Qovery provides basic metrics about your CPU, memory and storage usage."),Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Navigate to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(a.b)("li",null,Object(a.b)("p",null,"Choose your project, environment, and application.")),Object(a.b)("li",null,Object(a.b)("p",null,"In the main application view, you can see a table with the current application resource consumption."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/debugging/metrics.png",alt:"Metrics"})))),Object(a.b)("h2",{id:"alerting"},"Alerting"),Object(a.b)("p",null,"We highly recommend using tools like ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.datadoghq.com"}),"Datadog"),", ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://sentry.io/"}),"Sentry")," or ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://newrelic.com/"}),"NewRelic")," to manage your alerting.\nQovery will provide easy integrations in the coming release. Check out our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://roadmap.qovery.com/"}),"roadmap")),Object(a.b)("p",null,"Do you need any help? ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discord.qovery.com"}),"Reach us on Discord")))}p.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),l=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,g=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return n?o.a.createElement(g,c({ref:t},u,{components:n})):o.a.createElement(g,c({ref:t},u))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,u=void 0===s?n:o(s,n);u>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),p=l[0],b=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 48764d63.c4c3de41.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[83],{235:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),a=(n(0),n(425)),i=(n(434),n(429)),c=(n(424),{last_modified_on:"2023-04-13",$schema:"/.meta/.schemas/guides.json",title:"Debugging",description:"How to debug your application",series_position:5,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),s={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Debugging",description:"How to debug your application",permalink:"/guides/getting-started/debugging",readingTime:"3 min read",seriesPosition:5,source:"@site/guides/getting-started/debugging.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Debugging",truncated:!1,prevItem:{title:"Environment variables",permalink:"/guides/getting-started/managing-environment-variables"},nextItem:{title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",permalink:"/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws"}},u=[{value:"Check the status of your app",id:"check-the-status-of-your-app",children:[]},{value:"Live Logs",id:"live-logs",children:[]},{value:"Deployment Logs",id:"deployment-logs",children:[]},{value:"Monitoring",id:"monitoring",children:[]},{value:"Alerting",id:"alerting",children:[]}],l={rightToc:u};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Your application is running, but something goes wrong? In this guide, you'll learn how to debug your application and solve your problem to\nmake it running smoothly."),Object(a.b)(i.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have already deployed an application with Qovery"))),Object(a.b)("p",null,"Your application is running, but for some reason, it is not working as expected. Here are a few tips to find out what's going on."),Object(a.b)("h2",{id:"check-the-status-of-your-app"},"Check the status of your app"),Object(a.b)("p",null,"Qovery expose in the interface the running status of your application which provides you some highlevel information of its healthiness. You can look ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/running-and-deployment-statuses/"}),"in this section")," to know more about the ",Object(a.b)("inlineCode",{parentName:"p"},"Running Status")),Object(a.b)("p",null,"If the service crashes, its ",Object(a.b)("inlineCode",{parentName:"p"},"Running Status")," will be displayed as a red dot. If that's the case, you can have a look at the logs to investigate the reason behind."),Object(a.b)("h2",{id:"live-logs"},"Live Logs"),Object(a.b)("p",null,"If you need to see the log output of your application while it's running, qovery expose them to you in real-time thanks to the Logs interface. You can have a look at ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#live-logs"}),"this section")," to know more."),Object(a.b)("p",null,"You can use this information to find out what causes your application to behave incorrectly."),Object(a.b)("h2",{id:"deployment-logs"},"Deployment Logs"),Object(a.b)("p",null,"If your application fails to start, you can check what's the cause in its deployment logs. You can have a look at ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#deployment-logs"}),"this section")," to have more information on the deployment logs and how to access them."),Object(a.b)("p",null,"This view provides insight into the build and deployment process. If anything goes wrong, you can see all the required information to fix the problem here."),Object(a.b)("p",null,"You can check the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/troubleshoot/"}),"Troubleshoot section")," to investigate any issue you might encounter during the deployment of your services."),Object(a.b)("h2",{id:"monitoring"},"Monitoring"),Object(a.b)("p",null,"If you need more information about the resources consumed by your application, Qovery provides basic metrics about your CPU, memory and storage usage."),Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Navigate to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(a.b)("li",null,Object(a.b)("p",null,"Choose your project, environment, and application.")),Object(a.b)("li",null,Object(a.b)("p",null,"In the main application view, you can see a table with the current application resource consumption."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/debugging/metrics.png",alt:"Metrics"})))),Object(a.b)("h2",{id:"alerting"},"Alerting"),Object(a.b)("p",null,"We highly recommend using tools like ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.datadoghq.com"}),"Datadog"),", ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://sentry.io/"}),"Sentry")," or ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://newrelic.com/"}),"NewRelic")," to manage your alerting.\nQovery will provide easy integrations in the coming release. Check out our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://roadmap.qovery.com/"}),"roadmap")),Object(a.b)("p",null,"Do you need any help? ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discord.qovery.com"}),"Reach us on Discord")))}p.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),l=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,g=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return n?o.a.createElement(g,c({ref:t},u,{components:n})):o.a.createElement(g,c({ref:t},u))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,u=void 0===s?n:o(s,n);u>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),p=l[0],b=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/49a59b02.03fc3907.js.LICENSE.txt b/48764d63.c4c3de41.js.LICENSE.txt similarity index 100% rename from 49a59b02.03fc3907.js.LICENSE.txt rename to 48764d63.c4c3de41.js.LICENSE.txt diff --git a/48912b2c.92b03980.js b/48912b2c.6caacd3e.js similarity index 51% rename from 48912b2c.92b03980.js rename to 48912b2c.6caacd3e.js index 8d1391e20f..7dda3c8b25 100644 --- a/48912b2c.92b03980.js +++ b/48912b2c.6caacd3e.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[82],{234:function(n,t,u){"use strict";u.r(t);var r=u(0),c=u.n(r),e=u(469);t.default=function(){return c.a.createElement(e.a,{to:"/community/"})}},469:function(n,t,u){"use strict";var r=u(39);u.d(t,"a",(function(){return r.c})),u.d(t,"b",(function(){return r.d})),u.d(t,"c",(function(){return r.e})),u.d(t,"d",(function(){return r.f}))}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[84],{236:function(n,t,u){"use strict";u.r(t);var r=u(0),c=u.n(r),e=u(472);t.default=function(){return c.a.createElement(e.a,{to:"/community/"})}},472:function(n,t,u){"use strict";var r=u(39);u.d(t,"a",(function(){return r.c})),u.d(t,"b",(function(){return r.d})),u.d(t,"c",(function(){return r.e})),u.d(t,"d",(function(){return r.f}))}}]); \ No newline at end of file diff --git a/1dd2c233.fc271294.js b/498daee8.66a3b4b4.js similarity index 93% rename from 1dd2c233.fc271294.js rename to 498daee8.66a3b4b4.js index 9a2e42af15..b17585790d 100644 --- a/1dd2c233.fc271294.js +++ b/498daee8.66a3b4b4.js @@ -1,2 +1,2 @@ -/*! For license information please see 1dd2c233.fc271294.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[38],{190:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return l})),r.d(t,"rightToc",(function(){return u})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),o=(r(0),r(422)),c=(r(431),r(426),r(421)),i={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Deploy Frontend App",description:"Learn how to deploy your Frontend app with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","language: javascript"]},l={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Deploy Frontend App",description:"Learn how to deploy your Frontend app with Qovery",permalink:"/guides/advanced/deploy-frontend",readingTime:"2 min read",source:"@site/guides/advanced/deploy-frontend.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"language: javascript",permalink:"/guides/tags/language-javascript"}],title:"Deploy Frontend App",truncated:!1,prevItem:{title:"Deploy External Services",permalink:"/guides/advanced/deploy-external-services"},nextItem:{title:"Deploy Rails with PostgreSQL and Sidekiq",permalink:"/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq"}},u=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:u};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery is versatile and has the ability to cater to a wide range of frontend applications. Whether you're working with a Single-Page\nApplication (SPA), a Server-Side Rendered (SSR) applications, or a general web app, Qovery has you covered."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to deploy your different type of Frontend apps with Qovery."),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Most Frontend apps does not require to have much CPU and RAM resources allocated to them at runtime.\nYou can use 100 mCPU and 128 MiB of RAM for most of them."),Object(o.b)("p",null,"However, build time can be very CPU and RAM intensive. Qovery provides default build resources for each type of Frontend app.\nYou can change them in your ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/advanced-settings/"}),"app advanced settings"),".")),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy SPA container")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy your frontend SPA (React) app inside a container with a NGINX web server")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy SPA container with Cloudfront")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy your frontend SPA (React) app inside a container with a NGINX web server and expose it via Cloudfront CDN")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery/"}),"Use Cloudflare as a CDN")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery/"}),"Use Cloudflare as a CDN for your frontend SPA (React) app")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy SSR container"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy your frontend SSR (NextJS) app inside a container with a NGINX web server"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy SSR on Cloudfront"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy your frontend SSR (NextJS) app on AWS Cloudfront"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=react"}),'"React" forum threads')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=react"}),'List "React" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=nextjs"}),'"NextJS" forum threads')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=nextjs"}),'List "NextJS" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=angular"}),'"Angular" forum threads')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=angular"}),'List "Angular" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},420:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),b=n,m=p["".concat(c,".").concat(b)]||p[b]||d[b]||o;return r?a.a.createElement(m,i({ref:t},u,{components:r})):a.a.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,c=new Array(o);c[0]=b;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var u=2;u1?arguments[1]:void 0,r),l=c>2?arguments[2]:void 0,u=void 0===l?r:a(l,r);u>i;)t[i++]=e;return t}},425:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,r){"use strict";r(425);var n=r(0),a=r.n(n),o=r(421);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},428:function(e,t,r){"use strict";var n=r(432),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var c=[];return a.slice().forEach((function(e){void 0!==e&&c.push(r(n,e,c.length))})),c.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(420),r(428)),c=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(n.useState)(null),p=s[0],d=s[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 498daee8.66a3b4b4.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[85],{237:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return l})),r.d(t,"rightToc",(function(){return u})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),o=(r(0),r(425)),c=(r(434),r(429),r(424)),i={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Deploy Frontend App",description:"Learn how to deploy your Frontend app with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","language: javascript"]},l={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Deploy Frontend App",description:"Learn how to deploy your Frontend app with Qovery",permalink:"/guides/advanced/deploy-frontend",readingTime:"2 min read",source:"@site/guides/advanced/deploy-frontend.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"language: javascript",permalink:"/guides/tags/language-javascript"}],title:"Deploy Frontend App",truncated:!1,prevItem:{title:"Deploy External Services",permalink:"/guides/advanced/deploy-external-services"},nextItem:{title:"Deploy Rails with PostgreSQL and Sidekiq",permalink:"/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq"}},u=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:u};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery is versatile and has the ability to cater to a wide range of frontend applications. Whether you're working with a Single-Page\nApplication (SPA), a Server-Side Rendered (SSR) applications, or a general web app, Qovery has you covered."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to deploy your different type of Frontend apps with Qovery."),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Most Frontend apps does not require to have much CPU and RAM resources allocated to them at runtime.\nYou can use 100 mCPU and 128 MiB of RAM for most of them."),Object(o.b)("p",null,"However, build time can be very CPU and RAM intensive. Qovery provides default build resources for each type of Frontend app.\nYou can change them in your ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/advanced-settings/"}),"app advanced settings"),".")),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy SPA container")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy your frontend SPA (React) app inside a container with a NGINX web server")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy SPA container with Cloudfront")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/"}),"Deploy your frontend SPA (React) app inside a container with a NGINX web server and expose it via Cloudfront CDN")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery/"}),"Use Cloudflare as a CDN")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery/"}),"Use Cloudflare as a CDN for your frontend SPA (React) app")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy SSR container"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy your frontend SSR (NextJS) app inside a container with a NGINX web server"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy SSR on Cloudfront"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Deploy your frontend SSR (NextJS) app on AWS Cloudfront"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=react"}),'"React" forum threads')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=react"}),'List "React" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=nextjs"}),'"NextJS" forum threads')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=nextjs"}),'List "NextJS" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=angular"}),'"Angular" forum threads')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=angular"}),'List "Angular" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),b=n,m=p["".concat(c,".").concat(b)]||p[b]||d[b]||o;return r?a.a.createElement(m,i({ref:t},u,{components:r})):a.a.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,c=new Array(o);c[0]=b;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var u=2;u1?arguments[1]:void 0,r),l=c>2?arguments[2]:void 0,u=void 0===l?r:a(l,r);u>i;)t[i++]=e;return t}},428:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,r){"use strict";r(428);var n=r(0),a=r.n(n),o=r(424);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},433:function(e,t,r){"use strict";var n=r(435),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var c=[];return a.slice().forEach((function(e){void 0!==e&&c.push(r(n,e,c.length))})),c.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(423),r(433)),c=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(n.useState)(null),p=s[0],d=s[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/4dcdbf34.a7699c8e.js.LICENSE.txt b/498daee8.66a3b4b4.js.LICENSE.txt similarity index 100% rename from 4dcdbf34.a7699c8e.js.LICENSE.txt rename to 498daee8.66a3b4b4.js.LICENSE.txt diff --git a/49a59b02.03fc3907.js b/49a59b02.2a8666ba.js similarity index 95% rename from 49a59b02.03fc3907.js rename to 49a59b02.2a8666ba.js index ca12637c31..6f0f8b673a 100644 --- a/49a59b02.03fc3907.js +++ b/49a59b02.2a8666ba.js @@ -1,2 +1,2 @@ -/*! For license information please see 49a59b02.03fc3907.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[84],{236:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return p})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return d}));var r=n(1),o=n(9),i=(n(0),n(422)),a=n(431),l=n(421),c=n(426),p={last_modified_on:"2022-03-16",$schema:"/.meta/.schemas/guides.json",title:"Deploy Temporal on Kubernetes",description:"How to deploy a Temporal.io server and UI on Qovery.",author_github:"https://github.com/l0ck3",tags:["type: tutorial","technology: qovery","database: postgresql"],hide_pagination:!0},b={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Deploy Temporal on Kubernetes",description:"How to deploy a Temporal.io server and UI on Qovery.",permalink:"/guides/tutorial/deploy-temporal-on-kubernetes",readingTime:"7 min read",source:"@site/guides/tutorial/deploy-temporal-on-kubernetes.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"},{label:"database: postgresql",permalink:"/guides/tags/database-postgresql"}],title:"Deploy Temporal on Kubernetes",truncated:!1,prevItem:{title:"Deploy Rails with PostgreSQL and Sidekiq",permalink:"/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq"},nextItem:{title:"Getting Started with Preview Environments on AWS",permalink:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners"}},s=[{value:"Goal",id:"goal",children:[]},{value:"Create the Qovery project and staging environment",id:"create-the-qovery-project-and-staging-environment",children:[]},{value:"Deploy Temporal server",id:"deploy-temporal-server",children:[]},{value:"Deploy the Web UI",id:"deploy-the-web-ui",children:[]},{value:"Deploy your environment",id:"deploy-your-environment",children:[]},{value:"Split the temporal services for independent scaling.",id:"split-the-temporal-services-for-independent-scaling",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],u={rightToc:s};function d(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(c.a,{name:"guide",mdxType:"Assumptions"},Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"You have a Qovery cluster ready"))),Object(i.b)("h2",{id:"goal"},"Goal"),Object(i.b)("p",null,"In this tutorial we will deploy ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://temporal.io"}),"Temporal.io")," on Qovery directly through the Qovery console.\nWe will first do a staging / preview env deployment then a multi-services deployment allowing to scale the different Temporal parts independently."),Object(i.b)(l.a,{type:"warning",mdxType:"Alert"},"Temporal.io is a complex product. Using it in production requires a good understanding of the project and its configuration options.",Object(i.b)("br",null),Object(i.b)("br",null),"This guide is useful if you want to deploy Temporal in your staging / preview environments. However, for production, you should install it directly on your Kubernetes cluster."),Object(i.b)("p",null,"You can find the official documentation for production deployment here: ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.temporal.io/docs/server/production-deployment"}),"https://docs.temporal.io/docs/server/production-deployment"),"."),Object(i.b)("h2",{id:"create-the-qovery-project-and-staging-environment"},"Create the Qovery project and staging environment"),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("h4",{id:"create-qovery-project"},"Create Qovery project"),Object(i.b)("p",null,"Head to the ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console")," and create a project:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/1.png",alt:"Qovery - Create Project"}))),Object(i.b)("li",null,Object(i.b)("h4",{id:"create-staging-environment"},"Create staging environment"),Object(i.b)("p",null,"Next create your staging environment:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/2.png",alt:"Qovery - Create Environment"}))))),Object(i.b)("h2",{id:"deploy-temporal-server"},"Deploy Temporal server"),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("h4",{id:"fork-the-example-github-repository"},"Fork the example GitHub repository"),Object(i.b)("p",null,"Go to ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-temporalio-example"}),"https://github.com/Qovery/qovery-temporalio-example")," and fork the repository."),Object(i.b)("p",null,"You can edit the tags in the Dockerfiles to match the latest versions. Check the latest tags here: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Server: ",Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.docker.com/r/temporalio/auto-setup/tags"}),"https://hub.docker.com/r/temporalio/auto-setup/tags")),Object(i.b)("li",{parentName:"ul"},"Web UI: ",Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.docker.com/r/temporalio/web/tags"}),"https://hub.docker.com/r/temporalio/web/tags")))),Object(i.b)("li",null,Object(i.b)("h4",{id:"create-the-temporal-server-application"},"Create the Temporal server application"),Object(i.b)("p",null,"Click on ",Object(i.b)("inlineCode",{parentName:"p"},"Create Application")," then fill the form:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Select your forked GitHub repository."),Object(i.b)("li",{parentName:"ul"},"Select ",Object(i.b)("inlineCode",{parentName:"li"},"Dockerfile")," as the build mode."),Object(i.b)("li",{parentName:"ul"},"Put ",Object(i.b)("inlineCode",{parentName:"li"},"7233")," as a port."),Object(i.b)("li",{parentName:"ul"},"Click ",Object(i.b)("inlineCode",{parentName:"li"},"Create"),".")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/3.png",alt:"Qovery - Create Application 1"})),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/4.png",alt:"Qovery - Create Application 2"})),Object(i.b)("p",null,"Your application is created:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/5.png",alt:"Qovery - Application Created"})),Object(i.b)("p",null,"Don't deploy it yet though. We still have a few steps to accomplish before.")),Object(i.b)("li",null,Object(i.b)("h4",{id:"update-the-port-settings"},"Update the port settings"),Object(i.b)("p",null,"First we will disable the public endpoint to the port."),Object(i.b)(l.a,{type:"warning",mdxType:"Alert"},"At the time of writing, Qovery doesn't support GRPC public endpoints. We disable the public endpoint since we can't use it from the outside."),Object(i.b)("p",null,"Click on ",Object(i.b)("inlineCode",{parentName:"p"},"Settings > Port"),", then on ",Object(i.b)("inlineCode",{parentName:"p"},"..."),", ",Object(i.b)("inlineCode",{parentName:"p"},"Advanced settings")," and uncheck ",Object(i.b)("inlineCode",{parentName:"p"},"Publicly"),".\nSave the settings and close the modal."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/6.png",alt:"Qovery - Disable Public Port"}))),Object(i.b)("li",null,Object(i.b)("h4",{id:"add-a-postgresql-database"},"Add a PostgreSQL database"),Object(i.b)("p",null,"We will now add a PostgreSQL database to serve as a persistence layer to our Temporal server."),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},"Temporal can also use MySQL or Cassandra as a persistence layer."),Object(i.b)("p",null,"Click on ",Object(i.b)("inlineCode",{parentName:"p"},"Add")," then ",Object(i.b)("inlineCode",{parentName:"p"},"Database")," then fill the form: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Pick a name for your DB."),Object(i.b)("li",{parentName:"ul"},"Type: PostgreSQL"),Object(i.b)("li",{parentName:"ul"},"Mode: Container (less expensive than Managed for non-production environments) "),Object(i.b)("li",{parentName:"ul"},"Version: 13"),Object(i.b)("li",{parentName:"ul"},"Accessibility: Private")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/7.png",alt:"Qovery - Add Database"})),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/8.png",alt:"Qovery - Configure PosgreSQL"})),Object(i.b)("p",null,"Your database is created:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/9.png",alt:"Qovery - Application Created"})),Object(i.b)("p",null,"Don't deploy it. We're not done setting-up our environment.")),Object(i.b)("li",null,Object(i.b)("h4",{id:"set-the-environment-variables"},"Set the environment variables"),Object(i.b)("p",null,"Now we need to set a bunch of environment variables.\nGo back to your Temporal server app and click on ",Object(i.b)("inlineCode",{parentName:"p"},"Environment variables"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/9.png",alt:"Qovery - Environment Variables"})),Object(i.b)(l.a,{type:"warning",mdxType:"Alert"},"Create all those env variables with the `ENVIRONMENT` scope. It will be useful when we split the server services, to avoid repeating the process for each app."),Object(i.b)("p",null,"Add the following environment variables: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"DB=postgresql")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"LOG_LEVEL=debug,info"))),Object(i.b)("p",null,"Now create the following aliases on environment variables:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_POSTGRESQL_Z[DB ID]_HOST_INTERNAL"),": ",Object(i.b)("inlineCode",{parentName:"li"},"POSTGRES_SEEDS")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_POSTGRESQL_[DB ID]_LOGIN"),": ",Object(i.b)("inlineCode",{parentName:"li"},"POSTGRES_USER")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_POSTGRESQL_[DB ID]_PORT"),": ",Object(i.b)("inlineCode",{parentName:"li"},"DB_PORT"))),Object(i.b)("p",null,"On an alias on secrets: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_POSTGRESQL_[DB ID]_PASSWORD"),": ",Object(i.b)("inlineCode",{parentName:"li"},"POSTGRES_PWD")))))),Object(i.b)("h2",{id:"deploy-the-web-ui"},"Deploy the Web UI"),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("h4",{id:"create-the-temporal-ui-application"},"Create the Temporal UI application"),Object(i.b)("p",null,"Now go to the environment level, and click on ",Object(i.b)("inlineCode",{parentName:"p"},"Add"),".\nSimilar to what you did for the server:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Select your forked GitHub repository."),Object(i.b)("li",{parentName:"ul"},"Select ",Object(i.b)("inlineCode",{parentName:"li"},"Dockerfile")," as the build mode."),Object(i.b)("li",{parentName:"ul"},"Put ",Object(i.b)("inlineCode",{parentName:"li"},"Dockerfile.web")," for the Dockerfile path."),Object(i.b)("li",{parentName:"ul"},"Put ",Object(i.b)("inlineCode",{parentName:"li"},"8088")," as a port."),Object(i.b)("li",{parentName:"ul"},"Click ",Object(i.b)("inlineCode",{parentName:"li"},"Create"),".")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/11.png",alt:"Qovery - Create application 1"})),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/12.png",alt:"Qovery - Create application 2"}))),Object(i.b)("li",null,Object(i.b)("h4",{id:"get-the-application-id-of-the-temporal-server"},"Get the application ID of the Temporal server"),Object(i.b)("p",null,"To get the application ID of the Temporal server, go back to the corresponding app, and note the first part of the UUID in the browser URL."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/13.png",alt:"Qovery - Get Application ID"})),Object(i.b)("p",null,"Copy this ID somewhere.")),Object(i.b)("li",null,Object(i.b)("h4",{id:"set-the-environment-variables-1"},"Set the environment variables"),Object(i.b)(l.a,{type:"warning",mdxType:"Alert"},"This time you can create the env variables with the `APPLICATION` scope."),Object(i.b)("p",null,"Add the following environment variable: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"TEMPORAL_SERVER_PORT"),": ",Object(i.b)("inlineCode",{parentName:"li"},"7233"))),Object(i.b)("p",null,"Now create the following alias on environment variables:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_APPLICATION_Z[SERVER APPLICATION ID]_HOST_INTERNAL"),": ",Object(i.b)("inlineCode",{parentName:"li"},"TEMPORAL_SERVER_HOST")))))),Object(i.b)("h2",{id:"deploy-your-environment"},"Deploy your environment"),Object(i.b)("p",null,"You can now deploy your environment. Go back to your environment view and click ",Object(i.b)("inlineCode",{parentName:"p"},"DEPLOY"),"."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/14.png",alt:"Qovery - Deploy Application"})),Object(i.b)("p",null,"Once it's deployed and the status is ",Object(i.b)("inlineCode",{parentName:"p"},"RUNNING"),", you can go to the Web UI application and open it."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/15.png",alt:"Qovery - Open Application"})),Object(i.b)("p",null,"If you see the Temporal Web UI with no error, well done. Your server is deployed!"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/16.png",alt:"Temporal - UI"})),Object(i.b)("h2",{id:"split-the-temporal-services-for-independent-scaling"},"Split the temporal services for independent scaling."),Object(i.b)("p",null,"Temporal server is composed of four different services. By default, they will all be running in the same process. But if you would like to scale them independently, you still have the option to deploy them separately."),Object(i.b)("p",null,"See the Temporal docs for more information on the architecture: ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.temporal.io/docs/concepts/what-is-a-temporal-cluster"}),"https://docs.temporal.io/docs/concepts/what-is-a-temporal-cluster")),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("h4",{id:"clone-your-environment"},"Clone your environment"),Object(i.b)("p",null,"We could start again from scratch or edit the running environment (which would require resetting the DB), but instead we will leverage the clone feature of Qovery, to start with an identical, clean environment."),Object(i.b)("p",null,"On your environment page, click ",Object(i.b)("inlineCode",{parentName:"p"},"Actions")," then ",Object(i.b)("inlineCode",{parentName:"p"},"Clone"),"."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/17.png",alt:"Qovery - Clone Environment"})),Object(i.b)("p",null,"Pick a name and click ",Object(i.b)("inlineCode",{parentName:"p"},"Create")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/18.png",alt:"Qovery - Clone Modal"})),Object(i.b)("p",null,"You will land in an identical environment, not deployed yet. Don't deploy it right away, we will first split our services.")),Object(i.b)("li",null,Object(i.b)("h4",{id:"switch-your-server-service-to-frontend-gateway"},"Switch your server service to frontend gateway"),Object(i.b)("p",null,"First we will rename the server application to call it ",Object(i.b)("inlineCode",{parentName:"p"},"temporal-frontend"),". Go to the server application and click ",Object(i.b)("inlineCode",{parentName:"p"},"Settings"),". Then change the name and save."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/19.png",alt:"Qovery - Clone Modal"}))),Object(i.b)("li",null,Object(i.b)("h4",{id:"add-an-env-variable-to-flag-the-service"},"Add an env variable to flag the service"),Object(i.b)("p",null,"In order to tell our application that it should only start the frontend service, we'll add an env variable with the ",Object(i.b)("inlineCode",{parentName:"p"},"APPLICATION")," scope: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"SERVICES=frontend"))),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},"You can run several services if you'd like, setting the variable with a value like `SERVICES=frontend,history`")),Object(i.b)("li",null,Object(i.b)("h4",{id:"create-the-other-services"},"Create the other services"),Object(i.b)("p",null,"Create three new application, following the steps you did for the server initially:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"temporal-history")," with an env variable ",Object(i.b)("inlineCode",{parentName:"li"},"SERVICES=history"),"."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"temporal-matching")," with an env variable ",Object(i.b)("inlineCode",{parentName:"li"},"SERVICES=matching"),"."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"temporal-worker")," with an env variable ",Object(i.b)("inlineCode",{parentName:"li"},"SERVICES=worker"),".")),Object(i.b)("p",null,"Each time set the port to ",Object(i.b)("inlineCode",{parentName:"p"},"7233")," and disable the public endpoint."),Object(i.b)("p",null,"You should end up with something like this: "),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/20.png",alt:"Qovery - Environment"}))),Object(i.b)("li",null,Object(i.b)("h4",{id:"deploy-your-environment-1"},"Deploy your environment"),Object(i.b)("p",null,"You can now deploy your environment.\nOnce it is ",Object(i.b)("inlineCode",{parentName:"p"},"RUNNING"),", you can open the UI again and check everything is ok.")))),Object(i.b)("h2",{id:"conclusion"},"Conclusion"),Object(i.b)("p",null,"We have successfully deployed Temporal on Qovery. It can be useful for Staging or Preview environments but this is a very minimal deployment and we would not advise doing it for production."),Object(i.b)("p",null,"There is no one-size-fits-all configuration for this type of products."),Object(i.b)("p",null,"You would probably like to setup authentication on your Web UI as well. We include the config file in the GitHub repository. You can edit it to your needs, following ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.temporal.io/docs/devtools/web-ui/#configuring-authentication"}),"this documentation"),"."),Object(i.b)("p",null,"For deploying on your Kubernetes cluster, check the ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.temporal.io/docs/server/production-deployment"}),"documentation")," and the following article: ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.temporal.io/blog/temporal-and-kubernetes"}),"https://docs.temporal.io/blog/temporal-and-kubernetes"),". The first video is worth watching."))}d.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=o.a.createContext({}),b=function(e){var t=o.a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},s=function(e){var t=b(e.components);return o.a.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,a=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),s=b(n),d=r,m=s["".concat(a,".").concat(d)]||s[d]||u[d]||i;return n?o.a.createElement(m,l({ref:t},p,{components:n})):o.a.createElement(m,l({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:r,a[1]=l;for(var p=2;p1?arguments[1]:void 0,n),c=a>2?arguments[2]:void 0,p=void 0===c?n:o(c,n);p>l;)t[l++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),i=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function i(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(o),i,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[i(t,e),"[",r,"]"].join(""):[i(t,e),"[",i(r,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return i(r,t);if(Array.isArray(o)){var a=[];return o.slice().forEach((function(e){void 0!==e&&a.push(n(r,e,a.length))})),a.join("&")}return i(r,t)+"="+i(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),i=(n(420),n(428)),a=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,c={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},p="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(c),b=Object(r.useState)(null),s=b[0],u=b[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!s&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return u("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:p,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==s&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 49a59b02.2a8666ba.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[86],{238:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return p})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return d}));var r=n(1),o=n(9),i=(n(0),n(425)),a=n(434),l=n(424),c=n(429),p={last_modified_on:"2022-03-16",$schema:"/.meta/.schemas/guides.json",title:"Deploy Temporal on Kubernetes",description:"How to deploy a Temporal.io server and UI on Qovery.",author_github:"https://github.com/l0ck3",tags:["type: tutorial","technology: qovery","database: postgresql"],hide_pagination:!0},b={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Deploy Temporal on Kubernetes",description:"How to deploy a Temporal.io server and UI on Qovery.",permalink:"/guides/tutorial/deploy-temporal-on-kubernetes",readingTime:"7 min read",source:"@site/guides/tutorial/deploy-temporal-on-kubernetes.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"},{label:"database: postgresql",permalink:"/guides/tags/database-postgresql"}],title:"Deploy Temporal on Kubernetes",truncated:!1,prevItem:{title:"Deploy Rails with PostgreSQL and Sidekiq",permalink:"/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq"},nextItem:{title:"Getting Started with Preview Environments on AWS",permalink:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners"}},s=[{value:"Goal",id:"goal",children:[]},{value:"Create the Qovery project and staging environment",id:"create-the-qovery-project-and-staging-environment",children:[]},{value:"Deploy Temporal server",id:"deploy-temporal-server",children:[]},{value:"Deploy the Web UI",id:"deploy-the-web-ui",children:[]},{value:"Deploy your environment",id:"deploy-your-environment",children:[]},{value:"Split the temporal services for independent scaling.",id:"split-the-temporal-services-for-independent-scaling",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],u={rightToc:s};function d(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(c.a,{name:"guide",mdxType:"Assumptions"},Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"You have a Qovery cluster ready"))),Object(i.b)("h2",{id:"goal"},"Goal"),Object(i.b)("p",null,"In this tutorial we will deploy ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://temporal.io"}),"Temporal.io")," on Qovery directly through the Qovery console.\nWe will first do a staging / preview env deployment then a multi-services deployment allowing to scale the different Temporal parts independently."),Object(i.b)(l.a,{type:"warning",mdxType:"Alert"},"Temporal.io is a complex product. Using it in production requires a good understanding of the project and its configuration options.",Object(i.b)("br",null),Object(i.b)("br",null),"This guide is useful if you want to deploy Temporal in your staging / preview environments. However, for production, you should install it directly on your Kubernetes cluster."),Object(i.b)("p",null,"You can find the official documentation for production deployment here: ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.temporal.io/docs/server/production-deployment"}),"https://docs.temporal.io/docs/server/production-deployment"),"."),Object(i.b)("h2",{id:"create-the-qovery-project-and-staging-environment"},"Create the Qovery project and staging environment"),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("h4",{id:"create-qovery-project"},"Create Qovery project"),Object(i.b)("p",null,"Head to the ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console")," and create a project:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/1.png",alt:"Qovery - Create Project"}))),Object(i.b)("li",null,Object(i.b)("h4",{id:"create-staging-environment"},"Create staging environment"),Object(i.b)("p",null,"Next create your staging environment:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/2.png",alt:"Qovery - Create Environment"}))))),Object(i.b)("h2",{id:"deploy-temporal-server"},"Deploy Temporal server"),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("h4",{id:"fork-the-example-github-repository"},"Fork the example GitHub repository"),Object(i.b)("p",null,"Go to ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-temporalio-example"}),"https://github.com/Qovery/qovery-temporalio-example")," and fork the repository."),Object(i.b)("p",null,"You can edit the tags in the Dockerfiles to match the latest versions. Check the latest tags here: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Server: ",Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.docker.com/r/temporalio/auto-setup/tags"}),"https://hub.docker.com/r/temporalio/auto-setup/tags")),Object(i.b)("li",{parentName:"ul"},"Web UI: ",Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.docker.com/r/temporalio/web/tags"}),"https://hub.docker.com/r/temporalio/web/tags")))),Object(i.b)("li",null,Object(i.b)("h4",{id:"create-the-temporal-server-application"},"Create the Temporal server application"),Object(i.b)("p",null,"Click on ",Object(i.b)("inlineCode",{parentName:"p"},"Create Application")," then fill the form:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Select your forked GitHub repository."),Object(i.b)("li",{parentName:"ul"},"Select ",Object(i.b)("inlineCode",{parentName:"li"},"Dockerfile")," as the build mode."),Object(i.b)("li",{parentName:"ul"},"Put ",Object(i.b)("inlineCode",{parentName:"li"},"7233")," as a port."),Object(i.b)("li",{parentName:"ul"},"Click ",Object(i.b)("inlineCode",{parentName:"li"},"Create"),".")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/3.png",alt:"Qovery - Create Application 1"})),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/4.png",alt:"Qovery - Create Application 2"})),Object(i.b)("p",null,"Your application is created:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/5.png",alt:"Qovery - Application Created"})),Object(i.b)("p",null,"Don't deploy it yet though. We still have a few steps to accomplish before.")),Object(i.b)("li",null,Object(i.b)("h4",{id:"update-the-port-settings"},"Update the port settings"),Object(i.b)("p",null,"First we will disable the public endpoint to the port."),Object(i.b)(l.a,{type:"warning",mdxType:"Alert"},"At the time of writing, Qovery doesn't support GRPC public endpoints. We disable the public endpoint since we can't use it from the outside."),Object(i.b)("p",null,"Click on ",Object(i.b)("inlineCode",{parentName:"p"},"Settings > Port"),", then on ",Object(i.b)("inlineCode",{parentName:"p"},"..."),", ",Object(i.b)("inlineCode",{parentName:"p"},"Advanced settings")," and uncheck ",Object(i.b)("inlineCode",{parentName:"p"},"Publicly"),".\nSave the settings and close the modal."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/6.png",alt:"Qovery - Disable Public Port"}))),Object(i.b)("li",null,Object(i.b)("h4",{id:"add-a-postgresql-database"},"Add a PostgreSQL database"),Object(i.b)("p",null,"We will now add a PostgreSQL database to serve as a persistence layer to our Temporal server."),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},"Temporal can also use MySQL or Cassandra as a persistence layer."),Object(i.b)("p",null,"Click on ",Object(i.b)("inlineCode",{parentName:"p"},"Add")," then ",Object(i.b)("inlineCode",{parentName:"p"},"Database")," then fill the form: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Pick a name for your DB."),Object(i.b)("li",{parentName:"ul"},"Type: PostgreSQL"),Object(i.b)("li",{parentName:"ul"},"Mode: Container (less expensive than Managed for non-production environments) "),Object(i.b)("li",{parentName:"ul"},"Version: 13"),Object(i.b)("li",{parentName:"ul"},"Accessibility: Private")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/7.png",alt:"Qovery - Add Database"})),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/8.png",alt:"Qovery - Configure PosgreSQL"})),Object(i.b)("p",null,"Your database is created:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/9.png",alt:"Qovery - Application Created"})),Object(i.b)("p",null,"Don't deploy it. We're not done setting-up our environment.")),Object(i.b)("li",null,Object(i.b)("h4",{id:"set-the-environment-variables"},"Set the environment variables"),Object(i.b)("p",null,"Now we need to set a bunch of environment variables.\nGo back to your Temporal server app and click on ",Object(i.b)("inlineCode",{parentName:"p"},"Environment variables"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/9.png",alt:"Qovery - Environment Variables"})),Object(i.b)(l.a,{type:"warning",mdxType:"Alert"},"Create all those env variables with the `ENVIRONMENT` scope. It will be useful when we split the server services, to avoid repeating the process for each app."),Object(i.b)("p",null,"Add the following environment variables: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"DB=postgresql")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"LOG_LEVEL=debug,info"))),Object(i.b)("p",null,"Now create the following aliases on environment variables:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_POSTGRESQL_Z[DB ID]_HOST_INTERNAL"),": ",Object(i.b)("inlineCode",{parentName:"li"},"POSTGRES_SEEDS")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_POSTGRESQL_[DB ID]_LOGIN"),": ",Object(i.b)("inlineCode",{parentName:"li"},"POSTGRES_USER")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_POSTGRESQL_[DB ID]_PORT"),": ",Object(i.b)("inlineCode",{parentName:"li"},"DB_PORT"))),Object(i.b)("p",null,"On an alias on secrets: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_POSTGRESQL_[DB ID]_PASSWORD"),": ",Object(i.b)("inlineCode",{parentName:"li"},"POSTGRES_PWD")))))),Object(i.b)("h2",{id:"deploy-the-web-ui"},"Deploy the Web UI"),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("h4",{id:"create-the-temporal-ui-application"},"Create the Temporal UI application"),Object(i.b)("p",null,"Now go to the environment level, and click on ",Object(i.b)("inlineCode",{parentName:"p"},"Add"),".\nSimilar to what you did for the server:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Select your forked GitHub repository."),Object(i.b)("li",{parentName:"ul"},"Select ",Object(i.b)("inlineCode",{parentName:"li"},"Dockerfile")," as the build mode."),Object(i.b)("li",{parentName:"ul"},"Put ",Object(i.b)("inlineCode",{parentName:"li"},"Dockerfile.web")," for the Dockerfile path."),Object(i.b)("li",{parentName:"ul"},"Put ",Object(i.b)("inlineCode",{parentName:"li"},"8088")," as a port."),Object(i.b)("li",{parentName:"ul"},"Click ",Object(i.b)("inlineCode",{parentName:"li"},"Create"),".")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/11.png",alt:"Qovery - Create application 1"})),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/12.png",alt:"Qovery - Create application 2"}))),Object(i.b)("li",null,Object(i.b)("h4",{id:"get-the-application-id-of-the-temporal-server"},"Get the application ID of the Temporal server"),Object(i.b)("p",null,"To get the application ID of the Temporal server, go back to the corresponding app, and note the first part of the UUID in the browser URL."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/13.png",alt:"Qovery - Get Application ID"})),Object(i.b)("p",null,"Copy this ID somewhere.")),Object(i.b)("li",null,Object(i.b)("h4",{id:"set-the-environment-variables-1"},"Set the environment variables"),Object(i.b)(l.a,{type:"warning",mdxType:"Alert"},"This time you can create the env variables with the `APPLICATION` scope."),Object(i.b)("p",null,"Add the following environment variable: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"TEMPORAL_SERVER_PORT"),": ",Object(i.b)("inlineCode",{parentName:"li"},"7233"))),Object(i.b)("p",null,"Now create the following alias on environment variables:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"QOVERY_APPLICATION_Z[SERVER APPLICATION ID]_HOST_INTERNAL"),": ",Object(i.b)("inlineCode",{parentName:"li"},"TEMPORAL_SERVER_HOST")))))),Object(i.b)("h2",{id:"deploy-your-environment"},"Deploy your environment"),Object(i.b)("p",null,"You can now deploy your environment. Go back to your environment view and click ",Object(i.b)("inlineCode",{parentName:"p"},"DEPLOY"),"."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/14.png",alt:"Qovery - Deploy Application"})),Object(i.b)("p",null,"Once it's deployed and the status is ",Object(i.b)("inlineCode",{parentName:"p"},"RUNNING"),", you can go to the Web UI application and open it."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/15.png",alt:"Qovery - Open Application"})),Object(i.b)("p",null,"If you see the Temporal Web UI with no error, well done. Your server is deployed!"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/16.png",alt:"Temporal - UI"})),Object(i.b)("h2",{id:"split-the-temporal-services-for-independent-scaling"},"Split the temporal services for independent scaling."),Object(i.b)("p",null,"Temporal server is composed of four different services. By default, they will all be running in the same process. But if you would like to scale them independently, you still have the option to deploy them separately."),Object(i.b)("p",null,"See the Temporal docs for more information on the architecture: ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.temporal.io/docs/concepts/what-is-a-temporal-cluster"}),"https://docs.temporal.io/docs/concepts/what-is-a-temporal-cluster")),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("h4",{id:"clone-your-environment"},"Clone your environment"),Object(i.b)("p",null,"We could start again from scratch or edit the running environment (which would require resetting the DB), but instead we will leverage the clone feature of Qovery, to start with an identical, clean environment."),Object(i.b)("p",null,"On your environment page, click ",Object(i.b)("inlineCode",{parentName:"p"},"Actions")," then ",Object(i.b)("inlineCode",{parentName:"p"},"Clone"),"."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/17.png",alt:"Qovery - Clone Environment"})),Object(i.b)("p",null,"Pick a name and click ",Object(i.b)("inlineCode",{parentName:"p"},"Create")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/18.png",alt:"Qovery - Clone Modal"})),Object(i.b)("p",null,"You will land in an identical environment, not deployed yet. Don't deploy it right away, we will first split our services.")),Object(i.b)("li",null,Object(i.b)("h4",{id:"switch-your-server-service-to-frontend-gateway"},"Switch your server service to frontend gateway"),Object(i.b)("p",null,"First we will rename the server application to call it ",Object(i.b)("inlineCode",{parentName:"p"},"temporal-frontend"),". Go to the server application and click ",Object(i.b)("inlineCode",{parentName:"p"},"Settings"),". Then change the name and save."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/19.png",alt:"Qovery - Clone Modal"}))),Object(i.b)("li",null,Object(i.b)("h4",{id:"add-an-env-variable-to-flag-the-service"},"Add an env variable to flag the service"),Object(i.b)("p",null,"In order to tell our application that it should only start the frontend service, we'll add an env variable with the ",Object(i.b)("inlineCode",{parentName:"p"},"APPLICATION")," scope: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"SERVICES=frontend"))),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},"You can run several services if you'd like, setting the variable with a value like `SERVICES=frontend,history`")),Object(i.b)("li",null,Object(i.b)("h4",{id:"create-the-other-services"},"Create the other services"),Object(i.b)("p",null,"Create three new application, following the steps you did for the server initially:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"temporal-history")," with an env variable ",Object(i.b)("inlineCode",{parentName:"li"},"SERVICES=history"),"."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"temporal-matching")," with an env variable ",Object(i.b)("inlineCode",{parentName:"li"},"SERVICES=matching"),"."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"temporal-worker")," with an env variable ",Object(i.b)("inlineCode",{parentName:"li"},"SERVICES=worker"),".")),Object(i.b)("p",null,"Each time set the port to ",Object(i.b)("inlineCode",{parentName:"p"},"7233")," and disable the public endpoint."),Object(i.b)("p",null,"You should end up with something like this: "),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deploy-temporalio/20.png",alt:"Qovery - Environment"}))),Object(i.b)("li",null,Object(i.b)("h4",{id:"deploy-your-environment-1"},"Deploy your environment"),Object(i.b)("p",null,"You can now deploy your environment.\nOnce it is ",Object(i.b)("inlineCode",{parentName:"p"},"RUNNING"),", you can open the UI again and check everything is ok.")))),Object(i.b)("h2",{id:"conclusion"},"Conclusion"),Object(i.b)("p",null,"We have successfully deployed Temporal on Qovery. It can be useful for Staging or Preview environments but this is a very minimal deployment and we would not advise doing it for production."),Object(i.b)("p",null,"There is no one-size-fits-all configuration for this type of products."),Object(i.b)("p",null,"You would probably like to setup authentication on your Web UI as well. We include the config file in the GitHub repository. You can edit it to your needs, following ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.temporal.io/docs/devtools/web-ui/#configuring-authentication"}),"this documentation"),"."),Object(i.b)("p",null,"For deploying on your Kubernetes cluster, check the ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.temporal.io/docs/server/production-deployment"}),"documentation")," and the following article: ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.temporal.io/blog/temporal-and-kubernetes"}),"https://docs.temporal.io/blog/temporal-and-kubernetes"),". The first video is worth watching."))}d.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=o.a.createContext({}),b=function(e){var t=o.a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},s=function(e){var t=b(e.components);return o.a.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,a=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),s=b(n),d=r,m=s["".concat(a,".").concat(d)]||s[d]||u[d]||i;return n?o.a.createElement(m,l({ref:t},p,{components:n})):o.a.createElement(m,l({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:r,a[1]=l;for(var p=2;p1?arguments[1]:void 0,n),c=a>2?arguments[2]:void 0,p=void 0===c?n:o(c,n);p>l;)t[l++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),i=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function i(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(o),i,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[i(t,e),"[",r,"]"].join(""):[i(t,e),"[",i(r,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return i(r,t);if(Array.isArray(o)){var a=[];return o.slice().forEach((function(e){void 0!==e&&a.push(n(r,e,a.length))})),a.join("&")}return i(r,t)+"="+i(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),i=(n(423),n(433)),a=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,c={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},p="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(c),b=Object(r.useState)(null),s=b[0],u=b[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!s&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return u("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:p,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==s&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/4f6caeac.2a2baf4a.js.LICENSE.txt b/49a59b02.2a8666ba.js.LICENSE.txt similarity index 100% rename from 4f6caeac.2a2baf4a.js.LICENSE.txt rename to 49a59b02.2a8666ba.js.LICENSE.txt diff --git a/49d2885e.021c659e.js b/49d2885e.13cefdf2.js similarity index 72% rename from 49d2885e.021c659e.js rename to 49d2885e.13cefdf2.js index e4ac9fb6b8..6b65429dbc 100644 --- a/49d2885e.021c659e.js +++ b/49d2885e.13cefdf2.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[85],{237:function(e){e.exports=JSON.parse('{"permalink":"/guides","page":1,"guidesPerPage":1,"totalPages":1,"totalCount":65,"previousPage":"/guides","nextPage":"/guides"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[87],{239:function(e){e.exports=JSON.parse('{"permalink":"/guides","page":1,"guidesPerPage":1,"totalPages":1,"totalCount":65,"previousPage":"/guides","nextPage":"/guides"}')}}]); \ No newline at end of file diff --git a/49dea187.9fe4c3a4.js b/49dea187.a7bbfdba.js similarity index 72% rename from 49dea187.9fe4c3a4.js rename to 49dea187.a7bbfdba.js index a000217661..33e7e2def8 100644 --- a/49dea187.9fe4c3a4.js +++ b/49dea187.a7bbfdba.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[86],{238:function(e){e.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"technology-helm","name":"technology: helm","count":1,"permalink":"/guides/tags/technology-helm"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[88],{240:function(e){e.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"technology-helm","name":"technology: helm","count":1,"permalink":"/guides/tags/technology-helm"}')}}]); \ No newline at end of file diff --git a/4a111132.6374df2a.js b/4a111132.3d895074.js similarity index 74% rename from 4a111132.6374df2a.js rename to 4a111132.3d895074.js index 3b0950cafc..dc0263dad1 100644 --- a/4a111132.6374df2a.js +++ b/4a111132.3d895074.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[87],{239:function(s){s.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"database-postgresql","name":"database: postgresql","count":3,"permalink":"/guides/tags/database-postgresql"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[89],{241:function(s){s.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"database-postgresql","name":"database: postgresql","count":3,"permalink":"/guides/tags/database-postgresql"}')}}]); \ No newline at end of file diff --git a/4ac9ee63.2f33f546.js b/4ac9ee63.0a853ad3.js similarity index 76% rename from 4ac9ee63.2f33f546.js rename to 4ac9ee63.0a853ad3.js index fc1b9dda59..64b0bda87f 100644 --- a/4ac9ee63.2f33f546.js +++ b/4ac9ee63.0a853ad3.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[88],{240:function(o){o.exports=JSON.parse('{"category":{"name":"cloud-provider","title":"Cloud Provider","description":"Install Qovery on your favorite cloud provider.","permalink":"/guides/cloud-provider"}}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[90],{242:function(o){o.exports=JSON.parse('{"category":{"name":"cloud-provider","title":"Cloud Provider","description":"Install Qovery on your favorite cloud provider.","permalink":"/guides/cloud-provider"}}')}}]); \ No newline at end of file diff --git a/4c0b3d74.d69fe30a.js b/4c0b3d74.87501e6a.js similarity index 73% rename from 4c0b3d74.d69fe30a.js rename to 4c0b3d74.87501e6a.js index 05e0f1b4c1..869c42c2b4 100644 --- a/4c0b3d74.d69fe30a.js +++ b/4c0b3d74.87501e6a.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[89],{241:function(o){o.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"technology-qovery","name":"technology: qovery","count":39,"permalink":"/guides/tags/technology-qovery"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[91],{243:function(o){o.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"technology-qovery","name":"technology: qovery","count":39,"permalink":"/guides/tags/technology-qovery"}')}}]); \ No newline at end of file diff --git a/4dcdbf34.a7699c8e.js b/4dcdbf34.809bec3d.js similarity index 95% rename from 4dcdbf34.a7699c8e.js rename to 4dcdbf34.809bec3d.js index cdd77732b2..37282ec3c5 100644 --- a/4dcdbf34.a7699c8e.js +++ b/4dcdbf34.809bec3d.js @@ -1,2 +1,2 @@ -/*! For license information please see 4dcdbf34.a7699c8e.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[90],{242:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return c})),t.d(n,"metadata",(function(){return l})),t.d(n,"rightToc",(function(){return p})),t.d(n,"default",(function(){return m}));var o=t(1),r=t(9),a=(t(0),t(422)),i=t(421),c={last_modified_on:"2023-09-27",title:"Jenkins",description:"Learn how to connect Jenkins to Qovery"},l={id:"using-qovery/integration/continuous-integration/jenkins",title:"Jenkins",description:"Learn how to connect Jenkins to Qovery",source:"@site/docs/using-qovery/integration/continuous-integration/jenkins.md",permalink:"/docs/using-qovery/integration/continuous-integration/jenkins",sidebar:"docs",previous:{title:"Circle CI",permalink:"/docs/using-qovery/integration/continuous-integration/circle-ci"},next:{title:"Monitoring",permalink:"/docs/using-qovery/integration/monitoring"}},p=[{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Jenkins Examples",id:"jenkins-examples",children:[]},{value:"Qovery CLI command examples",id:"qovery-cli-command-examples",children:[{value:"Deploy your application with a specific commit ID",id:"deploy-your-application-with-a-specific-commit-id",children:[]},{value:"Deploy your multiple applications with a different commit ID",id:"deploy-your-multiple-applications-with-a-different-commit-id",children:[]},{value:"Deploy your multiple applications with a specific commit ID (monorepo)",id:"deploy-your-multiple-applications-with-a-specific-commit-id-monorepo",children:[]},{value:"Create a Preview Environment for your Pull-Request",id:"create-a-preview-environment-for-your-pull-request",children:[]},{value:"Delete a Preview Environment",id:"delete-a-preview-environment",children:[]},{value:"Terraform",id:"terraform",children:[]},{value:"Any other examples?",id:"any-other-examples",children:[]}]}],u={rightToc:p};function m(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},u,t,{components:n,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Using Jenkins with Qovery is super powerful and gives you the ability to manage the way that you want to deploy your applications. As the possibility are endless, I will share with you a couple of examples that you can use. Feel free to adapt them to your need."),Object(a.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(a.b)("p",null,"Before using the examples below, you need to:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Install the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI"),"."),Object(a.b)("li",{parentName:"ol"},"Generate an API token via ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/#generate-api-token"}),"the CLI")," or the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/api-token/"}),"Console")," ."),Object(a.b)("li",{parentName:"ol"},"Set the environment variable ",Object(a.b)("inlineCode",{parentName:"li"},"Q_CLI_ACCESS_TOKEN")," or ",Object(a.b)("inlineCode",{parentName:"li"},"QOVERY_CLI_ACCESS_TOKEN")," (both are valid) with your API token. E.g. ",Object(a.b)("inlineCode",{parentName:"li"},"export QOVERY_CLI_ACCESS_TOKEN=your-api-token")),Object(a.b)("li",{parentName:"ol"},"You have turned off the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Qovery Auto Deployment")," for every service that you want to deploy manually.")),Object(a.b)("h2",{id:"jenkins-examples"},"Jenkins Examples"),Object(a.b)("p",null,"Since Jenkins also provides a .yaml file to configure your pipeline. Refers to ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/gitlab-ci/#gitlab-ci-examples"}),"GitLab CI")," and ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/#github-actions-examples"}),"GitHub Actions")," examples to learn how to configure your pipeline with Qovery."),Object(a.b)("h2",{id:"qovery-cli-command-examples"},"Qovery CLI command examples"),Object(a.b)("h3",{id:"deploy-your-application-with-a-specific-commit-id"},"Deploy your application with a specific commit ID"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"qovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n")),Object(a.b)(i.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,Object(a.b)("inlineCode",{parentName:"p"},"--watch")," is an optional parameter that will display the status of the deployment and return 0 if the deployment is successful or 1 if it fails.")),Object(a.b)("h3",{id:"deploy-your-multiple-applications-with-a-different-commit-id"},"Deploy your multiple applications with a different commit ID"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"# deploy the application 1 and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n\n# deploy the application 2 and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n")),Object(a.b)("p",null,"This is also applicable for the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery container deploy"),", ",Object(a.b)("inlineCode",{parentName:"p"},"qovery lifecycle deploy"),", and ",Object(a.b)("inlineCode",{parentName:"p"},"qovery cronjob deploy")," commands."),Object(a.b)("h3",{id:"deploy-your-multiple-applications-with-a-specific-commit-id-monorepo"},"Deploy your multiple applications with a specific commit ID (monorepo)"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),'# deploy the application 1, 2 and 3 with the same commit ID and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --applications ", , " \\\n --commit-id \\\n --watch\n')),Object(a.b)("p",null,"This is also applicable for the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery container deploy"),", ",Object(a.b)("inlineCode",{parentName:"p"},"qovery lifecycle deploy"),", and ",Object(a.b)("inlineCode",{parentName:"p"},"qovery cronjob deploy")," commands."),Object(a.b)("h3",{id:"create-a-preview-environment-for-your-pull-request"},"Create a Preview Environment for your Pull-Request"),Object(a.b)("p",null,"Qovery integrates automatically with GitHub, GitLab and Bitbucket to create a Preview Environment for each Pull-Request. But in case you want to control the creation of the Preview Environment manually, you can use the following commands:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"# Clone your base environment\nqovery environment clone \\\n --organization \\\n --project \\\n --environment \\\n --new-environment-name \n\n# Change your application branch to the Pull-Request branch\nqovery application update \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --branch \n\n# Deploy your new environment\nqovery environment deploy \\\n --organization \\\n --project \\\n --environment \\\n --watch\n")),Object(a.b)("h3",{id:"delete-a-preview-environment"},"Delete a Preview Environment"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"qovery environment delete \\\n --organization \\\n --project \\\n --environment \\\n --watch\n")),Object(a.b)("h3",{id:"terraform"},"Terraform"),Object(a.b)("p",null,"Do you want to include Terraform in your CI? Check out our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"Terraform documentation"),"."),Object(a.b)("h3",{id:"any-other-examples"},"Any other examples?"),Object(a.b)("p",null,"Feel free to share your examples with us, and we'll be happy to share them with the community. Contact us on ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum"),"."))}m.isMDXComponent=!0},420:function(e,n,t){var o;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var p=r.a.createContext({}),u=function(e){var n=r.a.useContext(p),t=n;return e&&(t="function"==typeof e?e(n):c({},n,{},e)),t},m=function(e){var n=u(e.components);return r.a.createElement(p.Provider,{value:n},e.children)},s={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},y=Object(o.forwardRef)((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),m=u(t),y=o,b=m["".concat(i,".").concat(y)]||m[y]||s[y]||a;return t?r.a.createElement(b,c({ref:n},p,{components:t})):r.a.createElement(b,c({ref:n},p))}));function b(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=y;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var p=2;p1?arguments[1]:void 0,t),l=i>2?arguments[2]:void 0,p=void 0===l?t:r(l,t);p>c;)n[c++]=e;return n}}}]); \ No newline at end of file +/*! For license information please see 4dcdbf34.809bec3d.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[92],{244:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return c})),t.d(n,"metadata",(function(){return l})),t.d(n,"rightToc",(function(){return p})),t.d(n,"default",(function(){return m}));var o=t(1),r=t(9),a=(t(0),t(425)),i=t(424),c={last_modified_on:"2023-09-27",title:"Jenkins",description:"Learn how to connect Jenkins to Qovery"},l={id:"using-qovery/integration/continuous-integration/jenkins",title:"Jenkins",description:"Learn how to connect Jenkins to Qovery",source:"@site/docs/using-qovery/integration/continuous-integration/jenkins.md",permalink:"/docs/using-qovery/integration/continuous-integration/jenkins",sidebar:"docs",previous:{title:"Circle CI",permalink:"/docs/using-qovery/integration/continuous-integration/circle-ci"},next:{title:"Monitoring",permalink:"/docs/using-qovery/integration/monitoring"}},p=[{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Jenkins Examples",id:"jenkins-examples",children:[]},{value:"Qovery CLI command examples",id:"qovery-cli-command-examples",children:[{value:"Deploy your application with a specific commit ID",id:"deploy-your-application-with-a-specific-commit-id",children:[]},{value:"Deploy your multiple applications with a different commit ID",id:"deploy-your-multiple-applications-with-a-different-commit-id",children:[]},{value:"Deploy your multiple applications with a specific commit ID (monorepo)",id:"deploy-your-multiple-applications-with-a-specific-commit-id-monorepo",children:[]},{value:"Create a Preview Environment for your Pull-Request",id:"create-a-preview-environment-for-your-pull-request",children:[]},{value:"Delete a Preview Environment",id:"delete-a-preview-environment",children:[]},{value:"Terraform",id:"terraform",children:[]},{value:"Any other examples?",id:"any-other-examples",children:[]}]}],u={rightToc:p};function m(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},u,t,{components:n,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Using Jenkins with Qovery is super powerful and gives you the ability to manage the way that you want to deploy your applications. As the possibility are endless, I will share with you a couple of examples that you can use. Feel free to adapt them to your need."),Object(a.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(a.b)("p",null,"Before using the examples below, you need to:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Install the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI"),"."),Object(a.b)("li",{parentName:"ol"},"Generate an API token via ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/#generate-api-token"}),"the CLI")," or the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/api-token/"}),"Console")," ."),Object(a.b)("li",{parentName:"ol"},"Set the environment variable ",Object(a.b)("inlineCode",{parentName:"li"},"Q_CLI_ACCESS_TOKEN")," or ",Object(a.b)("inlineCode",{parentName:"li"},"QOVERY_CLI_ACCESS_TOKEN")," (both are valid) with your API token. E.g. ",Object(a.b)("inlineCode",{parentName:"li"},"export QOVERY_CLI_ACCESS_TOKEN=your-api-token")),Object(a.b)("li",{parentName:"ol"},"You have turned off the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Qovery Auto Deployment")," for every service that you want to deploy manually.")),Object(a.b)("h2",{id:"jenkins-examples"},"Jenkins Examples"),Object(a.b)("p",null,"Since Jenkins also provides a .yaml file to configure your pipeline. Refers to ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/gitlab-ci/#gitlab-ci-examples"}),"GitLab CI")," and ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/#github-actions-examples"}),"GitHub Actions")," examples to learn how to configure your pipeline with Qovery."),Object(a.b)("h2",{id:"qovery-cli-command-examples"},"Qovery CLI command examples"),Object(a.b)("h3",{id:"deploy-your-application-with-a-specific-commit-id"},"Deploy your application with a specific commit ID"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"qovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n")),Object(a.b)(i.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,Object(a.b)("inlineCode",{parentName:"p"},"--watch")," is an optional parameter that will display the status of the deployment and return 0 if the deployment is successful or 1 if it fails.")),Object(a.b)("h3",{id:"deploy-your-multiple-applications-with-a-different-commit-id"},"Deploy your multiple applications with a different commit ID"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"# deploy the application 1 and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n\n# deploy the application 2 and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id \\\n --watch\n")),Object(a.b)("p",null,"This is also applicable for the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery container deploy"),", ",Object(a.b)("inlineCode",{parentName:"p"},"qovery lifecycle deploy"),", and ",Object(a.b)("inlineCode",{parentName:"p"},"qovery cronjob deploy")," commands."),Object(a.b)("h3",{id:"deploy-your-multiple-applications-with-a-specific-commit-id-monorepo"},"Deploy your multiple applications with a specific commit ID (monorepo)"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),'# deploy the application 1, 2 and 3 with the same commit ID and wait for the deployment to be successful with the --watch argument\nqovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --applications ", , " \\\n --commit-id \\\n --watch\n')),Object(a.b)("p",null,"This is also applicable for the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery container deploy"),", ",Object(a.b)("inlineCode",{parentName:"p"},"qovery lifecycle deploy"),", and ",Object(a.b)("inlineCode",{parentName:"p"},"qovery cronjob deploy")," commands."),Object(a.b)("h3",{id:"create-a-preview-environment-for-your-pull-request"},"Create a Preview Environment for your Pull-Request"),Object(a.b)("p",null,"Qovery integrates automatically with GitHub, GitLab and Bitbucket to create a Preview Environment for each Pull-Request. But in case you want to control the creation of the Preview Environment manually, you can use the following commands:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"# Clone your base environment\nqovery environment clone \\\n --organization \\\n --project \\\n --environment \\\n --new-environment-name \n\n# Change your application branch to the Pull-Request branch\nqovery application update \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --branch \n\n# Deploy your new environment\nqovery environment deploy \\\n --organization \\\n --project \\\n --environment \\\n --watch\n")),Object(a.b)("h3",{id:"delete-a-preview-environment"},"Delete a Preview Environment"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"qovery environment delete \\\n --organization \\\n --project \\\n --environment \\\n --watch\n")),Object(a.b)("h3",{id:"terraform"},"Terraform"),Object(a.b)("p",null,"Do you want to include Terraform in your CI? Check out our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"Terraform documentation"),"."),Object(a.b)("h3",{id:"any-other-examples"},"Any other examples?"),Object(a.b)("p",null,"Feel free to share your examples with us, and we'll be happy to share them with the community. Contact us on ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum"),"."))}m.isMDXComponent=!0},423:function(e,n,t){var o;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var p=r.a.createContext({}),u=function(e){var n=r.a.useContext(p),t=n;return e&&(t="function"==typeof e?e(n):c({},n,{},e)),t},m=function(e){var n=u(e.components);return r.a.createElement(p.Provider,{value:n},e.children)},s={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},y=Object(o.forwardRef)((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),m=u(t),y=o,b=m["".concat(i,".").concat(y)]||m[y]||s[y]||a;return t?r.a.createElement(b,c({ref:n},p,{components:t})):r.a.createElement(b,c({ref:n},p))}));function b(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=y;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var p=2;p1?arguments[1]:void 0,t),l=i>2?arguments[2]:void 0,p=void 0===l?t:r(l,t);p>c;)n[c++]=e;return n}}}]); \ No newline at end of file diff --git a/4fed1128.2afb42b2.js.LICENSE.txt b/4dcdbf34.809bec3d.js.LICENSE.txt similarity index 100% rename from 4fed1128.2afb42b2.js.LICENSE.txt rename to 4dcdbf34.809bec3d.js.LICENSE.txt diff --git a/4f6caeac.2a2baf4a.js b/4f6caeac.9a9801ea.js similarity index 93% rename from 4f6caeac.2a2baf4a.js rename to 4f6caeac.9a9801ea.js index 9c0791d24c..1bfd821716 100644 --- a/4f6caeac.2a2baf4a.js +++ b/4f6caeac.9a9801ea.js @@ -1,2 +1,2 @@ -/*! For license information please see 4f6caeac.2a2baf4a.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[91],{243:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return l})),a.d(t,"metadata",(function(){return i})),a.d(t,"rightToc",(function(){return o})),a.d(t,"default",(function(){return p}));var n=a(1),r=a(9),b=(a(0),a(422)),c=a(431),l=(a(429),a(421),a(426),{last_modified_on:"2023-09-04",title:"Service Advanced Settings",description:"Learn how to set advanced settings on your infrastructure with Qovery"}),i={id:"using-qovery/configuration/advanced-settings",title:"Service Advanced Settings",description:"Learn how to set advanced settings on your infrastructure with Qovery",source:"@site/docs/using-qovery/configuration/advanced-settings.md",permalink:"/docs/using-qovery/configuration/advanced-settings",sidebar:"docs",previous:{title:"Service Health Checks",permalink:"/docs/using-qovery/configuration/service-health-checks"},next:{title:"Object Storage",permalink:"/docs/using-qovery/configuration/object-storage"}},o=[{value:"Application Deployment",id:"application-deployment",children:[{value:"Deployment strategy",id:"deployment-strategy",children:[]}]},{value:"Network Settings",id:"network-settings",children:[]},{value:"Auto-scaling",id:"auto-scaling",children:[]},{value:"Job Settings",id:"job-settings",children:[]},{value:"Security",id:"security",children:[]}],s={rightToc:o};function p(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(b.b)("wrapper",Object(n.a)({},s,a,{components:t,mdxType:"MDXLayout"}),Object(b.b)("p",null,"To further fine-tune your Qovery infrastructure, you can set advanced settings through the Advanced Settings section of your service."),Object(b.b)("p",null,"To access the Advanced Settings section:"),Object(b.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(b.b)("ol",null,Object(b.b)("li",null,Object(b.b)("p",null,"Select the service where you want to modify the advanced settings"),Object(b.b)("p",{align:"center"},Object(b.b)("img",{src:"/img/configuration/advanced-settings/settings.png",alt:"Settings"}))),Object(b.b)("li",null,Object(b.b)("p",null,"Open the advanced settings section from the left menu"),Object(b.b)("p",{align:"center"},Object(b.b)("img",{src:"/img/configuration/advanced-settings/advanced_settings.png",alt:"Advanced Settings"}))))),Object(b.b)("p",null,"The screen shows you the list of available advanced settings and for each of them:"),Object(b.b)("ul",null,Object(b.b)("li",{parentName:"ul"},"The default value"),Object(b.b)("li",{parentName:"ul"},"The value configured right now")),Object(b.b)("p",null,'You can show only the modified values by activating the "Show only overridden settings" feature toggle.'),Object(b.b)("p",null,"All services have access to advanced settings, you can find where they are available in the documentation below with those badges:"),Object(b.b)("h4",{id:""},Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("h2",{id:"application-deployment"},"Application Deployment"),Object(b.b)("h4",{id:"buildtimeout_max_sec"},"build.timeout_max_sec ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to specify an interval, in seconds, after which the application build times out."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"1800"))))),Object(b.b)("h4",{id:"buildcpu_max_in_milli"},"build.cpu_max_in_milli ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"CPU allocated to your build process"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"4000"))))),Object(b.b)("h4",{id:"buildram_max_in_gib"},"build.ram_max_in_gib ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"GB RAM allocated to your build process"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"8"))))),Object(b.b)("h4",{id:"deploymentcustom_domain_check_enabled"},"deployment.custom_domain_check_enabled ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"boolean"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery allows you to set custom domains for your applications through the addition of a CNAME record to your domain's DNS settings. By default, when an application is deployed, Qovery checks that the CNAME record is set up correctly. This advanced setting allows you to disable this check."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"If you are using a Content Delivery Network (CDN), checking the CNAME setup for any custom domains you may have set up is likely to stall the deployment of your application. ",Object(b.b)("br",null)," ",Object(b.b)("br",null)," Therefore, if you are using a CDN behind your application, we recommend disabling this feature to save time during your application deployments."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"true"))))),Object(b.b)("h4",{id:"deploymenttermination_grace_period_seconds"},"deployment.termination_grace_period_seconds ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Decide how many times in seconds the application is supposed to stop at maximum. After this time, the application will be forced to stop (killed)"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"An application requiring several tasks to be stopped properly should have a higher grace period. If the application finishes early, then it will not wait until the end of the grace period"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"60"))))),Object(b.b)("h4",{id:"deploymentaffinitynoderequired"},"deployment.affinity.node.required ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Map"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Set pod placement on specific Kubernetes nodes labels."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Can be useful to send pods on GPU nodes or any other specific workload based on node lablels (Eg. ",Object(b.b)("inlineCode",{parentName:"td"},'{"eks.amazonaws.com/nodegroup": "gpu"}'),")"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"``")))),Object(b.b)("h4",{id:"deploymentantiaffinitypod"},"deployment.antiaffinity.pod ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Define how you want pods affinity to behave.",Object(b.b)("br",null),"\u2022 ",Object(b.b)("inlineCode",{parentName:"td"},"Preferred"),": allows, but does not require, pods of a given service are not co-located (or co-hosted) on a single node",Object(b.b)("br",null),"\u2022 ",Object(b.b)("inlineCode",{parentName:"td"},"Required"),": ensures that the pods of a given service are not co-located (or co-hosted) on a single node (safer in term of availability but can be expensive depending on the number of replicas)"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"Preferred"))))),Object(b.b)("h3",{id:"deployment-strategy"},"Deployment strategy"),Object(b.b)("h4",{id:"deploymentupdate_strategytype"},"deployment.update_strategy.type ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Set deployment strategy type (",Object(b.b)("inlineCode",{parentName:"td"},"RollingUpdate")," or ",Object(b.b)("inlineCode",{parentName:"td"},"Recreate"),")"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Rolling update strategy will gracefully rollout new versions, while Recreate will stop all current versions and create new ones once all old ones have been shutdown (",Object(b.b)("a",Object(n.a)({parentName:"td"},{href:"/docs/using-qovery/deployment/deployment-strategies/"}),"more info"),")"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"RollingUpdate"))))),Object(b.b)("h4",{id:"deploymentupdate_strategyrolling_updatemax_unavailable_percent"},"deployment.update_strategy.rolling_update.max_unavailable_percent ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Define the percentage of a maximum number of pods that can be unavailable during the update process (",Object(b.b)("a",Object(n.a)({parentName:"td"},{href:"https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#max-unavailable"}),"more info"),")."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"25"))))),Object(b.b)("h4",{id:"deploymentupdate_strategyrolling_updatemax_surge_percent"},"deployment.update_strategy.rolling_update.max_surge_percent ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Define the percentage of the maximum number of pods that can be created over the desired number of pods (",Object(b.b)("a",Object(n.a)({parentName:"td"},{href:"https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#max-surge"}),"more info"),")"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"25"))))),Object(b.b)("h2",{id:"network-settings"},"Network Settings"),Object(b.b)("h4",{id:"networkingresscors_allow_headers"},"network.ingress.cors_allow_headers ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("em",{parentName:"td"},"(For CORS users)")," Allows you to specify which set of headers can be present in the client request."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"For security purposes, you can indicate which HTTP headers can be used during a CORS preflight request which includes the ",Object(b.b)("inlineCode",{parentName:"td"},"Access-Control-Request-Headers")," request header. For more information, see ",Object(b.b)("a",Object(n.a)({parentName:"td"},{href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#the_http_response_headers"}),"CORS HTTP Response Headers"),"."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},'"DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization"'))))),Object(b.b)("h4",{id:"networkingresscors_allow_methods"},"network.ingress.cors_allow_methods ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("em",{parentName:"td"},"(For CORS users)")," Allows you to specify which set of methods can be used for the client request."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"For security purposes, you can indicate which HTTP methods are permitted while accessing a resource in response to cross-origin requests. For more information, see ",Object(b.b)("a",Object(n.a)({parentName:"td"},{href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#the_http_response_headers"}),"CORS HTTP Response Headers"),"."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},'"GET, PUT, POST, DELETE, PATCH, OPTIONS"'))))),Object(b.b)("h4",{id:"networkingresscors_allow_origin"},"network.ingress.cors_allow_origin ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("em",{parentName:"td"},"(For CORS users)")," Allows you to specify which origin(s) (domain, scheme, port) can access a resource."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"For security purposes, you can allow only one or a short list of origins to access your resources. For more information, see ",Object(b.b)("a",Object(n.a)({parentName:"td"},{href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#the_http_response_headers"}),"CORS HTTP Response Headers"),"."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},'"*"'))))),Object(b.b)("h4",{id:"networkingressenable_cors"},"network.ingress.enable_cors ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"boolean"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to enable Cross-Origin Resource Sharing (CORS)."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The CORS mechanism supports secure cross-origin requests and data transfers between browsers and servers. For more information on CORS and when to enable it, see ",Object(b.b)("a",Object(n.a)({parentName:"td"},{href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"}),"Cross-Origin Resources Sharing"),"."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"false"))))),Object(b.b)("h4",{id:"networkingressenable_sticky_session"},"network.ingress.enable_sticky_session ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"boolean"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to enable Sticky session."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Enable the load balancer to bind a user's session to a specific target. This ensures that all requests from the user during the session are sent to the same target"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"false"))))),Object(b.b)("h4",{id:"networkingresskeepalive_time_seconds"},"network.ingress.keepalive_time_seconds ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Limits the maximum time (in seconds) during which requests can be processed through one keepalive connection. After this time is reached, the connection is closed following the subsequent request processing."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Useful to tune your gRPC application"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"3600"))))),Object(b.b)("h4",{id:"networkingresskeepalive_timeout_seconds"},"network.ingress.keepalive_timeout_seconds ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Sets a timeout (in seconds) during which an idle keepalive connection to an upstream server will stay open."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Useful to tune your gRPC application"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"60"))))),Object(b.b)("h4",{id:"networkingressproxy_body_size_mb"},"network.ingress.proxy_body_size_mb ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to set, in megabytes, a maximum size for resources that can be downloaded from your server."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"By default, users can download resources (files, images, videos...) of up to 100 MB. You can use this advanced setting to lower or increase this limitation."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"100"))))),Object(b.b)("h4",{id:"networkingressproxy_buffer_size_kb"},"network.ingress.proxy_buffer_size_kb ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to set, in kilobytes, a header buffer size used while reading the response header from upstream."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"E.g. You are using Auth0 with NextJS, you will need to set a bigger header size"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"4"))))),Object(b.b)("h4",{id:"networkingressproxy_connect_timeout_seconds"},"network.ingress.proxy_connect_timeout_seconds ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Defines a timeout (in seconds) for establishing a connection with a proxied server. It should be noted that this timeout cannot usually exceed 75 seconds."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"E.g. You can use it to define the maximum time to wait for your application to establish the connexion."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"60"))))),Object(b.b)("h4",{id:"networkingressproxy_read_timeout_seconds"},"network.ingress.proxy_read_timeout_seconds ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Defines a timeout for reading a response from the proxied server. The timeout is set only between two successive read operations, not for the transmission of the whole response. If the proxied server does not transmit anything within this time, the connection is closed."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"E.g. You can use it to fine-tune your WebSocket application."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"60"))))),Object(b.b)("h4",{id:"networkingressproxy_send_timeout_seconds"},"network.ingress.proxy_send_timeout_seconds ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Sets a timeout (in seconds) for transmitting a request to the proxied server. The timeout is set only between two successive write operations, not for the transmission of the whole request. If the proxied server does not receive anything within this time, the connection is closed."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"E.g. You can use it to fine-tune your WebSocket application."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"60"))))),Object(b.b)("h4",{id:"networkingressproxy_buffering"},"network.ingress.proxy_buffering ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to enable or disable nginx ",Object(b.b)("inlineCode",{parentName:"td"},"proxy-buffering"),". Valid values are ",Object(b.b)("inlineCode",{parentName:"td"},"on")," or ",Object(b.b)("inlineCode",{parentName:"td"},"off")),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"on"))))),Object(b.b)("h4",{id:"networkingressproxy_request_buffering"},"network.ingress.proxy_request_buffering ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to enable or disable nginx ",Object(b.b)("inlineCode",{parentName:"td"},"proxy-request_buffering"),". Valid values are ",Object(b.b)("inlineCode",{parentName:"td"},"on")," or ",Object(b.b)("inlineCode",{parentName:"td"},"off")),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"on"))))),Object(b.b)("h4",{id:"networkingresssend_timeout_seconds"},"network.ingress.send_timeout_seconds ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Sets a timeout (in seconds) for transmitting a response to the client. The timeout is set only between two successive write operations, not for the transmission of the whole response. If the client does not receive anything within this time, the connection is closed."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Useful to define the maximum timeout to wait for client connection."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"60"))))),Object(b.b)("h4",{id:"networkingresswhitelist_source_range"},"network.ingress.whitelist_source_range ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to specify which IP ranges are allowed to access your application. The value is a comma-separated list of CIDRs, e.g. ",Object(b.b)("inlineCode",{parentName:"td"},"10.0.0.0/24,172.10.0.1")),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"By default, any IP can access your application if it's exposed publicly and the users know the URL. You can limit its access by specifying the IPs you want to reach the app (e.g. the IP of your office)"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"0.0.0.0/0")," (any IP)")))),Object(b.b)("h4",{id:"networkingressdenylist_source_range"},"network.ingress.denylist_source_range ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to specify which IP ranges are not allowed to access your application. The value is a comma-separated list of CIDRs, e.g. ",Object(b.b)("inlineCode",{parentName:"td"},"10.0.0.0/24,172.10.0.1")),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"``")))),Object(b.b)("h4",{id:"networkingressbasic_auth_env_var"},"network.ingress.basic_auth_env_var ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Set the name of an environment variable to use as a basic authentication (",Object(b.b)("inlineCode",{parentName:"td"},"login:crypted_password"),") from ",Object(b.b)("inlineCode",{parentName:"td"},"htpasswd")," command."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"``")))),Object(b.b)("p",null,"Here is an example where you can create a secret environment variable on Qovery and set a name like ",Object(b.b)("inlineCode",{parentName:"p"},"BASIC_AUTH_CREDENTIALS"),". The content should be the result of the ",Object(b.b)("inlineCode",{parentName:"p"},"htpasswd")," command:"),Object(b.b)("pre",null,Object(b.b)("code",Object(n.a)({parentName:"pre"},{}),"$ htpasswd -n \nNew password:\nRe-type new password:\nusername:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20\n")),Object(b.b)("p",null,"The content of the ",Object(b.b)("inlineCode",{parentName:"p"},"BASIC_AUTH_CREDENTIALS")," environment variable should be: ",Object(b.b)("inlineCode",{parentName:"p"},"username:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20"),". To finish, set the ",Object(b.b)("a",Object(n.a)({parentName:"p"},{href:"#networkingressbasic_auth_env_var"}),Object(b.b)("inlineCode",{parentName:"a"},"network.ingress.basic_auth_env_var"))," advanced settings to ",Object(b.b)("inlineCode",{parentName:"p"},"BASIC_AUTH_CREDENTIALS"),"."),Object(b.b)("p",null,"You can pass set credentials by separating them with a comma. For example: ",Object(b.b)("inlineCode",{parentName:"p"},"username1:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20,username2:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20"),". However, the total length of the environment variable should not exceed 1MB."),Object(b.b)("h4",{id:"networkingressextra_headers"},"network.ingress.extra_headers ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to specify response headers with values separated by comma (e.g. ",Object(b.b)("inlineCode",{parentName:"td"},' {"X-Frame-Options":"DENY","X-Content-Type-Options":"nosniff"}')),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"{}"))))),Object(b.b)("h2",{id:"auto-scaling"},"Auto-scaling"),Object(b.b)("h4",{id:"hpacpuaverage_utilization_percent"},"hpa.cpu.average_utilization_percent ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Auto-scaling is triggered when a specific CPU utilization metric is reached (for instance, 40%). This advanced setting allows you to set this metric."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"60"))))),Object(b.b)("h2",{id:"job-settings"},"Job Settings"),Object(b.b)("h4",{id:"jobdelete_ttl_seconds_after_finished"},"job.delete_ttl_seconds_after_finished ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"By default terminated jobs in a completed or failure state are not deleted. if this parameter is set, Kubernetes will automatically cleanup completed jobs after the ttl"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"null"))))),Object(b.b)("h4",{id:"cronjobconcurrency_policy"},"cronjob.concurrency_policy ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"It defines if it is allowed to start another instance of the same job if the previous execution didn't finish yet: ",Object(b.b)("inlineCode",{parentName:"td"},"Allow"),"/",Object(b.b)("inlineCode",{parentName:"td"},"Forbid"),"/",Object(b.b)("inlineCode",{parentName:"td"},"Replace"),")"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"Forbidden"))))),Object(b.b)("h4",{id:"cronjobfailed_job_history_limit"},"cronjob.failed_job_history_limit ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to define the maximum number of failed job executions that should be returned in the job execution history"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"1"))))),Object(b.b)("h4",{id:"cronjobsuccess_job_history_limit"},"cronjob.success_job_history_limit ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to define the maximum number of succeeded job executions that should be returned in the job execution history"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"1"))))),Object(b.b)("h2",{id:"security"},"Security"),Object(b.b)("h4",{id:"securityservice_account_name"},"security.service_account_name ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to set an existing Kubernetes service account name"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"E.g. On AWS, you can assume a role on an application to give it specific AWS permissions without having to specify AWS credentials"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"``")))))}p.isMDXComponent=!0},420:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var b=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var o=r.a.createContext({}),s=function(e){var t=r.a.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):l({},t,{},e)),a},p=function(e){var t=s(e.components);return r.a.createElement(o.Provider,{value:t},e.children)},j={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,b=e.originalType,c=e.parentName,o=i(e,["components","mdxType","originalType","parentName"]),p=s(a),d=n,m=p["".concat(c,".").concat(d)]||p[d]||j[d]||b;return a?r.a.createElement(m,l({ref:t},o,{components:a})):r.a.createElement(m,l({ref:t},o))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var b=a.length,c=new Array(b);c[0]=d;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l.mdxType="string"==typeof e?e:n,c[1]=l;for(var o=2;o1?arguments[1]:void 0,a),i=c>2?arguments[2]:void 0,o=void 0===i?a:r(i,a);o>l;)t[l++]=e;return t}},425:function(e,t,a){var n=a(28).f,r=Function.prototype,b=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(b)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var n=a(0),r=a.n(n),b=a(421);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(b.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},427:function(e,t,a){"use strict";var n=a(1),r=a(0),b=a.n(r),c=a(39),l=a(430),i=a(20),o=a.n(i);t.a=function(e){var t,a=e.to,i=e.href,s=a||i,p=Object(l.a)(s),j=Object(r.useRef)(!1),d=o.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(s),function(){d&&t&&t.disconnect()}}),[s,d,p]),s&&p?b.a.createElement(c.b,Object(n.a)({},e,{onMouseEnter:function(){j.current||(window.docusaurus.preload(s),j.current=!0)},innerRef:function(e){var a,n;d&&e&&p&&(a=e,n=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:s})):b.a.createElement("a",Object(n.a)({},e,{href:s}))}},428:function(e,t,a){"use strict";var n=a(432),r=a(51);function b(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var a=function(e){var t;switch(e.arrayFormat){case"index":return function(e,a,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=a):n[e]=a};case"bracket":return function(e,a,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],a):n[e]=[a]:n[e]=a};default:return function(e,t,a){void 0!==a[e]?a[e]=[].concat(a[e],t):a[e]=t}}}(t=r({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),b=t.length>0?t.join("="):void 0;b=void 0===b?null:decodeURIComponent(b),a(decodeURIComponent(r),b,n)})),Object.keys(n).sort().reduce((function(e,t){var a=n[t];return Boolean(a)&&"object"==typeof a&&!Array.isArray(a)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(a):e[t]=a,e}),Object.create(null))):n},t.stringify=function(e,t){var a=function(e){switch(e.arrayFormat){case"index":return function(t,a,n){return null===a?[b(t,e),"[",n,"]"].join(""):[b(t,e),"[",b(n,e),"]=",b(a,e)].join("")};case"bracket":return function(t,a){return null===a?b(t,e):[b(t,e),"[]=",b(a,e)].join("")};default:return function(t,a){return null===a?b(t,e):[b(t,e),"=",b(a,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var r=e[n];if(void 0===r)return"";if(null===r)return b(n,t);if(Array.isArray(r)){var c=[];return r.slice().forEach((function(e){void 0!==e&&c.push(a(n,e,c.length))})),c.join("&")}return b(n,t)+"="+b(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,a){"use strict";var n=a(0),r=a.n(n),b=a(427),c=a(420),l=a.n(c);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,c=e.leftIcon,i=e.rightIcon,o=e.size,s=e.target,p=e.to,j=l()("jump-to","jump-to--"+o,a),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(i||"chevron-right")+" arrow"}))));return s?r.a.createElement("a",{href:p,target:s,className:j},d):r.a.createElement(b.a,{to:p,className:j},d)}},430:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},431:function(e,t,a){"use strict";var n=a(0),r=a.n(n),b=(a(420),a(428)),c=a.n(b);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,b=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,i={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},o="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(i),s=Object(n.useState)(null),p=s[0],j=s[1];return r.a.createElement("div",{className:"steps steps--h"+a},t,!b&&!p&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return j("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:o,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,a){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 4f6caeac.9a9801ea.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[93],{245:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return l})),a.d(t,"metadata",(function(){return i})),a.d(t,"rightToc",(function(){return o})),a.d(t,"default",(function(){return p}));var n=a(1),r=a(9),b=(a(0),a(425)),c=a(434),l=(a(431),a(424),a(429),{last_modified_on:"2023-09-04",title:"Service Advanced Settings",description:"Learn how to set advanced settings on your infrastructure with Qovery"}),i={id:"using-qovery/configuration/advanced-settings",title:"Service Advanced Settings",description:"Learn how to set advanced settings on your infrastructure with Qovery",source:"@site/docs/using-qovery/configuration/advanced-settings.md",permalink:"/docs/using-qovery/configuration/advanced-settings",sidebar:"docs",previous:{title:"Service Health Checks",permalink:"/docs/using-qovery/configuration/service-health-checks"},next:{title:"Object Storage",permalink:"/docs/using-qovery/configuration/object-storage"}},o=[{value:"Application Deployment",id:"application-deployment",children:[{value:"Deployment strategy",id:"deployment-strategy",children:[]}]},{value:"Network Settings",id:"network-settings",children:[]},{value:"Auto-scaling",id:"auto-scaling",children:[]},{value:"Job Settings",id:"job-settings",children:[]},{value:"Security",id:"security",children:[]}],s={rightToc:o};function p(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(b.b)("wrapper",Object(n.a)({},s,a,{components:t,mdxType:"MDXLayout"}),Object(b.b)("p",null,"To further fine-tune your Qovery infrastructure, you can set advanced settings through the Advanced Settings section of your service."),Object(b.b)("p",null,"To access the Advanced Settings section:"),Object(b.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(b.b)("ol",null,Object(b.b)("li",null,Object(b.b)("p",null,"Select the service where you want to modify the advanced settings"),Object(b.b)("p",{align:"center"},Object(b.b)("img",{src:"/img/configuration/advanced-settings/settings.png",alt:"Settings"}))),Object(b.b)("li",null,Object(b.b)("p",null,"Open the advanced settings section from the left menu"),Object(b.b)("p",{align:"center"},Object(b.b)("img",{src:"/img/configuration/advanced-settings/advanced_settings.png",alt:"Advanced Settings"}))))),Object(b.b)("p",null,"The screen shows you the list of available advanced settings and for each of them:"),Object(b.b)("ul",null,Object(b.b)("li",{parentName:"ul"},"The default value"),Object(b.b)("li",{parentName:"ul"},"The value configured right now")),Object(b.b)("p",null,'You can show only the modified values by activating the "Show only overridden settings" feature toggle.'),Object(b.b)("p",null,"All services have access to advanced settings, you can find where they are available in the documentation below with those badges:"),Object(b.b)("h4",{id:""},Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("h2",{id:"application-deployment"},"Application Deployment"),Object(b.b)("h4",{id:"buildtimeout_max_sec"},"build.timeout_max_sec ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to specify an interval, in seconds, after which the application build times out."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"1800"))))),Object(b.b)("h4",{id:"buildcpu_max_in_milli"},"build.cpu_max_in_milli ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"CPU allocated to your build process"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"4000"))))),Object(b.b)("h4",{id:"buildram_max_in_gib"},"build.ram_max_in_gib ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"GB RAM allocated to your build process"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"8"))))),Object(b.b)("h4",{id:"deploymentcustom_domain_check_enabled"},"deployment.custom_domain_check_enabled ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"boolean"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery allows you to set custom domains for your applications through the addition of a CNAME record to your domain's DNS settings. By default, when an application is deployed, Qovery checks that the CNAME record is set up correctly. This advanced setting allows you to disable this check."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"If you are using a Content Delivery Network (CDN), checking the CNAME setup for any custom domains you may have set up is likely to stall the deployment of your application. ",Object(b.b)("br",null)," ",Object(b.b)("br",null)," Therefore, if you are using a CDN behind your application, we recommend disabling this feature to save time during your application deployments."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"true"))))),Object(b.b)("h4",{id:"deploymenttermination_grace_period_seconds"},"deployment.termination_grace_period_seconds ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Decide how many times in seconds the application is supposed to stop at maximum. After this time, the application will be forced to stop (killed)"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"An application requiring several tasks to be stopped properly should have a higher grace period. If the application finishes early, then it will not wait until the end of the grace period"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"60"))))),Object(b.b)("h4",{id:"deploymentaffinitynoderequired"},"deployment.affinity.node.required ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Map"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Set pod placement on specific Kubernetes nodes labels."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Can be useful to send pods on GPU nodes or any other specific workload based on node lablels (Eg. ",Object(b.b)("inlineCode",{parentName:"td"},'{"eks.amazonaws.com/nodegroup": "gpu"}'),")"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"``")))),Object(b.b)("h4",{id:"deploymentantiaffinitypod"},"deployment.antiaffinity.pod ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Define how you want pods affinity to behave.",Object(b.b)("br",null),"\u2022 ",Object(b.b)("inlineCode",{parentName:"td"},"Preferred"),": allows, but does not require, pods of a given service are not co-located (or co-hosted) on a single node",Object(b.b)("br",null),"\u2022 ",Object(b.b)("inlineCode",{parentName:"td"},"Required"),": ensures that the pods of a given service are not co-located (or co-hosted) on a single node (safer in term of availability but can be expensive depending on the number of replicas)"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"Preferred"))))),Object(b.b)("h3",{id:"deployment-strategy"},"Deployment strategy"),Object(b.b)("h4",{id:"deploymentupdate_strategytype"},"deployment.update_strategy.type ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Set deployment strategy type (",Object(b.b)("inlineCode",{parentName:"td"},"RollingUpdate")," or ",Object(b.b)("inlineCode",{parentName:"td"},"Recreate"),")"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Rolling update strategy will gracefully rollout new versions, while Recreate will stop all current versions and create new ones once all old ones have been shutdown (",Object(b.b)("a",Object(n.a)({parentName:"td"},{href:"/docs/using-qovery/deployment/deployment-strategies/"}),"more info"),")"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"RollingUpdate"))))),Object(b.b)("h4",{id:"deploymentupdate_strategyrolling_updatemax_unavailable_percent"},"deployment.update_strategy.rolling_update.max_unavailable_percent ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Define the percentage of a maximum number of pods that can be unavailable during the update process (",Object(b.b)("a",Object(n.a)({parentName:"td"},{href:"https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#max-unavailable"}),"more info"),")."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"25"))))),Object(b.b)("h4",{id:"deploymentupdate_strategyrolling_updatemax_surge_percent"},"deployment.update_strategy.rolling_update.max_surge_percent ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Define the percentage of the maximum number of pods that can be created over the desired number of pods (",Object(b.b)("a",Object(n.a)({parentName:"td"},{href:"https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#max-surge"}),"more info"),")"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"25"))))),Object(b.b)("h2",{id:"network-settings"},"Network Settings"),Object(b.b)("h4",{id:"networkingresscors_allow_headers"},"network.ingress.cors_allow_headers ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("em",{parentName:"td"},"(For CORS users)")," Allows you to specify which set of headers can be present in the client request."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"For security purposes, you can indicate which HTTP headers can be used during a CORS preflight request which includes the ",Object(b.b)("inlineCode",{parentName:"td"},"Access-Control-Request-Headers")," request header. For more information, see ",Object(b.b)("a",Object(n.a)({parentName:"td"},{href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#the_http_response_headers"}),"CORS HTTP Response Headers"),"."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},'"DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization"'))))),Object(b.b)("h4",{id:"networkingresscors_allow_methods"},"network.ingress.cors_allow_methods ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("em",{parentName:"td"},"(For CORS users)")," Allows you to specify which set of methods can be used for the client request."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"For security purposes, you can indicate which HTTP methods are permitted while accessing a resource in response to cross-origin requests. For more information, see ",Object(b.b)("a",Object(n.a)({parentName:"td"},{href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#the_http_response_headers"}),"CORS HTTP Response Headers"),"."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},'"GET, PUT, POST, DELETE, PATCH, OPTIONS"'))))),Object(b.b)("h4",{id:"networkingresscors_allow_origin"},"network.ingress.cors_allow_origin ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("em",{parentName:"td"},"(For CORS users)")," Allows you to specify which origin(s) (domain, scheme, port) can access a resource."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"For security purposes, you can allow only one or a short list of origins to access your resources. For more information, see ",Object(b.b)("a",Object(n.a)({parentName:"td"},{href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#the_http_response_headers"}),"CORS HTTP Response Headers"),"."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},'"*"'))))),Object(b.b)("h4",{id:"networkingressenable_cors"},"network.ingress.enable_cors ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"boolean"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to enable Cross-Origin Resource Sharing (CORS)."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The CORS mechanism supports secure cross-origin requests and data transfers between browsers and servers. For more information on CORS and when to enable it, see ",Object(b.b)("a",Object(n.a)({parentName:"td"},{href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"}),"Cross-Origin Resources Sharing"),"."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"false"))))),Object(b.b)("h4",{id:"networkingressenable_sticky_session"},"network.ingress.enable_sticky_session ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"boolean"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to enable Sticky session."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Enable the load balancer to bind a user's session to a specific target. This ensures that all requests from the user during the session are sent to the same target"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"false"))))),Object(b.b)("h4",{id:"networkingresskeepalive_time_seconds"},"network.ingress.keepalive_time_seconds ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Limits the maximum time (in seconds) during which requests can be processed through one keepalive connection. After this time is reached, the connection is closed following the subsequent request processing."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Useful to tune your gRPC application"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"3600"))))),Object(b.b)("h4",{id:"networkingresskeepalive_timeout_seconds"},"network.ingress.keepalive_timeout_seconds ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Sets a timeout (in seconds) during which an idle keepalive connection to an upstream server will stay open."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Useful to tune your gRPC application"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"60"))))),Object(b.b)("h4",{id:"networkingressproxy_body_size_mb"},"network.ingress.proxy_body_size_mb ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to set, in megabytes, a maximum size for resources that can be downloaded from your server."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"By default, users can download resources (files, images, videos...) of up to 100 MB. You can use this advanced setting to lower or increase this limitation."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"100"))))),Object(b.b)("h4",{id:"networkingressproxy_buffer_size_kb"},"network.ingress.proxy_buffer_size_kb ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to set, in kilobytes, a header buffer size used while reading the response header from upstream."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"E.g. You are using Auth0 with NextJS, you will need to set a bigger header size"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"4"))))),Object(b.b)("h4",{id:"networkingressproxy_connect_timeout_seconds"},"network.ingress.proxy_connect_timeout_seconds ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Defines a timeout (in seconds) for establishing a connection with a proxied server. It should be noted that this timeout cannot usually exceed 75 seconds."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"E.g. You can use it to define the maximum time to wait for your application to establish the connexion."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"60"))))),Object(b.b)("h4",{id:"networkingressproxy_read_timeout_seconds"},"network.ingress.proxy_read_timeout_seconds ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Defines a timeout for reading a response from the proxied server. The timeout is set only between two successive read operations, not for the transmission of the whole response. If the proxied server does not transmit anything within this time, the connection is closed."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"E.g. You can use it to fine-tune your WebSocket application."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"60"))))),Object(b.b)("h4",{id:"networkingressproxy_send_timeout_seconds"},"network.ingress.proxy_send_timeout_seconds ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Sets a timeout (in seconds) for transmitting a request to the proxied server. The timeout is set only between two successive write operations, not for the transmission of the whole request. If the proxied server does not receive anything within this time, the connection is closed."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"E.g. You can use it to fine-tune your WebSocket application."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"60"))))),Object(b.b)("h4",{id:"networkingressproxy_buffering"},"network.ingress.proxy_buffering ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to enable or disable nginx ",Object(b.b)("inlineCode",{parentName:"td"},"proxy-buffering"),". Valid values are ",Object(b.b)("inlineCode",{parentName:"td"},"on")," or ",Object(b.b)("inlineCode",{parentName:"td"},"off")),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"on"))))),Object(b.b)("h4",{id:"networkingressproxy_request_buffering"},"network.ingress.proxy_request_buffering ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to enable or disable nginx ",Object(b.b)("inlineCode",{parentName:"td"},"proxy-request_buffering"),". Valid values are ",Object(b.b)("inlineCode",{parentName:"td"},"on")," or ",Object(b.b)("inlineCode",{parentName:"td"},"off")),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"on"))))),Object(b.b)("h4",{id:"networkingresssend_timeout_seconds"},"network.ingress.send_timeout_seconds ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Sets a timeout (in seconds) for transmitting a response to the client. The timeout is set only between two successive write operations, not for the transmission of the whole response. If the client does not receive anything within this time, the connection is closed."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Useful to define the maximum timeout to wait for client connection."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"60"))))),Object(b.b)("h4",{id:"networkingresswhitelist_source_range"},"network.ingress.whitelist_source_range ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to specify which IP ranges are allowed to access your application. The value is a comma-separated list of CIDRs, e.g. ",Object(b.b)("inlineCode",{parentName:"td"},"10.0.0.0/24,172.10.0.1")),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"By default, any IP can access your application if it's exposed publicly and the users know the URL. You can limit its access by specifying the IPs you want to reach the app (e.g. the IP of your office)"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"0.0.0.0/0")," (any IP)")))),Object(b.b)("h4",{id:"networkingressdenylist_source_range"},"network.ingress.denylist_source_range ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to specify which IP ranges are not allowed to access your application. The value is a comma-separated list of CIDRs, e.g. ",Object(b.b)("inlineCode",{parentName:"td"},"10.0.0.0/24,172.10.0.1")),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"``")))),Object(b.b)("h4",{id:"networkingressbasic_auth_env_var"},"network.ingress.basic_auth_env_var ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Set the name of an environment variable to use as a basic authentication (",Object(b.b)("inlineCode",{parentName:"td"},"login:crypted_password"),") from ",Object(b.b)("inlineCode",{parentName:"td"},"htpasswd")," command."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"``")))),Object(b.b)("p",null,"Here is an example where you can create a secret environment variable on Qovery and set a name like ",Object(b.b)("inlineCode",{parentName:"p"},"BASIC_AUTH_CREDENTIALS"),". The content should be the result of the ",Object(b.b)("inlineCode",{parentName:"p"},"htpasswd")," command:"),Object(b.b)("pre",null,Object(b.b)("code",Object(n.a)({parentName:"pre"},{}),"$ htpasswd -n \nNew password:\nRe-type new password:\nusername:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20\n")),Object(b.b)("p",null,"The content of the ",Object(b.b)("inlineCode",{parentName:"p"},"BASIC_AUTH_CREDENTIALS")," environment variable should be: ",Object(b.b)("inlineCode",{parentName:"p"},"username:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20"),". To finish, set the ",Object(b.b)("a",Object(n.a)({parentName:"p"},{href:"#networkingressbasic_auth_env_var"}),Object(b.b)("inlineCode",{parentName:"a"},"network.ingress.basic_auth_env_var"))," advanced settings to ",Object(b.b)("inlineCode",{parentName:"p"},"BASIC_AUTH_CREDENTIALS"),"."),Object(b.b)("p",null,"You can pass set credentials by separating them with a comma. For example: ",Object(b.b)("inlineCode",{parentName:"p"},"username1:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20,username2:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20"),". However, the total length of the environment variable should not exceed 1MB."),Object(b.b)("h4",{id:"networkingressextra_headers"},"network.ingress.extra_headers ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to specify response headers with values separated by comma (e.g. ",Object(b.b)("inlineCode",{parentName:"td"},' {"X-Frame-Options":"DENY","X-Content-Type-Options":"nosniff"}')),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"{}"))))),Object(b.b)("h2",{id:"auto-scaling"},"Auto-scaling"),Object(b.b)("h4",{id:"hpacpuaverage_utilization_percent"},"hpa.cpu.average_utilization_percent ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Auto-scaling is triggered when a specific CPU utilization metric is reached (for instance, 40%). This advanced setting allows you to set this metric."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"60"))))),Object(b.b)("h2",{id:"job-settings"},"Job Settings"),Object(b.b)("h4",{id:"jobdelete_ttl_seconds_after_finished"},"job.delete_ttl_seconds_after_finished ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"integer"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"By default terminated jobs in a completed or failure state are not deleted. if this parameter is set, Kubernetes will automatically cleanup completed jobs after the ttl"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"null"))))),Object(b.b)("h4",{id:"cronjobconcurrency_policy"},"cronjob.concurrency_policy ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"It defines if it is allowed to start another instance of the same job if the previous execution didn't finish yet: ",Object(b.b)("inlineCode",{parentName:"td"},"Allow"),"/",Object(b.b)("inlineCode",{parentName:"td"},"Forbid"),"/",Object(b.b)("inlineCode",{parentName:"td"},"Replace"),")"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"Forbidden"))))),Object(b.b)("h4",{id:"cronjobfailed_job_history_limit"},"cronjob.failed_job_history_limit ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to define the maximum number of failed job executions that should be returned in the job execution history"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"1"))))),Object(b.b)("h4",{id:"cronjobsuccess_job_history_limit"},"cronjob.success_job_history_limit ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to define the maximum number of succeeded job executions that should be returned in the job execution history"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"1"))))),Object(b.b)("h2",{id:"security"},"Security"),Object(b.b)("h4",{id:"securityservice_account_name"},"security.service_account_name ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/application.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/container.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/cronjob.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/job.svg",alt:null}))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Type"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Use Case"),Object(b.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"string"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Allows you to set an existing Kubernetes service account name"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"E.g. On AWS, you can assume a role on an application to give it specific AWS permissions without having to specify AWS credentials"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"``")))))}p.isMDXComponent=!0},423:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var b=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var o=r.a.createContext({}),s=function(e){var t=r.a.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):l({},t,{},e)),a},p=function(e){var t=s(e.components);return r.a.createElement(o.Provider,{value:t},e.children)},j={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,b=e.originalType,c=e.parentName,o=i(e,["components","mdxType","originalType","parentName"]),p=s(a),d=n,m=p["".concat(c,".").concat(d)]||p[d]||j[d]||b;return a?r.a.createElement(m,l({ref:t},o,{components:a})):r.a.createElement(m,l({ref:t},o))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var b=a.length,c=new Array(b);c[0]=d;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l.mdxType="string"==typeof e?e:n,c[1]=l;for(var o=2;o1?arguments[1]:void 0,a),i=c>2?arguments[2]:void 0,o=void 0===i?a:r(i,a);o>l;)t[l++]=e;return t}},428:function(e,t,a){var n=a(28).f,r=Function.prototype,b=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(b)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var n=a(0),r=a.n(n),b=a(424);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(b.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},430:function(e,t,a){"use strict";var n=a(1),r=a(0),b=a.n(r),c=a(39),l=a(432),i=a(20),o=a.n(i);t.a=function(e){var t,a=e.to,i=e.href,s=a||i,p=Object(l.a)(s),j=Object(r.useRef)(!1),d=o.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(s),function(){d&&t&&t.disconnect()}}),[s,d,p]),s&&p?b.a.createElement(c.b,Object(n.a)({},e,{onMouseEnter:function(){j.current||(window.docusaurus.preload(s),j.current=!0)},innerRef:function(e){var a,n;d&&e&&p&&(a=e,n=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:s})):b.a.createElement("a",Object(n.a)({},e,{href:s}))}},431:function(e,t,a){"use strict";var n=a(0),r=a.n(n),b=a(430),c=a(423),l=a.n(c);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,c=e.leftIcon,i=e.rightIcon,o=e.size,s=e.target,p=e.to,j=l()("jump-to","jump-to--"+o,a),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(i||"chevron-right")+" arrow"}))));return s?r.a.createElement("a",{href:p,target:s,className:j},d):r.a.createElement(b.a,{to:p,className:j},d)}},432:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},433:function(e,t,a){"use strict";var n=a(435),r=a(51);function b(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var a=function(e){var t;switch(e.arrayFormat){case"index":return function(e,a,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=a):n[e]=a};case"bracket":return function(e,a,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],a):n[e]=[a]:n[e]=a};default:return function(e,t,a){void 0!==a[e]?a[e]=[].concat(a[e],t):a[e]=t}}}(t=r({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),b=t.length>0?t.join("="):void 0;b=void 0===b?null:decodeURIComponent(b),a(decodeURIComponent(r),b,n)})),Object.keys(n).sort().reduce((function(e,t){var a=n[t];return Boolean(a)&&"object"==typeof a&&!Array.isArray(a)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(a):e[t]=a,e}),Object.create(null))):n},t.stringify=function(e,t){var a=function(e){switch(e.arrayFormat){case"index":return function(t,a,n){return null===a?[b(t,e),"[",n,"]"].join(""):[b(t,e),"[",b(n,e),"]=",b(a,e)].join("")};case"bracket":return function(t,a){return null===a?b(t,e):[b(t,e),"[]=",b(a,e)].join("")};default:return function(t,a){return null===a?b(t,e):[b(t,e),"=",b(a,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var r=e[n];if(void 0===r)return"";if(null===r)return b(n,t);if(Array.isArray(r)){var c=[];return r.slice().forEach((function(e){void 0!==e&&c.push(a(n,e,c.length))})),c.join("&")}return b(n,t)+"="+b(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,a){"use strict";var n=a(0),r=a.n(n),b=(a(423),a(433)),c=a.n(b);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,b=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,i={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},o="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(i),s=Object(n.useState)(null),p=s[0],j=s[1];return r.a.createElement("div",{className:"steps steps--h"+a},t,!b&&!p&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return j("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:o,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,a){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/50bab564.72efcdb9.js.LICENSE.txt b/4f6caeac.9a9801ea.js.LICENSE.txt similarity index 100% rename from 50bab564.72efcdb9.js.LICENSE.txt rename to 4f6caeac.9a9801ea.js.LICENSE.txt diff --git a/4fed1128.2afb42b2.js b/4fed1128.93b5efc7.js similarity index 96% rename from 4fed1128.2afb42b2.js rename to 4fed1128.93b5efc7.js index ac555215e3..5bff5c688d 100644 --- a/4fed1128.2afb42b2.js +++ b/4fed1128.93b5efc7.js @@ -1,2 +1,2 @@ -/*! For license information please see 4fed1128.2afb42b2.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[92],{244:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return c})),a.d(t,"rightToc",(function(){return o})),a.d(t,"default",(function(){return m}));var n=a(1),r=a(9),l=(a(0),a(422)),b=(a(429),a(421)),i=(a(426),{last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"How to deploy Helm charts",description:"Use jobs to simply deploy Helm charts with Qovery (Kubecost example)",author_github:"https://github.com/deimosfr",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to deploy Helm charts",description:"Use jobs to simply deploy Helm charts with Qovery (Kubecost example)",permalink:"/guides/tutorial/how-to-deploy-helm-charts",readingTime:"7 min read",source:"@site/guides/tutorial/how-to-deploy-helm-charts.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to deploy Helm charts",truncated:!1,prevItem:{title:"How to deploy a Rust REST API application on AWS with ease",permalink:"/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease"},nextItem:{title:"How to integrate Qovery with GitHub Actions",permalink:"/guides/tutorial/how-to-integrate-qovery-with-github-actions"}},o=[{value:"Choose a deployment method",id:"choose-a-deployment-method",children:[]},{value:"Lifecycle job parameters for Helm charts",id:"lifecycle-job-parameters-for-helm-charts",children:[]},{value:"Chart deployment",id:"chart-deployment",children:[{value:"From a 3rd party or Artifact Hub",id:"from-a-3rd-party-or-artifact-hub",children:[]},{value:"From a Helm chart from a Git repository",id:"from-a-helm-chart-from-a-git-repository",children:[]},{value:"Lifecycle Job and Timeout management",id:"lifecycle-job-and-timeout-management",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],p={rightToc:o};function m(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(l.b)("wrapper",Object(n.a)({},p,a,{components:t,mdxType:"MDXLayout"}),Object(l.b)("p",null,Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://helm.sh/docs/"}),"Helm")," is one of the most known tools to deploy on Kubernetes. It has several very useful features, Qovery uses it behind the scene to deploy some of its components. But you can also deploy Helm charts by your self if you wish."),Object(l.b)("p",null,"Installing a chart can be useful for specific use cases:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"When you want to deploy some specific objects on Kubernetes."),Object(l.b)("li",{parentName:"ul"},"When a third-party vendor requires an installation with Helm."),Object(l.b)("li",{parentName:"ul"},"When some specific configuration has to be set and does not fit into an application or container proposed by Qovery.")),Object(l.b)("h2",{id:"choose-a-deployment-method"},"Choose a deployment method"),Object(l.b)("p",null,"There are several ways to deploy a chart:"),Object(l.b)("ol",null,Object(l.b)("li",{parentName:"ol"},"You can find a lot of Helm charts on the ",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://artifacthub.io/"}),"Artifact Hub")),Object(l.b)("li",{parentName:"ol"},"You can deploy a Helm chart from a third-party provider (",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.datadoghq.com/"}),"Datadog"),", ",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.kubecost.com/"}),"Kubecost"),"...)"),Object(l.b)("li",{parentName:"ol"},"You can deploy a Helm chart from a private or public Git repository (",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/Qovery/helm-freeze"}),"Helm freeze")," is useful in this case)")),Object(l.b)("p",null,"We will make an example with all of these methods, so you can choose the one that suits you best.\nIn all the examples, we will make use of the Lifecycle jobs to manage the deployment of your helm chart (install and uninstall). The Lifecycle job configuration will be different depending on the method you have chosen."),Object(l.b)("h2",{id:"lifecycle-job-parameters-for-helm-charts"},"Lifecycle job parameters for Helm charts"),Object(l.b)(b.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,"Qovery provides a Helm container, simplifying the Helm chart deployments, but you can do it your way if you prefer. The container image is ",Object(l.b)("inlineCode",{parentName:"p"},"qoveryrd/helm"),".")),Object(l.b)("p",null,"From the Qovery Helm container, several options exist and are accessible through environment variables to help you to configure the chart deployment:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Name"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Required"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm repository name"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_URL")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm chart URL (if none is specified, Artifact Hub will be used)"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"default")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_PATH")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The local repository PATH or name from Artifact Hub"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_RELEASE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The release name of the chart deployment (should be unique in a given namespace)"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_VALUES")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm chart values file path, containing your custom settings to override from the default values"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_TIMEOUT_SEC")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm timeout in seconds, to install and uninstall chart"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"180")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_MAX_HISTORY")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The number of releases history. Useful to be able to rollback"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"50")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_DRY_RUN")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Enable or disable ",Object(l.b)("inlineCode",{parentName:"td"},"dry run")," for testing purpose"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_SHOW_DIFF")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Enable or disable ",Object(l.b)("inlineCode",{parentName:"td"},"helm diff")," between the currently deployed version and the requested one"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_ADDITIONAL_PARAMS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Additional Helm CLI parameters to add to the command line"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_KUBERNETES_NAMESPACE")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Kubernetes namespace name in which this chart will be deployed"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"$QOVERY_KUBERNETES_NAMESPACE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Kubeconfig file path location"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no*")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG_B64")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The encoded base64 Kubeconfig content. It will be decoded and used in ",Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG")," environment variable"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no*")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG_GET_EKS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Set to ",Object(l.b)("inlineCode",{parentName:"td"},"true")," to get the Kubeconfig from AWS API. It will be used as ",Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG")," environment variable"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no*")))),Object(l.b)(b.a,{type:"warning",mdxType:"Alert"},Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG"),", ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_B64")," or ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_GET_EKS")," are required to be set to access Kubernetes cluster")),Object(l.b)("h2",{id:"chart-deployment"},"Chart deployment"),Object(l.b)("p",null,"In this tutorial, ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://docs.kubecost.com/install-and-configure/install"}),"Kubecost")," will be the chart to deploy. You can deploy it in an environment where other applications are already deployed or create a dedicated one for this purpose (tooling, monitoring...)."),Object(l.b)(b.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,"You will have to configure the ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG"),", ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_B64")," or ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_GET_EKS")," environment variable to be able to deploy the chart. It is mandatory to ensure Helm will be able to connect to your Kubernetes cluster.\nYou may also have to push AWS credentials (with ",Object(l.b)("inlineCode",{parentName:"p"},"eks:DescribeCluster")," permissions) or use ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/use-aws-iam-roles-with-qovery"}),"AWS IAM roles"),".")),Object(l.b)("h3",{id:"from-a-3rd-party-or-artifact-hub"},"From a 3rd party or Artifact Hub"),Object(l.b)("p",null,"First of all, create a ",Object(l.b)("inlineCode",{parentName:"p"},"Lifecycle Job"),":"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_container.png",alt:"create lifecycle job"})),Object(l.b)("p",null,"Then select the ",Object(l.b)("inlineCode",{parentName:"p"},"Start")," event, and add ",Object(l.b)("inlineCode",{parentName:"p"},'["install"]')," in the command arguments. In the ",Object(l.b)("inlineCode",{parentName:"p"},"Delete")," event, add ",Object(l.b)("inlineCode",{parentName:"p"},'["uninstall"]'),". And configure them to run the install during the Start"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_event.png",alt:"lifecycle event"})),Object(l.b)("p",null,"Click on continue and go up to the environment variables."),Object(l.b)("p",null,"Qovery Helm image to deploy Helm charts, proposes several options to be set with the help of environment variables:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_URL")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"https://kubecost.github.io/cost-analyzer/")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_PATH")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost/cost-analyzer")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_RELEASE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_KUBERNETES_NAMESPACE")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")))),Object(l.b)("p",null,"Additionally, you can set the ",Object(l.b)("inlineCode",{parentName:"p"},"Kubecost token")," if you have a license with additional Helm args like:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_ADDITIONAL_PARAMS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},'--set kubecostToken="xxx"')),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")))),Object(l.b)("h3",{id:"from-a-helm-chart-from-a-git-repository"},"From a Helm chart from a Git repository"),Object(l.b)("p",null,"If you prefer using a ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://en.wikipedia.org/wiki/DevOps#GitOps"}),"GitOps")," approach, having all your charts, etc... in a single Git repository, it is possible to deploy your charts this way."),Object(l.b)("p",null,"From a very simple repository where we could have a helm-freeze configuration looking like this:"),Object(l.b)("pre",null,Object(l.b)("code",Object(n.a)({parentName:"pre"},{className:"language-yaml"}),"charts:\n - name: cost-analyzer\n version: 1.99.0\n repo_name: kubecost\n\nrepos:\n - name: stable\n url: https://charts.helm.sh/stable\n - name: kubecost\n url: https://kubecost.github.io/cost-analyzer/\n\ndestinations:\n - name: default\n path: ./charts\n")),Object(l.b)("p",null,"Running ",Object(l.b)("inlineCode",{parentName:"p"},"helm-freeze sync")," will download the chart ",Object(l.b)("inlineCode",{parentName:"p"},"cost-analyzer")," into the charts folder. You can then use this simple ",Object(l.b)("inlineCode",{parentName:"p"},"Dockerfile")," which will add all the content of this git repository inside a container:"),Object(l.b)("pre",null,Object(l.b)("code",Object(n.a)({parentName:"pre"},{}),'FROM qoveryrd/helm:1.0\nADD . /helm\nENTRYPOINT ["/helm/run.sh"]\n')),Object(l.b)("p",null,"Finally, add the ",Object(l.b)("inlineCode",{parentName:"p"},"run.sh")," file from the ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/helm"}),"Qovery Helm image")," inside your repository. Commit now everything. To summarize, in your Git repository you should have:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"charts"),": a folder containing all the charts (here cost-analyzer chart)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"Dockerfile"),": helping you to deploy helm chart and containing all your charts"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"helm-freeze.yaml"),": configuration file for helm-freeze"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"run.sh"),": the container start script")),Object(l.b)("p",null,"We are now ready to create a ",Object(l.b)("inlineCode",{parentName:"p"},"Lifecycle job")," and select your repository:"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_git.png",alt:"create lifecycle job"})),Object(l.b)("p",null,"Then select the ",Object(l.b)("inlineCode",{parentName:"p"},"Start")," event, and add ",Object(l.b)("inlineCode",{parentName:"p"},'["install"]')," in the command arguments. In the ",Object(l.b)("inlineCode",{parentName:"p"},"Delete")," event, add ",Object(l.b)("inlineCode",{parentName:"p"},'["uninstall"]'),". And configure them to run the install during the Start"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_event.png",alt:"lifecycle event"})),Object(l.b)("p",null,"Set the environment variables to point to the chart to deploy with the release name and other required information:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_PATH")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"/helm/charts/cost-analyzer")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_RELEASE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_KUBERNETES_NAMESPACE")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")))),Object(l.b)("p",null,"Additionally, you can set the ",Object(l.b)("inlineCode",{parentName:"p"},"Kubecost token")," if you have a license with additional Helm args like:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_ADDITIONAL_PARAMS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},'--set kubecostToken="xxx"')),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")))),Object(l.b)("h3",{id:"lifecycle-job-and-timeout-management"},"Lifecycle Job and Timeout management"),Object(l.b)(b.a,{type:"warning",mdxType:"Alert"},Object(l.b)("p",null,Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://helm.sh/docs/intro/using_helm/#helpful-options-for-installupgraderollback"}),"Helm timeout")," and Qovery Lifecycle job should be correctly set to avoid board effects!"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"Qovery Liefcycle Job timeout > ( Helm deployment timeout + Helm rollback time )"))),Object(l.b)("p",null,"The default Helm timeout set by Qovery is 3 minutes. Qovery enables Helm options:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"--wait"),": to wait for all resources to be in a ready state before marking the release as successful"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"--atomic"),": to roll back the release if the deployment fails")),Object(l.b)("p",null,"Because of the atomic check, the rollback can take more than 5 minutes. By default, Qovery set the default Lifecycle timeout to 3 minutes, to avoid falling into this issue, but there is no guarantee, it depends on what resources are deployed:"),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Qovery strongly recommends leveraging the default Qovery Lifecycle Job timeout or reducing the default Helm timeout to ensure the rollback will occur properly in case of failure.")),Object(l.b)("h2",{id:"conclusion"},"Conclusion"),Object(l.b)("p",null,"As you can see, deploying Helm charts with Qovery is straightforward. Qovery Lifecycle jobs and its Qovery Helm image should help you a lot if you familiarize yourself with it and its options."))}m.isMDXComponent=!0},420:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var o=r.a.createContext({}),p=function(e){var t=r.a.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):i({},t,{},e)),a},m=function(e){var t=p(e.components);return r.a.createElement(o.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},u=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,l=e.originalType,b=e.parentName,o=c(e,["components","mdxType","originalType","parentName"]),m=p(a),u=n,s=m["".concat(b,".").concat(u)]||m[u]||d[u]||l;return a?r.a.createElement(s,i({ref:t},o,{components:a})):r.a.createElement(s,i({ref:t},o))}));function s(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var l=a.length,b=new Array(l);b[0]=u;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i.mdxType="string"==typeof e?e:n,b[1]=i;for(var o=2;o1?arguments[1]:void 0,a),c=b>2?arguments[2]:void 0,o=void 0===c?a:r(c,a);o>i;)t[i++]=e;return t}},425:function(e,t,a){var n=a(28).f,r=Function.prototype,l=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(l)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var n=a(0),r=a.n(n),l=a(421);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(l.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},427:function(e,t,a){"use strict";var n=a(1),r=a(0),l=a.n(r),b=a(39),i=a(430),c=a(20),o=a.n(c);t.a=function(e){var t,a=e.to,c=e.href,p=a||c,m=Object(i.a)(p),d=Object(r.useRef)(!1),u=o.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!u&&m&&window.docusaurus.prefetch(p),function(){u&&t&&t.disconnect()}}),[p,u,m]),p&&m?l.a.createElement(b.b,Object(n.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(p),d.current=!0)},innerRef:function(e){var a,n;u&&e&&m&&(a=e,n=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:p})):l.a.createElement("a",Object(n.a)({},e,{href:p}))}},429:function(e,t,a){"use strict";var n=a(0),r=a.n(n),l=a(427),b=a(420),i=a.n(b);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,b=e.leftIcon,c=e.rightIcon,o=e.size,p=e.target,m=e.to,d=i()("jump-to","jump-to--"+o,a),u=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},b&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+b})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:m,target:p,className:d},u):r.a.createElement(l.a,{to:m,className:d},u)}},430:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))}}]); \ No newline at end of file +/*! For license information please see 4fed1128.93b5efc7.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[94],{246:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return c})),a.d(t,"rightToc",(function(){return o})),a.d(t,"default",(function(){return m}));var n=a(1),r=a(9),l=(a(0),a(425)),b=(a(431),a(424)),i=(a(429),{last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"How to deploy Helm charts",description:"Use jobs to simply deploy Helm charts with Qovery (Kubecost example)",author_github:"https://github.com/deimosfr",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to deploy Helm charts",description:"Use jobs to simply deploy Helm charts with Qovery (Kubecost example)",permalink:"/guides/tutorial/how-to-deploy-helm-charts",readingTime:"7 min read",source:"@site/guides/tutorial/how-to-deploy-helm-charts.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to deploy Helm charts",truncated:!1,prevItem:{title:"How to deploy a Rust REST API application on AWS with ease",permalink:"/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease"},nextItem:{title:"How to integrate Qovery with GitHub Actions",permalink:"/guides/tutorial/how-to-integrate-qovery-with-github-actions"}},o=[{value:"Choose a deployment method",id:"choose-a-deployment-method",children:[]},{value:"Lifecycle job parameters for Helm charts",id:"lifecycle-job-parameters-for-helm-charts",children:[]},{value:"Chart deployment",id:"chart-deployment",children:[{value:"From a 3rd party or Artifact Hub",id:"from-a-3rd-party-or-artifact-hub",children:[]},{value:"From a Helm chart from a Git repository",id:"from-a-helm-chart-from-a-git-repository",children:[]},{value:"Lifecycle Job and Timeout management",id:"lifecycle-job-and-timeout-management",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],p={rightToc:o};function m(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(l.b)("wrapper",Object(n.a)({},p,a,{components:t,mdxType:"MDXLayout"}),Object(l.b)("p",null,Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://helm.sh/docs/"}),"Helm")," is one of the most known tools to deploy on Kubernetes. It has several very useful features, Qovery uses it behind the scene to deploy some of its components. But you can also deploy Helm charts by your self if you wish."),Object(l.b)("p",null,"Installing a chart can be useful for specific use cases:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"When you want to deploy some specific objects on Kubernetes."),Object(l.b)("li",{parentName:"ul"},"When a third-party vendor requires an installation with Helm."),Object(l.b)("li",{parentName:"ul"},"When some specific configuration has to be set and does not fit into an application or container proposed by Qovery.")),Object(l.b)("h2",{id:"choose-a-deployment-method"},"Choose a deployment method"),Object(l.b)("p",null,"There are several ways to deploy a chart:"),Object(l.b)("ol",null,Object(l.b)("li",{parentName:"ol"},"You can find a lot of Helm charts on the ",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://artifacthub.io/"}),"Artifact Hub")),Object(l.b)("li",{parentName:"ol"},"You can deploy a Helm chart from a third-party provider (",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.datadoghq.com/"}),"Datadog"),", ",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.kubecost.com/"}),"Kubecost"),"...)"),Object(l.b)("li",{parentName:"ol"},"You can deploy a Helm chart from a private or public Git repository (",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/Qovery/helm-freeze"}),"Helm freeze")," is useful in this case)")),Object(l.b)("p",null,"We will make an example with all of these methods, so you can choose the one that suits you best.\nIn all the examples, we will make use of the Lifecycle jobs to manage the deployment of your helm chart (install and uninstall). The Lifecycle job configuration will be different depending on the method you have chosen."),Object(l.b)("h2",{id:"lifecycle-job-parameters-for-helm-charts"},"Lifecycle job parameters for Helm charts"),Object(l.b)(b.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,"Qovery provides a Helm container, simplifying the Helm chart deployments, but you can do it your way if you prefer. The container image is ",Object(l.b)("inlineCode",{parentName:"p"},"qoveryrd/helm"),".")),Object(l.b)("p",null,"From the Qovery Helm container, several options exist and are accessible through environment variables to help you to configure the chart deployment:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Name"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Required"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm repository name"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_URL")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm chart URL (if none is specified, Artifact Hub will be used)"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"default")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_PATH")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The local repository PATH or name from Artifact Hub"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_RELEASE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The release name of the chart deployment (should be unique in a given namespace)"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_VALUES")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm chart values file path, containing your custom settings to override from the default values"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_TIMEOUT_SEC")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm timeout in seconds, to install and uninstall chart"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"180")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_MAX_HISTORY")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The number of releases history. Useful to be able to rollback"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"50")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_DRY_RUN")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Enable or disable ",Object(l.b)("inlineCode",{parentName:"td"},"dry run")," for testing purpose"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_SHOW_DIFF")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Enable or disable ",Object(l.b)("inlineCode",{parentName:"td"},"helm diff")," between the currently deployed version and the requested one"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_ADDITIONAL_PARAMS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Additional Helm CLI parameters to add to the command line"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_KUBERNETES_NAMESPACE")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Kubernetes namespace name in which this chart will be deployed"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"$QOVERY_KUBERNETES_NAMESPACE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Kubeconfig file path location"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no*")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG_B64")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The encoded base64 Kubeconfig content. It will be decoded and used in ",Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG")," environment variable"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no*")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG_GET_EKS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Set to ",Object(l.b)("inlineCode",{parentName:"td"},"true")," to get the Kubeconfig from AWS API. It will be used as ",Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG")," environment variable"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no*")))),Object(l.b)(b.a,{type:"warning",mdxType:"Alert"},Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG"),", ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_B64")," or ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_GET_EKS")," are required to be set to access Kubernetes cluster")),Object(l.b)("h2",{id:"chart-deployment"},"Chart deployment"),Object(l.b)("p",null,"In this tutorial, ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://docs.kubecost.com/install-and-configure/install"}),"Kubecost")," will be the chart to deploy. You can deploy it in an environment where other applications are already deployed or create a dedicated one for this purpose (tooling, monitoring...)."),Object(l.b)(b.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,"You will have to configure the ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG"),", ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_B64")," or ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_GET_EKS")," environment variable to be able to deploy the chart. It is mandatory to ensure Helm will be able to connect to your Kubernetes cluster.\nYou may also have to push AWS credentials (with ",Object(l.b)("inlineCode",{parentName:"p"},"eks:DescribeCluster")," permissions) or use ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/use-aws-iam-roles-with-qovery"}),"AWS IAM roles"),".")),Object(l.b)("h3",{id:"from-a-3rd-party-or-artifact-hub"},"From a 3rd party or Artifact Hub"),Object(l.b)("p",null,"First of all, create a ",Object(l.b)("inlineCode",{parentName:"p"},"Lifecycle Job"),":"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_container.png",alt:"create lifecycle job"})),Object(l.b)("p",null,"Then select the ",Object(l.b)("inlineCode",{parentName:"p"},"Start")," event, and add ",Object(l.b)("inlineCode",{parentName:"p"},'["install"]')," in the command arguments. In the ",Object(l.b)("inlineCode",{parentName:"p"},"Delete")," event, add ",Object(l.b)("inlineCode",{parentName:"p"},'["uninstall"]'),". And configure them to run the install during the Start"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_event.png",alt:"lifecycle event"})),Object(l.b)("p",null,"Click on continue and go up to the environment variables."),Object(l.b)("p",null,"Qovery Helm image to deploy Helm charts, proposes several options to be set with the help of environment variables:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_URL")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"https://kubecost.github.io/cost-analyzer/")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_PATH")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost/cost-analyzer")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_RELEASE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_KUBERNETES_NAMESPACE")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")))),Object(l.b)("p",null,"Additionally, you can set the ",Object(l.b)("inlineCode",{parentName:"p"},"Kubecost token")," if you have a license with additional Helm args like:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_ADDITIONAL_PARAMS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},'--set kubecostToken="xxx"')),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")))),Object(l.b)("h3",{id:"from-a-helm-chart-from-a-git-repository"},"From a Helm chart from a Git repository"),Object(l.b)("p",null,"If you prefer using a ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://en.wikipedia.org/wiki/DevOps#GitOps"}),"GitOps")," approach, having all your charts, etc... in a single Git repository, it is possible to deploy your charts this way."),Object(l.b)("p",null,"From a very simple repository where we could have a helm-freeze configuration looking like this:"),Object(l.b)("pre",null,Object(l.b)("code",Object(n.a)({parentName:"pre"},{className:"language-yaml"}),"charts:\n - name: cost-analyzer\n version: 1.99.0\n repo_name: kubecost\n\nrepos:\n - name: stable\n url: https://charts.helm.sh/stable\n - name: kubecost\n url: https://kubecost.github.io/cost-analyzer/\n\ndestinations:\n - name: default\n path: ./charts\n")),Object(l.b)("p",null,"Running ",Object(l.b)("inlineCode",{parentName:"p"},"helm-freeze sync")," will download the chart ",Object(l.b)("inlineCode",{parentName:"p"},"cost-analyzer")," into the charts folder. You can then use this simple ",Object(l.b)("inlineCode",{parentName:"p"},"Dockerfile")," which will add all the content of this git repository inside a container:"),Object(l.b)("pre",null,Object(l.b)("code",Object(n.a)({parentName:"pre"},{}),'FROM qoveryrd/helm:1.0\nADD . /helm\nENTRYPOINT ["/helm/run.sh"]\n')),Object(l.b)("p",null,"Finally, add the ",Object(l.b)("inlineCode",{parentName:"p"},"run.sh")," file from the ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/helm"}),"Qovery Helm image")," inside your repository. Commit now everything. To summarize, in your Git repository you should have:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"charts"),": a folder containing all the charts (here cost-analyzer chart)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"Dockerfile"),": helping you to deploy helm chart and containing all your charts"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"helm-freeze.yaml"),": configuration file for helm-freeze"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"run.sh"),": the container start script")),Object(l.b)("p",null,"We are now ready to create a ",Object(l.b)("inlineCode",{parentName:"p"},"Lifecycle job")," and select your repository:"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_git.png",alt:"create lifecycle job"})),Object(l.b)("p",null,"Then select the ",Object(l.b)("inlineCode",{parentName:"p"},"Start")," event, and add ",Object(l.b)("inlineCode",{parentName:"p"},'["install"]')," in the command arguments. In the ",Object(l.b)("inlineCode",{parentName:"p"},"Delete")," event, add ",Object(l.b)("inlineCode",{parentName:"p"},'["uninstall"]'),". And configure them to run the install during the Start"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_event.png",alt:"lifecycle event"})),Object(l.b)("p",null,"Set the environment variables to point to the chart to deploy with the release name and other required information:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_PATH")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"/helm/charts/cost-analyzer")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_RELEASE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_KUBERNETES_NAMESPACE")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")))),Object(l.b)("p",null,"Additionally, you can set the ",Object(l.b)("inlineCode",{parentName:"p"},"Kubecost token")," if you have a license with additional Helm args like:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_ADDITIONAL_PARAMS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},'--set kubecostToken="xxx"')),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")))),Object(l.b)("h3",{id:"lifecycle-job-and-timeout-management"},"Lifecycle Job and Timeout management"),Object(l.b)(b.a,{type:"warning",mdxType:"Alert"},Object(l.b)("p",null,Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://helm.sh/docs/intro/using_helm/#helpful-options-for-installupgraderollback"}),"Helm timeout")," and Qovery Lifecycle job should be correctly set to avoid board effects!"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"Qovery Liefcycle Job timeout > ( Helm deployment timeout + Helm rollback time )"))),Object(l.b)("p",null,"The default Helm timeout set by Qovery is 3 minutes. Qovery enables Helm options:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"--wait"),": to wait for all resources to be in a ready state before marking the release as successful"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"--atomic"),": to roll back the release if the deployment fails")),Object(l.b)("p",null,"Because of the atomic check, the rollback can take more than 5 minutes. By default, Qovery set the default Lifecycle timeout to 3 minutes, to avoid falling into this issue, but there is no guarantee, it depends on what resources are deployed:"),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Qovery strongly recommends leveraging the default Qovery Lifecycle Job timeout or reducing the default Helm timeout to ensure the rollback will occur properly in case of failure.")),Object(l.b)("h2",{id:"conclusion"},"Conclusion"),Object(l.b)("p",null,"As you can see, deploying Helm charts with Qovery is straightforward. Qovery Lifecycle jobs and its Qovery Helm image should help you a lot if you familiarize yourself with it and its options."))}m.isMDXComponent=!0},423:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var o=r.a.createContext({}),p=function(e){var t=r.a.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):i({},t,{},e)),a},m=function(e){var t=p(e.components);return r.a.createElement(o.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},u=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,l=e.originalType,b=e.parentName,o=c(e,["components","mdxType","originalType","parentName"]),m=p(a),u=n,s=m["".concat(b,".").concat(u)]||m[u]||d[u]||l;return a?r.a.createElement(s,i({ref:t},o,{components:a})):r.a.createElement(s,i({ref:t},o))}));function s(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var l=a.length,b=new Array(l);b[0]=u;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i.mdxType="string"==typeof e?e:n,b[1]=i;for(var o=2;o1?arguments[1]:void 0,a),c=b>2?arguments[2]:void 0,o=void 0===c?a:r(c,a);o>i;)t[i++]=e;return t}},428:function(e,t,a){var n=a(28).f,r=Function.prototype,l=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(l)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var n=a(0),r=a.n(n),l=a(424);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(l.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},430:function(e,t,a){"use strict";var n=a(1),r=a(0),l=a.n(r),b=a(39),i=a(432),c=a(20),o=a.n(c);t.a=function(e){var t,a=e.to,c=e.href,p=a||c,m=Object(i.a)(p),d=Object(r.useRef)(!1),u=o.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!u&&m&&window.docusaurus.prefetch(p),function(){u&&t&&t.disconnect()}}),[p,u,m]),p&&m?l.a.createElement(b.b,Object(n.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(p),d.current=!0)},innerRef:function(e){var a,n;u&&e&&m&&(a=e,n=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:p})):l.a.createElement("a",Object(n.a)({},e,{href:p}))}},431:function(e,t,a){"use strict";var n=a(0),r=a.n(n),l=a(430),b=a(423),i=a.n(b);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,b=e.leftIcon,c=e.rightIcon,o=e.size,p=e.target,m=e.to,d=i()("jump-to","jump-to--"+o,a),u=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},b&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+b})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:m,target:p,className:d},u):r.a.createElement(l.a,{to:m,className:d},u)}},432:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))}}]); \ No newline at end of file diff --git a/5385e737.267adc11.js.LICENSE.txt b/4fed1128.93b5efc7.js.LICENSE.txt similarity index 100% rename from 5385e737.267adc11.js.LICENSE.txt rename to 4fed1128.93b5efc7.js.LICENSE.txt diff --git a/50bab564.72efcdb9.js b/50bab564.c840ef92.js similarity index 96% rename from 50bab564.72efcdb9.js rename to 50bab564.c840ef92.js index 96e503bdb5..ce9740eeba 100644 --- a/50bab564.72efcdb9.js +++ b/50bab564.c840ef92.js @@ -1,2 +1,2 @@ -/*! For license information please see 50bab564.72efcdb9.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[93],{245:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return s})),t.d(n,"metadata",(function(){return p})),t.d(n,"rightToc",(function(){return b})),t.d(n,"default",(function(){return u}));var i=t(1),r=t(9),a=(t(0),t(422)),o=t(431),l=t(421),c=t(426),s={last_modified_on:"2022-02-02",$schema:"/.meta/.schemas/guides.json",title:"Deploy Rails with PostgreSQL and Sidekiq",description:"How to deploy a Rails application with the PostgreSQL database and Sidekiq workers",author_github:"https://github.com/l0ck3",tags:["type: tutorial","framework: rails","language: ruby","database: postgresql"],hide_pagination:!0},p={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Deploy Rails with PostgreSQL and Sidekiq",description:"How to deploy a Rails application with the PostgreSQL database and Sidekiq workers",permalink:"/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq",readingTime:"11 min read",source:"@site/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"framework: rails",permalink:"/guides/tags/framework-rails"},{label:"language: ruby",permalink:"/guides/tags/language-ruby"},{label:"database: postgresql",permalink:"/guides/tags/database-postgresql"}],title:"Deploy Rails with PostgreSQL and Sidekiq",truncated:!1,prevItem:{title:"Deploy Frontend App",permalink:"/guides/advanced/deploy-frontend"},nextItem:{title:"Deploy Temporal on Kubernetes",permalink:"/guides/tutorial/deploy-temporal-on-kubernetes"}},b=[{value:"Goal",id:"goal",children:[]},{value:"Prepare your Rails application",id:"prepare-your-rails-application",children:[]},{value:"Deploy your application to Qovery",id:"deploy-your-application-to-qovery",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],d={rightToc:b};function u(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(i.a)({},d,t,{components:n,mdxType:"MDXLayout"}),Object(a.b)(c.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have a Qovery cluster ready"))),Object(a.b)("h2",{id:"goal"},"Goal"),Object(a.b)("p",null,"In this tutorial we will deploy a typical Rails 6 application, using PostgreSQL as a database and Sidekiq as an ActiveJob backend for background tasks."),Object(a.b)("h2",{id:"prepare-your-rails-application"},"Prepare your Rails application"),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"If you don't have a Rails 6 application at hand, you can clone this demo app: https://github.com/Qovery/qovery-rails-full-application-example"),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Qovery doesn't support Procfiles with multiple processes yet. We'll have to use Dockerfiles for both the web application and Sidekiq workers.",Object(a.b)("br",null),"Qovery doesn't support overriding Docker command yet, so we'll use two different Dockerfiles."),Object(a.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"web-application-dockerfile"},"Web application Dockerfile"),Object(a.b)("p",null,"Add a ",Object(a.b)("inlineCode",{parentName:"p"},"Dockerfile")," file at the root of your application with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{className:"language-Dockerfile"}),'FROM ruby:3.0.2-alpine3.13 AS builder\n\n# Minimal requirements to run a Rails app\nRUN apk add --no-cache --update build-base \\\n linux-headers \\\n git \\\n postgresql-dev=~13 \\\n # Rails SQL schema format requires `pg_dump(1)` and `psql(1)`\n postgresql=~13 \\\n # Install same version of pg_dump\n postgresql-client=~13 \\\n nodejs \\\n yarn \\\n # Needed for nodejs / node-gyp\n python2 \\\n tzdata\n\n \nENV BUNDLER_VERSION 2.2.24\nENV BUNDLE_JOBS 8\nENV BUNDLE_RETRY 5\nENV BUNDLE_WITHOUT development:test\nENV BUNDLE_CACHE_ALL true\nENV RAILS_ENV production\nENV RACK_ENV production\nENV NODE_ENV production\nENV APP_PATH /work\n\nWORKDIR $APP_PATH\n\n# Gems installation\nCOPY Gemfile Gemfile.lock ./\nRUN gem install bundler -v $BUNDLER_VERSION\n\nRUN bundle config --global frozen 1 && \\\n bundle install && \\\n rm -rf /usr/local/bundle/cache/*.gem && \\\n find /usr/local/bundle/gems/ -name "*.c" -delete && \\\n find /usr/local/bundle/gems/ -name "*.o" -delete\n\n \n\n# NPM packages installation\nCOPY package.json yarn.lock ./\nRUN yarn install --frozen-lockfile --non-interactive --production\n\nADD . $APP_PATH\n\nRUN SECRET_KEY_BASE=`bin/rake secret` rails assets:precompile --trace && \\\n yarn cache clean && \\\n rm -rf node_modules tmp/cache vendor/assets test\n\n \nFROM ruby:3.0.2-alpine3.13\n\nRUN mkdir -p /work\nWORKDIR /work\n\nENV RAILS_ENV production\nENV NODE_ENV production\nENV RAILS_SERVE_STATIC_FILES true\n\n# Some native extensions required by gems such as pg or mysql2.\nCOPY --from=builder /usr/lib /usr/lib\n\n# Timezone data is required at runtime\nCOPY --from=builder /usr/share/zoneinfo/ /usr/share/zoneinfo/\n\n# Ruby gems\nCOPY --from=builder /usr/local/bundle /usr/local/bundle\nCOPY --from=builder /work /work\n\nCOPY docker-entrypoint.sh ./\nENTRYPOINT ["./docker-entrypoint.sh"]\n\nEXPOSE 3000\n\nCMD ["rails", "server", "-p", "3000", "-b", "0.0.0.0"]\n')),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"You can tweak the versions if you are using a different version of Ruby, Bundler, PostgreSQL ...")),Object(a.b)("li",null,Object(a.b)("h4",{id:"sidekiq-dockerfile"},"Sidekiq Dockerfile"),Object(a.b)("p",null,"We'll use a similar Dockerfile for our Sidekiq worker.\nCreate a ",Object(a.b)("inlineCode",{parentName:"p"},"Dockerfile.sidekiq")," at the root of your repository with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{className:"language-Dockerfile"}),'FROM ruby:3.0.2-alpine3.13 AS builder\n\nLABEL maintener=\'yirbah@qovery.com\'\n\n# Minimal requirements to run a Rails app\nRUN apk add --no-cache --update build-base \\\n linux-headers \\\n git \\\n postgresql-dev=~13 \\\n # Rails SQL schema format requires `pg_dump(1)` and `psql(1)`\n postgresql=~13 \\\n # Install same version of pg_dump\n postgresql-client=~13 \\\n nodejs \\\n yarn \\\n # Needed for nodejs / node-gyp\n python2 \\\n tzdata\n\nENV BUNDLER_VERSION 2.2.24\nENV BUNDLE_JOBS 8\nENV BUNDLE_RETRY 5\nENV BUNDLE_WITHOUT development:test\nENV BUNDLE_CACHE_ALL true\nENV RAILS_ENV production\nENV RACK_ENV production\nENV NODE_ENV production\nENV APP_PATH /work\n\nWORKDIR $APP_PATH\n\n# Gems installation\nCOPY Gemfile Gemfile.lock ./\n\nRUN gem install bundler -v $BUNDLER_VERSION\n\nRUN bundle config --global frozen 1 && \\\n bundle install && \\\n rm -rf /usr/local/bundle/cache/*.gem && \\\n find /usr/local/bundle/gems/ -name "*.c" -delete && \\\n find /usr/local/bundle/gems/ -name "*.o" -delete\n\n# NPM packages installation\nCOPY package.json yarn.lock ./\n\nRUN yarn install --frozen-lockfile --non-interactive --production\n\nADD . $APP_PATH\n\nRUN SECRET_KEY_BASE=`bin/rake secret` rails assets:precompile --trace && \\\n yarn cache clean && \\\n rm -rf node_modules tmp/cache vendor/assets test\n\nFROM ruby:3.0.2-alpine3.13\n\nRUN mkdir -p /work\nWORKDIR /work\n\nENV RAILS_ENV production\nENV NODE_ENV production\nENV RAILS_SERVE_STATIC_FILES true\n\n# Some native extensions required by gems such as pg or mysql2.\nCOPY --from=builder /usr/lib /usr/lib\n\n# Timezone data is required at runtime\nCOPY --from=builder /usr/share/zoneinfo/ /usr/share/zoneinfo/\n\n# Ruby gems\nCOPY --from=builder /usr/local/bundle /usr/local/bundle\n\nCOPY --from=builder /work /work\n\nCOPY docker-entrypoint.sh ./\n\n\nCMD ["bundle", "exec", "sidekiq"]\n'))),Object(a.b)("li",null,Object(a.b)("h4",{id:"dockerignore"},"Dockerignore"),Object(a.b)("p",null,"In order to avoid unneeded files being copied to your Docker image, you can add a ",Object(a.b)("inlineCode",{parentName:"p"},".dockerignore")," file to the root of your project, with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{}),"# See https://help.github.com/articles/ignoring-files for more about ignoring files.\n#\n# If you find yourself ignoring temporary files generated by your text editor\n# or operating system, you probably want to add a global ignore instead:\n# git config --global core.excludesfile '~/.gitignore_global'\n\n# Ignore bundler config.\n/.bundle\n\n# Ignore all logfiles and tempfiles.\n/log/*\n/tmp/*\n!/log/.keep\n!/tmp/.keep\n\n# Ignore pidfiles, but keep the directory.\n/tmp/pids/*\n!/tmp/pids/\n!/tmp/pids/.keep\n\n# Ignore uploaded files in development.\n/storage/*\n!/storage/.keep\n/public/assets\n.byebug_history\n\n# Ignore master key for decrypting credentials and more.\n/config/master.key\n/public/packs\n/public/packs-test\n/node_modules\n/yarn-error.log\nyarn-debug.log*\n.yarn-integrity\n")),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"You can customize this file for the needs of your project. Add any file that is not useful for the runtime of your application.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"docker-entrypoint"},"Docker entrypoint"),Object(a.b)("p",null,"Finally we will add an entrypoint script that will be called at the start of the application.\nWe'll use it to run the database setup and migration commands."),Object(a.b)("p",null,"You can read more about why this entrypoint is needed ",Object(a.b)("a",Object(i.a)({parentName:"p"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"here"),". "),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"Soon Qovery will add lifecycle hooks and this won't be needed anymore"),Object(a.b)("p",null,"Add a ",Object(a.b)("inlineCode",{parentName:"p"},"docker-entrypoint.sh")," file at the root of your project with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{className:"language-bash"}),'#! /bin/sh\n\nbundle exec rake db:migrate\n\nif [[ $? != 0 ]]; then\n\necho\necho "== Failed to migrate. Running setup first."\necho\n\nbundle exec rake db:setup\nfi\n\n# Execute the given or default command:\n\nexec "$@"\n')),Object(a.b)("p",null,"Make this script executable: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{}),"chmod +x docker-entrypoint.sh\n"))))),Object(a.b)("h2",{id:"deploy-your-application-to-qovery"},"Deploy your application to Qovery"),Object(a.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"create-a-project"},"Create a project"),Object(a.b)("p",null,"Now that your Rails application is ready to be dockerized, we can create a project on the Qovery console:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/01.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"create-an-environment"},"Create an environment"),Object(a.b)("p",null,"Now we'll create an environment. Let's start with our ",Object(a.b)("inlineCode",{parentName:"p"},"staging")," environment:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/02.png",alt:"Qovery console"})),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/03.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-your-rails-app"},"Add your Rails app"),Object(a.b)("p",null,"We'll now add our Rails app to the environment: "),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/04.png",alt:"Qovery console"})),Object(a.b)("p",null,"On the form you'll need to enter the following information:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"The app name: it can be whatever you want. Here ",Object(a.b)("inlineCode",{parentName:"li"},"web"),"."),Object(a.b)("li",{parentName:"ul"},"Pick your Git privider, then the repository for your application"),Object(a.b)("li",{parentName:"ul"},"The branch you want to deploy for this application. We chose ",Object(a.b)("inlineCode",{parentName:"li"},"main")),Object(a.b)("li",{parentName:"ul"},"The Root application path. In case your application is not at the root of your repository (e.g. you have a monorepo), otherwise it will be ",Object(a.b)("inlineCode",{parentName:"li"},"/"),"."),Object(a.b)("li",{parentName:"ul"},"For the Build mode, pick ",Object(a.b)("inlineCode",{parentName:"li"},"Dockerfile"),"."),Object(a.b)("li",{parentName:"ul"},"Enter the path to your Dockerfile.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/05.png",alt:"Qovery console"})),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/06.png",alt:"Qovery console"})),Object(a.b)("p",null,"You can then click ",Object(a.b)("inlineCode",{parentName:"p"},"Create"),". You'll be redirected to your application dashboard."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/07.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"Your application is not being deployed yet. We'll add the database and do some more configuration before.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-a-postgresql-database"},"Add a PostgreSQL database"),Object(a.b)("p",null,"Our application will use a PostgreSQL database. Let's add one to our environment:"),Object(a.b)("p",null,"Click on ",Object(a.b)("inlineCode",{parentName:"p"},"ADD"),", then ",Object(a.b)("inlineCode",{parentName:"p"},"Database")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/08.png",alt:"Qovery console"})),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Give a name to your database."),Object(a.b)("li",{parentName:"ul"},"For the Type, select ",Object(a.b)("inlineCode",{parentName:"li"},"POSTGRESQL"),"."),Object(a.b)("li",{parentName:"ul"},"For the Mode, we'll pick ",Object(a.b)("inlineCode",{parentName:"li"},"CONTAINER"),"."),Object(a.b)("li",{parentName:"ul"},"Chose the Version you need.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/09.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Since we are creating a Staging environment, we used the CONTAINER mode. This is not recommended for Production. In Production environment you should go for the MANAGED option."),Object(a.b)("p",null,"You can then click ",Object(a.b)("inlineCode",{parentName:"p"},"Create"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-a-redis-database"},"Add a Redis database"),Object(a.b)("p",null,"Since we're using Sidekiq, we'll also need a Redis database as a backend."),Object(a.b)("p",null,"If you didn't close the ",Object(a.b)("inlineCode",{parentName:"p"},"Database")," modal, you can click the ",Object(a.b)("inlineCode",{parentName:"p"},"ADD")," button, then in the dropbox for ",Object(a.b)("inlineCode",{parentName:"p"},"Database 2")," click ",Object(a.b)("inlineCode",{parentName:"p"},"Create database"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/10.png",alt:"Qovery console"})),Object(a.b)("p",null,"Fill the form the same way you did for PostgreSQL:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/11.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Since we are creating a Staging environment, we used the CONTAINER mode. This is not recommended for Production. In Production environment you should go for the MANAGED option."),Object(a.b)("p",null,"Click ",Object(a.b)("inlineCode",{parentName:"p"},"Create")," and close the Databases modal."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/12.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"configure-your-application-env-variables"},"Configure your application ENV variables"),Object(a.b)("p",null,"Go back to your environment view:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/13.png",alt:"Qovery console"})),Object(a.b)("p",null,"Then click on your application:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/14.png",alt:"Qovery console"})),Object(a.b)("p",null,"On your application dashboard, go to ",Object(a.b)("inlineCode",{parentName:"p"},"Environment variables"),":"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/15.png",alt:"Qovery console"})),Object(a.b)("p",null,"Here you can add any environment variable your application needs."),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Since we are creating a Staging environment, we used the CONTAIWe do not advise you to add secret values here. For sensitive information, like credentials, use the Secret variables, which are encrypted."),Object(a.b)("p",null,"We'll now configure a few secrets for our application. Click on the ",Object(a.b)("inlineCode",{parentName:"p"},"Secret variables")," tab:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/16.png",alt:"Qovery console"})),Object(a.b)("p",null,"First since our Demo application uses the Rails Encrypted Secrets, we'll add the ",Object(a.b)("inlineCode",{parentName:"p"},"RAILS_MASTER_KEY")," secret\nClick on ",Object(a.b)("inlineCode",{parentName:"p"},"CREATE SECRET"),", then fill the form:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Variable: enter the variable name, ",Object(a.b)("inlineCode",{parentName:"li"},"RAILS_MASTER_KEY"),"."),Object(a.b)("li",{parentName:"ul"},"Value: enter the actual value for your ",Object(a.b)("inlineCode",{parentName:"li"},"RAILS_MASTER_KEY"),"."),Object(a.b)("li",{parentName:"ul"},"Scope: chose ",Object(a.b)("inlineCode",{parentName:"li"},"ENVIRONMENT")," since the secret will be used by our Sidekiq worker too.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/17.png",alt:"Qovery console"})),Object(a.b)("p",null,"Now we'll need to add the ",Object(a.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," and ",Object(a.b)("inlineCode",{parentName:"p"},"REDIS_URL"),", that Rails will use to connect to PostgreSQL and Redis. Those are secrets as well, since the URLs contain passwords."),Object(a.b)("p",null,"But instead of creating new secrets like we did for the ",Object(a.b)("inlineCode",{parentName:"p"},"RAILS_MASTER_KEY"),", we'll use aliases. Aliases are just a way of giving a different name to an existing ENV variable or secret.\nSince Qovery provides us with the secrets corresponding to the two databases we created earlier, we can alias them."),Object(a.b)("p",null,"First, create an alias to the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_POSTGRESQL_ZXXXXXXXX_DATABASE_URL_INTERNAL"),":"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/18.png",alt:"Qovery console"})),Object(a.b)("p",null,"In the form, chose ",Object(a.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," for the alias name and set it at the ",Object(a.b)("inlineCode",{parentName:"p"},"ENVIRONMENT")," level:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/19.png",alt:"Qovery console"})),Object(a.b)("p",null,"Click ",Object(a.b)("inlineCode",{parentName:"p"},"Create")," then do the same thing with a ",Object(a.b)("inlineCode",{parentName:"p"},"REDIS_URL")," alias to the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_REDIS_ZXXXXXXXX_DATABASE_URL_INTERNAL"),"."),Object(a.b)("p",null,"You should see your two aliases created:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/20.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"These are the secrets required for our demo application. Yours might need more. Add all the variables you need before going to the next step.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"deploy-the-environment"},"Deploy the environment"),Object(a.b)("p",null,"Go back to the ",Object(a.b)("inlineCode",{parentName:"p"},"staging")," environment view and deploy it:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/21.png",alt:"Qovery console"})),Object(a.b)("p",null,"You should see it switch to the ",Object(a.b)("inlineCode",{parentName:"p"},"DEPLOYING")," status. Wait until the status turns to ",Object(a.b)("inlineCode",{parentName:"p"},"RUNNING"),". "),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"The first deployment could take a while."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/22.png",alt:"Qovery console"})),Object(a.b)("p",null,"Once your environment is ",Object(a.b)("inlineCode",{parentName:"p"},"RUNNING"),", open the ",Object(a.b)("inlineCode",{parentName:"p"},"web")," application to see if it works. It will open a new tab showing your application."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/23.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-the-sidekiq-worker"},"Add the Sidekiq worker"),Object(a.b)("p",null,"The last step is to add your Sidekiq Worker. We'll follow the same steps as in the ",Object(a.b)("inlineCode",{parentName:"p"},"Add your Rails app")," section with a few differences:"),Object(a.b)("p",null,"Add a new application:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/24.png",alt:"Qovery console"})),Object(a.b)("p",null,"The settigs are the same as for the Rails application, except:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"We use the ",Object(a.b)("inlineCode",{parentName:"li"},"Dockerfile.sidekiq")," Dockerfile this time"),Object(a.b)("li",{parentName:"ul"},"We don't declare a port since our worker is not a web service but communicates with our application through Redis.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/25.png",alt:"Qovery console"})),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/26.png",alt:"Qovery console"})),Object(a.b)("p",null,"Click ",Object(a.b)("inlineCode",{parentName:"p"},"Create"),"."),Object(a.b)("p",null,"If we check the ENV variables and secrets, we notice that it directly inherited the ones we set at the ",Object(a.b)("inlineCode",{parentName:"p"},"Environment")," level. So we don't need to do the configuration again."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/27.png",alt:"Qovery console"})),Object(a.b)("p",null,"You can now deploy your ",Object(a.b)("inlineCode",{parentName:"p"},"worker")," application:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/28.png",alt:"Qovery console"})),Object(a.b)("p",null,"Wait for it to switch to the ",Object(a.b)("inlineCode",{parentName:"p"},"RUNNING")," status.")))),Object(a.b)("h2",{id:"conclusion"},"Conclusion"),Object(a.b)("p",null,"You now have a Rails application with PostgreSQL and Sidekiq running on Qovery. "),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Depending on the gems you are using, their versions or your application configuration, you might need to tweak the Dockerfiles provided.",Object(a.b)("br",null),"This example is meant to be a starting point for your own configuration, not a one-size-fits-all configuration."))}u.isMDXComponent=!0},420:function(e,n,t){var i;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=r.a.createContext({}),p=function(e){var n=r.a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):l({},n,{},e)),t},b=function(e){var n=p(e.components);return r.a.createElement(s.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},u=Object(i.forwardRef)((function(e,n){var t=e.components,i=e.mdxType,a=e.originalType,o=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),b=p(t),u=i,m=b["".concat(o,".").concat(u)]||b[u]||d[u]||a;return t?r.a.createElement(m,l({ref:n},s,{components:t})):r.a.createElement(m,l({ref:n},s))}));function m(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var a=t.length,o=new Array(a);o[0]=u;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l.mdxType="string"==typeof e?e:i,o[1]=l;for(var s=2;s1?arguments[1]:void 0,t),c=o>2?arguments[2]:void 0,s=void 0===c?t:r(c,t);s>l;)n[l++]=e;return n}},425:function(e,n,t){var i=t(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||t(10)&&i(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,n,t){"use strict";t(425);var i=t(0),r=t.n(i),a=t(421);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},428:function(e,n,t){"use strict";var i=t(432),r=t(51);function a(e,n){return n.encode?n.strict?i(e):encodeURIComponent(e):e}n.extract=function(e){return e.split("?")[1]||""},n.parse=function(e,n){var t=function(e){var n;switch(e.arrayFormat){case"index":return function(e,t,i){n=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),n?(void 0===i[e]&&(i[e]={}),i[e][n[1]]=t):i[e]=t};case"bracket":return function(e,t,i){n=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),n?void 0!==i[e]?i[e]=[].concat(i[e],t):i[e]=[t]:i[e]=t};default:return function(e,n,t){void 0!==t[e]?t[e]=[].concat(t[e],n):t[e]=n}}}(n=r({arrayFormat:"none"},n)),i=Object.create(null);return"string"!=typeof e?i:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var n=e.replace(/\+/g," ").split("="),r=n.shift(),a=n.length>0?n.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),t(decodeURIComponent(r),a,i)})),Object.keys(i).sort().reduce((function(e,n){var t=i[n];return Boolean(t)&&"object"==typeof t&&!Array.isArray(t)?e[n]=function e(n){return Array.isArray(n)?n.sort():"object"==typeof n?e(Object.keys(n)).sort((function(e,n){return Number(e)-Number(n)})).map((function(e){return n[e]})):n}(t):e[n]=t,e}),Object.create(null))):i},n.stringify=function(e,n){var t=function(e){switch(e.arrayFormat){case"index":return function(n,t,i){return null===t?[a(n,e),"[",i,"]"].join(""):[a(n,e),"[",a(i,e),"]=",a(t,e)].join("")};case"bracket":return function(n,t){return null===t?a(n,e):[a(n,e),"[]=",a(t,e)].join("")};default:return function(n,t){return null===t?a(n,e):[a(n,e),"=",a(t,e)].join("")}}}(n=r({encode:!0,strict:!0,arrayFormat:"none"},n));return e?Object.keys(e).sort().map((function(i){var r=e[i];if(void 0===r)return"";if(null===r)return a(i,n);if(Array.isArray(r)){var o=[];return r.slice().forEach((function(e){void 0!==e&&o.push(t(i,e,o.length))})),o.join("&")}return a(i,n)+"="+a(r,n)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,n,t){"use strict";var i=t(0),r=t.n(i),a=(t(420),t(428)),o=t.n(a);t(134);n.a=function(e){var n=e.children,t=e.headingDepth,a=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,c={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+o.a.stringify(c),p=Object(i.useState)(null),b=p[0],d=p[1];return r.a.createElement("div",{className:"steps steps--h"+t},n,!a&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,n,t){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 50bab564.c840ef92.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[95],{247:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return s})),t.d(n,"metadata",(function(){return p})),t.d(n,"rightToc",(function(){return b})),t.d(n,"default",(function(){return u}));var i=t(1),r=t(9),a=(t(0),t(425)),o=t(434),l=t(424),c=t(429),s={last_modified_on:"2022-02-02",$schema:"/.meta/.schemas/guides.json",title:"Deploy Rails with PostgreSQL and Sidekiq",description:"How to deploy a Rails application with the PostgreSQL database and Sidekiq workers",author_github:"https://github.com/l0ck3",tags:["type: tutorial","framework: rails","language: ruby","database: postgresql"],hide_pagination:!0},p={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Deploy Rails with PostgreSQL and Sidekiq",description:"How to deploy a Rails application with the PostgreSQL database and Sidekiq workers",permalink:"/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq",readingTime:"11 min read",source:"@site/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"framework: rails",permalink:"/guides/tags/framework-rails"},{label:"language: ruby",permalink:"/guides/tags/language-ruby"},{label:"database: postgresql",permalink:"/guides/tags/database-postgresql"}],title:"Deploy Rails with PostgreSQL and Sidekiq",truncated:!1,prevItem:{title:"Deploy Frontend App",permalink:"/guides/advanced/deploy-frontend"},nextItem:{title:"Deploy Temporal on Kubernetes",permalink:"/guides/tutorial/deploy-temporal-on-kubernetes"}},b=[{value:"Goal",id:"goal",children:[]},{value:"Prepare your Rails application",id:"prepare-your-rails-application",children:[]},{value:"Deploy your application to Qovery",id:"deploy-your-application-to-qovery",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],d={rightToc:b};function u(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(i.a)({},d,t,{components:n,mdxType:"MDXLayout"}),Object(a.b)(c.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have a Qovery cluster ready"))),Object(a.b)("h2",{id:"goal"},"Goal"),Object(a.b)("p",null,"In this tutorial we will deploy a typical Rails 6 application, using PostgreSQL as a database and Sidekiq as an ActiveJob backend for background tasks."),Object(a.b)("h2",{id:"prepare-your-rails-application"},"Prepare your Rails application"),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"If you don't have a Rails 6 application at hand, you can clone this demo app: https://github.com/Qovery/qovery-rails-full-application-example"),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Qovery doesn't support Procfiles with multiple processes yet. We'll have to use Dockerfiles for both the web application and Sidekiq workers.",Object(a.b)("br",null),"Qovery doesn't support overriding Docker command yet, so we'll use two different Dockerfiles."),Object(a.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"web-application-dockerfile"},"Web application Dockerfile"),Object(a.b)("p",null,"Add a ",Object(a.b)("inlineCode",{parentName:"p"},"Dockerfile")," file at the root of your application with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{className:"language-Dockerfile"}),'FROM ruby:3.0.2-alpine3.13 AS builder\n\n# Minimal requirements to run a Rails app\nRUN apk add --no-cache --update build-base \\\n linux-headers \\\n git \\\n postgresql-dev=~13 \\\n # Rails SQL schema format requires `pg_dump(1)` and `psql(1)`\n postgresql=~13 \\\n # Install same version of pg_dump\n postgresql-client=~13 \\\n nodejs \\\n yarn \\\n # Needed for nodejs / node-gyp\n python2 \\\n tzdata\n\n \nENV BUNDLER_VERSION 2.2.24\nENV BUNDLE_JOBS 8\nENV BUNDLE_RETRY 5\nENV BUNDLE_WITHOUT development:test\nENV BUNDLE_CACHE_ALL true\nENV RAILS_ENV production\nENV RACK_ENV production\nENV NODE_ENV production\nENV APP_PATH /work\n\nWORKDIR $APP_PATH\n\n# Gems installation\nCOPY Gemfile Gemfile.lock ./\nRUN gem install bundler -v $BUNDLER_VERSION\n\nRUN bundle config --global frozen 1 && \\\n bundle install && \\\n rm -rf /usr/local/bundle/cache/*.gem && \\\n find /usr/local/bundle/gems/ -name "*.c" -delete && \\\n find /usr/local/bundle/gems/ -name "*.o" -delete\n\n \n\n# NPM packages installation\nCOPY package.json yarn.lock ./\nRUN yarn install --frozen-lockfile --non-interactive --production\n\nADD . $APP_PATH\n\nRUN SECRET_KEY_BASE=`bin/rake secret` rails assets:precompile --trace && \\\n yarn cache clean && \\\n rm -rf node_modules tmp/cache vendor/assets test\n\n \nFROM ruby:3.0.2-alpine3.13\n\nRUN mkdir -p /work\nWORKDIR /work\n\nENV RAILS_ENV production\nENV NODE_ENV production\nENV RAILS_SERVE_STATIC_FILES true\n\n# Some native extensions required by gems such as pg or mysql2.\nCOPY --from=builder /usr/lib /usr/lib\n\n# Timezone data is required at runtime\nCOPY --from=builder /usr/share/zoneinfo/ /usr/share/zoneinfo/\n\n# Ruby gems\nCOPY --from=builder /usr/local/bundle /usr/local/bundle\nCOPY --from=builder /work /work\n\nCOPY docker-entrypoint.sh ./\nENTRYPOINT ["./docker-entrypoint.sh"]\n\nEXPOSE 3000\n\nCMD ["rails", "server", "-p", "3000", "-b", "0.0.0.0"]\n')),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"You can tweak the versions if you are using a different version of Ruby, Bundler, PostgreSQL ...")),Object(a.b)("li",null,Object(a.b)("h4",{id:"sidekiq-dockerfile"},"Sidekiq Dockerfile"),Object(a.b)("p",null,"We'll use a similar Dockerfile for our Sidekiq worker.\nCreate a ",Object(a.b)("inlineCode",{parentName:"p"},"Dockerfile.sidekiq")," at the root of your repository with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{className:"language-Dockerfile"}),'FROM ruby:3.0.2-alpine3.13 AS builder\n\nLABEL maintener=\'yirbah@qovery.com\'\n\n# Minimal requirements to run a Rails app\nRUN apk add --no-cache --update build-base \\\n linux-headers \\\n git \\\n postgresql-dev=~13 \\\n # Rails SQL schema format requires `pg_dump(1)` and `psql(1)`\n postgresql=~13 \\\n # Install same version of pg_dump\n postgresql-client=~13 \\\n nodejs \\\n yarn \\\n # Needed for nodejs / node-gyp\n python2 \\\n tzdata\n\nENV BUNDLER_VERSION 2.2.24\nENV BUNDLE_JOBS 8\nENV BUNDLE_RETRY 5\nENV BUNDLE_WITHOUT development:test\nENV BUNDLE_CACHE_ALL true\nENV RAILS_ENV production\nENV RACK_ENV production\nENV NODE_ENV production\nENV APP_PATH /work\n\nWORKDIR $APP_PATH\n\n# Gems installation\nCOPY Gemfile Gemfile.lock ./\n\nRUN gem install bundler -v $BUNDLER_VERSION\n\nRUN bundle config --global frozen 1 && \\\n bundle install && \\\n rm -rf /usr/local/bundle/cache/*.gem && \\\n find /usr/local/bundle/gems/ -name "*.c" -delete && \\\n find /usr/local/bundle/gems/ -name "*.o" -delete\n\n# NPM packages installation\nCOPY package.json yarn.lock ./\n\nRUN yarn install --frozen-lockfile --non-interactive --production\n\nADD . $APP_PATH\n\nRUN SECRET_KEY_BASE=`bin/rake secret` rails assets:precompile --trace && \\\n yarn cache clean && \\\n rm -rf node_modules tmp/cache vendor/assets test\n\nFROM ruby:3.0.2-alpine3.13\n\nRUN mkdir -p /work\nWORKDIR /work\n\nENV RAILS_ENV production\nENV NODE_ENV production\nENV RAILS_SERVE_STATIC_FILES true\n\n# Some native extensions required by gems such as pg or mysql2.\nCOPY --from=builder /usr/lib /usr/lib\n\n# Timezone data is required at runtime\nCOPY --from=builder /usr/share/zoneinfo/ /usr/share/zoneinfo/\n\n# Ruby gems\nCOPY --from=builder /usr/local/bundle /usr/local/bundle\n\nCOPY --from=builder /work /work\n\nCOPY docker-entrypoint.sh ./\n\n\nCMD ["bundle", "exec", "sidekiq"]\n'))),Object(a.b)("li",null,Object(a.b)("h4",{id:"dockerignore"},"Dockerignore"),Object(a.b)("p",null,"In order to avoid unneeded files being copied to your Docker image, you can add a ",Object(a.b)("inlineCode",{parentName:"p"},".dockerignore")," file to the root of your project, with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{}),"# See https://help.github.com/articles/ignoring-files for more about ignoring files.\n#\n# If you find yourself ignoring temporary files generated by your text editor\n# or operating system, you probably want to add a global ignore instead:\n# git config --global core.excludesfile '~/.gitignore_global'\n\n# Ignore bundler config.\n/.bundle\n\n# Ignore all logfiles and tempfiles.\n/log/*\n/tmp/*\n!/log/.keep\n!/tmp/.keep\n\n# Ignore pidfiles, but keep the directory.\n/tmp/pids/*\n!/tmp/pids/\n!/tmp/pids/.keep\n\n# Ignore uploaded files in development.\n/storage/*\n!/storage/.keep\n/public/assets\n.byebug_history\n\n# Ignore master key for decrypting credentials and more.\n/config/master.key\n/public/packs\n/public/packs-test\n/node_modules\n/yarn-error.log\nyarn-debug.log*\n.yarn-integrity\n")),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"You can customize this file for the needs of your project. Add any file that is not useful for the runtime of your application.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"docker-entrypoint"},"Docker entrypoint"),Object(a.b)("p",null,"Finally we will add an entrypoint script that will be called at the start of the application.\nWe'll use it to run the database setup and migration commands."),Object(a.b)("p",null,"You can read more about why this entrypoint is needed ",Object(a.b)("a",Object(i.a)({parentName:"p"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"here"),". "),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"Soon Qovery will add lifecycle hooks and this won't be needed anymore"),Object(a.b)("p",null,"Add a ",Object(a.b)("inlineCode",{parentName:"p"},"docker-entrypoint.sh")," file at the root of your project with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{className:"language-bash"}),'#! /bin/sh\n\nbundle exec rake db:migrate\n\nif [[ $? != 0 ]]; then\n\necho\necho "== Failed to migrate. Running setup first."\necho\n\nbundle exec rake db:setup\nfi\n\n# Execute the given or default command:\n\nexec "$@"\n')),Object(a.b)("p",null,"Make this script executable: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{}),"chmod +x docker-entrypoint.sh\n"))))),Object(a.b)("h2",{id:"deploy-your-application-to-qovery"},"Deploy your application to Qovery"),Object(a.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"create-a-project"},"Create a project"),Object(a.b)("p",null,"Now that your Rails application is ready to be dockerized, we can create a project on the Qovery console:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/01.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"create-an-environment"},"Create an environment"),Object(a.b)("p",null,"Now we'll create an environment. Let's start with our ",Object(a.b)("inlineCode",{parentName:"p"},"staging")," environment:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/02.png",alt:"Qovery console"})),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/03.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-your-rails-app"},"Add your Rails app"),Object(a.b)("p",null,"We'll now add our Rails app to the environment: "),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/04.png",alt:"Qovery console"})),Object(a.b)("p",null,"On the form you'll need to enter the following information:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"The app name: it can be whatever you want. Here ",Object(a.b)("inlineCode",{parentName:"li"},"web"),"."),Object(a.b)("li",{parentName:"ul"},"Pick your Git privider, then the repository for your application"),Object(a.b)("li",{parentName:"ul"},"The branch you want to deploy for this application. We chose ",Object(a.b)("inlineCode",{parentName:"li"},"main")),Object(a.b)("li",{parentName:"ul"},"The Root application path. In case your application is not at the root of your repository (e.g. you have a monorepo), otherwise it will be ",Object(a.b)("inlineCode",{parentName:"li"},"/"),"."),Object(a.b)("li",{parentName:"ul"},"For the Build mode, pick ",Object(a.b)("inlineCode",{parentName:"li"},"Dockerfile"),"."),Object(a.b)("li",{parentName:"ul"},"Enter the path to your Dockerfile.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/05.png",alt:"Qovery console"})),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/06.png",alt:"Qovery console"})),Object(a.b)("p",null,"You can then click ",Object(a.b)("inlineCode",{parentName:"p"},"Create"),". You'll be redirected to your application dashboard."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/07.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"Your application is not being deployed yet. We'll add the database and do some more configuration before.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-a-postgresql-database"},"Add a PostgreSQL database"),Object(a.b)("p",null,"Our application will use a PostgreSQL database. Let's add one to our environment:"),Object(a.b)("p",null,"Click on ",Object(a.b)("inlineCode",{parentName:"p"},"ADD"),", then ",Object(a.b)("inlineCode",{parentName:"p"},"Database")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/08.png",alt:"Qovery console"})),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Give a name to your database."),Object(a.b)("li",{parentName:"ul"},"For the Type, select ",Object(a.b)("inlineCode",{parentName:"li"},"POSTGRESQL"),"."),Object(a.b)("li",{parentName:"ul"},"For the Mode, we'll pick ",Object(a.b)("inlineCode",{parentName:"li"},"CONTAINER"),"."),Object(a.b)("li",{parentName:"ul"},"Chose the Version you need.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/09.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Since we are creating a Staging environment, we used the CONTAINER mode. This is not recommended for Production. In Production environment you should go for the MANAGED option."),Object(a.b)("p",null,"You can then click ",Object(a.b)("inlineCode",{parentName:"p"},"Create"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-a-redis-database"},"Add a Redis database"),Object(a.b)("p",null,"Since we're using Sidekiq, we'll also need a Redis database as a backend."),Object(a.b)("p",null,"If you didn't close the ",Object(a.b)("inlineCode",{parentName:"p"},"Database")," modal, you can click the ",Object(a.b)("inlineCode",{parentName:"p"},"ADD")," button, then in the dropbox for ",Object(a.b)("inlineCode",{parentName:"p"},"Database 2")," click ",Object(a.b)("inlineCode",{parentName:"p"},"Create database"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/10.png",alt:"Qovery console"})),Object(a.b)("p",null,"Fill the form the same way you did for PostgreSQL:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/11.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Since we are creating a Staging environment, we used the CONTAINER mode. This is not recommended for Production. In Production environment you should go for the MANAGED option."),Object(a.b)("p",null,"Click ",Object(a.b)("inlineCode",{parentName:"p"},"Create")," and close the Databases modal."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/12.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"configure-your-application-env-variables"},"Configure your application ENV variables"),Object(a.b)("p",null,"Go back to your environment view:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/13.png",alt:"Qovery console"})),Object(a.b)("p",null,"Then click on your application:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/14.png",alt:"Qovery console"})),Object(a.b)("p",null,"On your application dashboard, go to ",Object(a.b)("inlineCode",{parentName:"p"},"Environment variables"),":"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/15.png",alt:"Qovery console"})),Object(a.b)("p",null,"Here you can add any environment variable your application needs."),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Since we are creating a Staging environment, we used the CONTAIWe do not advise you to add secret values here. For sensitive information, like credentials, use the Secret variables, which are encrypted."),Object(a.b)("p",null,"We'll now configure a few secrets for our application. Click on the ",Object(a.b)("inlineCode",{parentName:"p"},"Secret variables")," tab:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/16.png",alt:"Qovery console"})),Object(a.b)("p",null,"First since our Demo application uses the Rails Encrypted Secrets, we'll add the ",Object(a.b)("inlineCode",{parentName:"p"},"RAILS_MASTER_KEY")," secret\nClick on ",Object(a.b)("inlineCode",{parentName:"p"},"CREATE SECRET"),", then fill the form:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Variable: enter the variable name, ",Object(a.b)("inlineCode",{parentName:"li"},"RAILS_MASTER_KEY"),"."),Object(a.b)("li",{parentName:"ul"},"Value: enter the actual value for your ",Object(a.b)("inlineCode",{parentName:"li"},"RAILS_MASTER_KEY"),"."),Object(a.b)("li",{parentName:"ul"},"Scope: chose ",Object(a.b)("inlineCode",{parentName:"li"},"ENVIRONMENT")," since the secret will be used by our Sidekiq worker too.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/17.png",alt:"Qovery console"})),Object(a.b)("p",null,"Now we'll need to add the ",Object(a.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," and ",Object(a.b)("inlineCode",{parentName:"p"},"REDIS_URL"),", that Rails will use to connect to PostgreSQL and Redis. Those are secrets as well, since the URLs contain passwords."),Object(a.b)("p",null,"But instead of creating new secrets like we did for the ",Object(a.b)("inlineCode",{parentName:"p"},"RAILS_MASTER_KEY"),", we'll use aliases. Aliases are just a way of giving a different name to an existing ENV variable or secret.\nSince Qovery provides us with the secrets corresponding to the two databases we created earlier, we can alias them."),Object(a.b)("p",null,"First, create an alias to the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_POSTGRESQL_ZXXXXXXXX_DATABASE_URL_INTERNAL"),":"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/18.png",alt:"Qovery console"})),Object(a.b)("p",null,"In the form, chose ",Object(a.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," for the alias name and set it at the ",Object(a.b)("inlineCode",{parentName:"p"},"ENVIRONMENT")," level:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/19.png",alt:"Qovery console"})),Object(a.b)("p",null,"Click ",Object(a.b)("inlineCode",{parentName:"p"},"Create")," then do the same thing with a ",Object(a.b)("inlineCode",{parentName:"p"},"REDIS_URL")," alias to the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_REDIS_ZXXXXXXXX_DATABASE_URL_INTERNAL"),"."),Object(a.b)("p",null,"You should see your two aliases created:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/20.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"These are the secrets required for our demo application. Yours might need more. Add all the variables you need before going to the next step.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"deploy-the-environment"},"Deploy the environment"),Object(a.b)("p",null,"Go back to the ",Object(a.b)("inlineCode",{parentName:"p"},"staging")," environment view and deploy it:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/21.png",alt:"Qovery console"})),Object(a.b)("p",null,"You should see it switch to the ",Object(a.b)("inlineCode",{parentName:"p"},"DEPLOYING")," status. Wait until the status turns to ",Object(a.b)("inlineCode",{parentName:"p"},"RUNNING"),". "),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"The first deployment could take a while."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/22.png",alt:"Qovery console"})),Object(a.b)("p",null,"Once your environment is ",Object(a.b)("inlineCode",{parentName:"p"},"RUNNING"),", open the ",Object(a.b)("inlineCode",{parentName:"p"},"web")," application to see if it works. It will open a new tab showing your application."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/23.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-the-sidekiq-worker"},"Add the Sidekiq worker"),Object(a.b)("p",null,"The last step is to add your Sidekiq Worker. We'll follow the same steps as in the ",Object(a.b)("inlineCode",{parentName:"p"},"Add your Rails app")," section with a few differences:"),Object(a.b)("p",null,"Add a new application:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/24.png",alt:"Qovery console"})),Object(a.b)("p",null,"The settigs are the same as for the Rails application, except:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"We use the ",Object(a.b)("inlineCode",{parentName:"li"},"Dockerfile.sidekiq")," Dockerfile this time"),Object(a.b)("li",{parentName:"ul"},"We don't declare a port since our worker is not a web service but communicates with our application through Redis.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/25.png",alt:"Qovery console"})),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/26.png",alt:"Qovery console"})),Object(a.b)("p",null,"Click ",Object(a.b)("inlineCode",{parentName:"p"},"Create"),"."),Object(a.b)("p",null,"If we check the ENV variables and secrets, we notice that it directly inherited the ones we set at the ",Object(a.b)("inlineCode",{parentName:"p"},"Environment")," level. So we don't need to do the configuration again."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/27.png",alt:"Qovery console"})),Object(a.b)("p",null,"You can now deploy your ",Object(a.b)("inlineCode",{parentName:"p"},"worker")," application:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/28.png",alt:"Qovery console"})),Object(a.b)("p",null,"Wait for it to switch to the ",Object(a.b)("inlineCode",{parentName:"p"},"RUNNING")," status.")))),Object(a.b)("h2",{id:"conclusion"},"Conclusion"),Object(a.b)("p",null,"You now have a Rails application with PostgreSQL and Sidekiq running on Qovery. "),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Depending on the gems you are using, their versions or your application configuration, you might need to tweak the Dockerfiles provided.",Object(a.b)("br",null),"This example is meant to be a starting point for your own configuration, not a one-size-fits-all configuration."))}u.isMDXComponent=!0},423:function(e,n,t){var i;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=r.a.createContext({}),p=function(e){var n=r.a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):l({},n,{},e)),t},b=function(e){var n=p(e.components);return r.a.createElement(s.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},u=Object(i.forwardRef)((function(e,n){var t=e.components,i=e.mdxType,a=e.originalType,o=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),b=p(t),u=i,m=b["".concat(o,".").concat(u)]||b[u]||d[u]||a;return t?r.a.createElement(m,l({ref:n},s,{components:t})):r.a.createElement(m,l({ref:n},s))}));function m(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var a=t.length,o=new Array(a);o[0]=u;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l.mdxType="string"==typeof e?e:i,o[1]=l;for(var s=2;s1?arguments[1]:void 0,t),c=o>2?arguments[2]:void 0,s=void 0===c?t:r(c,t);s>l;)n[l++]=e;return n}},428:function(e,n,t){var i=t(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||t(10)&&i(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,n,t){"use strict";t(428);var i=t(0),r=t.n(i),a=t(424);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},433:function(e,n,t){"use strict";var i=t(435),r=t(51);function a(e,n){return n.encode?n.strict?i(e):encodeURIComponent(e):e}n.extract=function(e){return e.split("?")[1]||""},n.parse=function(e,n){var t=function(e){var n;switch(e.arrayFormat){case"index":return function(e,t,i){n=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),n?(void 0===i[e]&&(i[e]={}),i[e][n[1]]=t):i[e]=t};case"bracket":return function(e,t,i){n=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),n?void 0!==i[e]?i[e]=[].concat(i[e],t):i[e]=[t]:i[e]=t};default:return function(e,n,t){void 0!==t[e]?t[e]=[].concat(t[e],n):t[e]=n}}}(n=r({arrayFormat:"none"},n)),i=Object.create(null);return"string"!=typeof e?i:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var n=e.replace(/\+/g," ").split("="),r=n.shift(),a=n.length>0?n.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),t(decodeURIComponent(r),a,i)})),Object.keys(i).sort().reduce((function(e,n){var t=i[n];return Boolean(t)&&"object"==typeof t&&!Array.isArray(t)?e[n]=function e(n){return Array.isArray(n)?n.sort():"object"==typeof n?e(Object.keys(n)).sort((function(e,n){return Number(e)-Number(n)})).map((function(e){return n[e]})):n}(t):e[n]=t,e}),Object.create(null))):i},n.stringify=function(e,n){var t=function(e){switch(e.arrayFormat){case"index":return function(n,t,i){return null===t?[a(n,e),"[",i,"]"].join(""):[a(n,e),"[",a(i,e),"]=",a(t,e)].join("")};case"bracket":return function(n,t){return null===t?a(n,e):[a(n,e),"[]=",a(t,e)].join("")};default:return function(n,t){return null===t?a(n,e):[a(n,e),"=",a(t,e)].join("")}}}(n=r({encode:!0,strict:!0,arrayFormat:"none"},n));return e?Object.keys(e).sort().map((function(i){var r=e[i];if(void 0===r)return"";if(null===r)return a(i,n);if(Array.isArray(r)){var o=[];return r.slice().forEach((function(e){void 0!==e&&o.push(t(i,e,o.length))})),o.join("&")}return a(i,n)+"="+a(r,n)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,n,t){"use strict";var i=t(0),r=t.n(i),a=(t(423),t(433)),o=t.n(a);t(134);n.a=function(e){var n=e.children,t=e.headingDepth,a=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,c={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+o.a.stringify(c),p=Object(i.useState)(null),b=p[0],d=p[1];return r.a.createElement("div",{className:"steps steps--h"+t},n,!a&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,n,t){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/543e268a.2cf957af.js.LICENSE.txt b/50bab564.c840ef92.js.LICENSE.txt similarity index 100% rename from 543e268a.2cf957af.js.LICENSE.txt rename to 50bab564.c840ef92.js.LICENSE.txt diff --git a/3e6b1f84.28cea352.js b/5385e737.917bcd55.js similarity index 92% rename from 3e6b1f84.28cea352.js rename to 5385e737.917bcd55.js index bc2c0edae5..e42dcc27ac 100644 --- a/3e6b1f84.28cea352.js +++ b/5385e737.917bcd55.js @@ -1,2 +1,2 @@ -/*! For license information please see 3e6b1f84.28cea352.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[69],{221:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return l})),r.d(t,"rightToc",(function(){return s})),r.d(t,"default",(function(){return b}));var a=r(1),n=r(9),o=(r(0),r(422)),c=(r(431),r(426),r(421)),i={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Deploy AWS Services",description:"Learn how to deploy any AWS services with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","cloud_provider: aws"]},l={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Deploy AWS Services",description:"Learn how to deploy any AWS services with Qovery",permalink:"/guides/advanced/deploy-aws-services",readingTime:"2 min read",source:"@site/guides/advanced/deploy-aws-services.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Deploy AWS Services",truncated:!1,prevItem:{title:"Deploy API Gateway",permalink:"/guides/advanced/deploy-api-gateway"},nextItem:{title:"Deploy External Services",permalink:"/guides/advanced/deploy-external-services"}},s=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],u={rightToc:s};function b(e){var t=e.components,r=Object(n.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},u,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery lets you deploy and connect any AWS services."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to learn how to deploy your AWS services with Qovery."),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Interested in deploying other services than AWS? Check out our ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/advanced/deploy-external-services/"}),Object(o.b)("inlineCode",{parentName:"a"},"Deploy External Services"))," guide.")),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/database/"}),"Deploy AWS RDS (built-in)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/database/"}),"Learn how to deploy a built-in AWS RDS instance with Qovery")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"Deploy AWS RDS with Terraform")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"Learn how to deploy an AWS RDS instance with Terraform and Qovery Lifecycle Job")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-ec2-with-pulumi"}),"Deploy AWS EC2 with Pulumi")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-ec2-with-pulumi"}),"Learn how to deploy an AWS EC2 instance with Pulumi and Qovery Lifecycle Job")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-lambda-and-sqs-with-cloudformation"}),"Deploy AWS Lambda and SQS with Cloudformation")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-lambda-and-sqs-with-cloudformation"}),"Learn how to deploy an AWS Lambda and SQS services with Cloudformation and Qovery Lifecycle Job")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-lambda-with-serverless"}),"Deploy AWS Lambda with Serverless")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-lambda-with-serverless"}),"Learn how to deploy an AWS Lambda with Serverless framework and Qovery Lifecycle Job")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"AWS VPC Peering")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"Learn how to interconnect Qovery AWS VPCs to your existing AWS VPCs")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=aws"}),'Forum "AWS"')),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=aws"}),'List "AWS" threads from Qovery community forum')),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}b.isMDXComponent=!0},420:function(e,t,r){var a;!function(){"use strict";var r={}.hasOwnProperty;function n(){for(var e=[],t=0;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=n.a.createContext({}),u=function(e){var t=n.a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},b=function(e){var t=u(e.components);return n.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(r),d=a,m=b["".concat(c,".").concat(d)]||b[d]||p[d]||o;return r?n.a.createElement(m,i({ref:t},s,{components:r})):n.a.createElement(m,i({ref:t},s))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,c=new Array(o);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:a,c[1]=i;for(var s=2;s1?arguments[1]:void 0,r),l=c>2?arguments[2]:void 0,s=void 0===l?r:n(l,r);s>i;)t[i++]=e;return t}},425:function(e,t,r){var a=r(28).f,n=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in n||r(10)&&a(n,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,r){"use strict";r(425);var a=r(0),n=r.n(a),o=r(421);t.a=function(e){var t=e.children,r=e.name;return n.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},428:function(e,t,r){"use strict";var a=r(432),n=r(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=r):a[e]=r};case"bracket":return function(e,r,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],r):a[e]=[r]:a[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=n({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),n=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(n),o,a)})),Object.keys(a).sort().reduce((function(e,t){var r=a[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):a},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,a){return null===r?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=n({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var n=e[a];if(void 0===n)return"";if(null===n)return o(a,t);if(Array.isArray(n)){var c=[];return n.slice().forEach((function(e){void 0!==e&&c.push(r(a,e,c.length))})),c.join("&")}return o(a,t)+"="+o(n,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,r){"use strict";var a=r(0),n=r.n(a),o=(r(420),r(428)),c=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),u=Object(a.useState)(null),b=u[0],p=u[1];return n.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!b&&n.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",n.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",n.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&n.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",n.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 5385e737.917bcd55.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[96],{248:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return l})),r.d(t,"rightToc",(function(){return s})),r.d(t,"default",(function(){return b}));var a=r(1),n=r(9),o=(r(0),r(425)),c=(r(434),r(429),r(424)),i={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Deploy AWS Services",description:"Learn how to deploy any AWS services with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","cloud_provider: aws"]},l={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Deploy AWS Services",description:"Learn how to deploy any AWS services with Qovery",permalink:"/guides/advanced/deploy-aws-services",readingTime:"2 min read",source:"@site/guides/advanced/deploy-aws-services.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Deploy AWS Services",truncated:!1,prevItem:{title:"Deploy API Gateway",permalink:"/guides/advanced/deploy-api-gateway"},nextItem:{title:"Deploy External Services",permalink:"/guides/advanced/deploy-external-services"}},s=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],u={rightToc:s};function b(e){var t=e.components,r=Object(n.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},u,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery lets you deploy and connect any AWS services."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to learn how to deploy your AWS services with Qovery."),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Interested in deploying other services than AWS? Check out our ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/advanced/deploy-external-services/"}),Object(o.b)("inlineCode",{parentName:"a"},"Deploy External Services"))," guide.")),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/database/"}),"Deploy AWS RDS (built-in)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/database/"}),"Learn how to deploy a built-in AWS RDS instance with Qovery")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"Deploy AWS RDS with Terraform")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"Learn how to deploy an AWS RDS instance with Terraform and Qovery Lifecycle Job")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-ec2-with-pulumi"}),"Deploy AWS EC2 with Pulumi")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-ec2-with-pulumi"}),"Learn how to deploy an AWS EC2 instance with Pulumi and Qovery Lifecycle Job")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-lambda-and-sqs-with-cloudformation"}),"Deploy AWS Lambda and SQS with Cloudformation")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-lambda-and-sqs-with-cloudformation"}),"Learn how to deploy an AWS Lambda and SQS services with Cloudformation and Qovery Lifecycle Job")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-lambda-with-serverless"}),"Deploy AWS Lambda with Serverless")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-lambda-with-serverless"}),"Learn how to deploy an AWS Lambda with Serverless framework and Qovery Lifecycle Job")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"AWS VPC Peering")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"Learn how to interconnect Qovery AWS VPCs to your existing AWS VPCs")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=aws"}),'Forum "AWS"')),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=aws"}),'List "AWS" threads from Qovery community forum')),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}b.isMDXComponent=!0},423:function(e,t,r){var a;!function(){"use strict";var r={}.hasOwnProperty;function n(){for(var e=[],t=0;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=n.a.createContext({}),u=function(e){var t=n.a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},b=function(e){var t=u(e.components);return n.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(r),d=a,m=b["".concat(c,".").concat(d)]||b[d]||p[d]||o;return r?n.a.createElement(m,i({ref:t},s,{components:r})):n.a.createElement(m,i({ref:t},s))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,c=new Array(o);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:a,c[1]=i;for(var s=2;s1?arguments[1]:void 0,r),l=c>2?arguments[2]:void 0,s=void 0===l?r:n(l,r);s>i;)t[i++]=e;return t}},428:function(e,t,r){var a=r(28).f,n=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in n||r(10)&&a(n,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,r){"use strict";r(428);var a=r(0),n=r.n(a),o=r(424);t.a=function(e){var t=e.children,r=e.name;return n.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},433:function(e,t,r){"use strict";var a=r(435),n=r(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=r):a[e]=r};case"bracket":return function(e,r,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],r):a[e]=[r]:a[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=n({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),n=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(n),o,a)})),Object.keys(a).sort().reduce((function(e,t){var r=a[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):a},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,a){return null===r?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=n({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var n=e[a];if(void 0===n)return"";if(null===n)return o(a,t);if(Array.isArray(n)){var c=[];return n.slice().forEach((function(e){void 0!==e&&c.push(r(a,e,c.length))})),c.join("&")}return o(a,t)+"="+o(n,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,r){"use strict";var a=r(0),n=r.n(a),o=(r(423),r(433)),c=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),u=Object(a.useState)(null),b=u[0],p=u[1];return n.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!b&&n.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",n.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",n.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&n.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",n.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/54ad54c7.c4b67d25.js.LICENSE.txt b/5385e737.917bcd55.js.LICENSE.txt similarity index 100% rename from 54ad54c7.c4b67d25.js.LICENSE.txt rename to 5385e737.917bcd55.js.LICENSE.txt diff --git a/543e268a.2cf957af.js b/543e268a.9a09bd3e.js similarity index 88% rename from 543e268a.2cf957af.js rename to 543e268a.9a09bd3e.js index 03a26f015e..24c9f36324 100644 --- a/543e268a.2cf957af.js +++ b/543e268a.9a09bd3e.js @@ -1,2 +1,2 @@ -/*! For license information please see 543e268a.2cf957af.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[95],{247:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),a=n(9),o=(n(0),n(422)),c=n(429),i=(n(550),{last_modified_on:"2021-06-19",title:"What's next?",description:"Where should I go to learn more about Qovery?"}),u={id:"getting-started/whats-next",title:"What's next?",description:"Where should I go to learn more about Qovery?",source:"@site/docs/getting-started/whats-next.md",permalink:"/docs/getting-started/whats-next",sidebar:"docs",previous:{title:"Deploy my application",permalink:"/docs/getting-started/deploy-my-app"},next:{title:"Using Qovery",permalink:"/docs/using-qovery"}},s=[],l={rightToc:s};function p(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Before you go any further, make sure you have followed and finished the basic Getting Started Guide:"),Object(o.b)(c.a,{to:"/guides/getting-started/",mdxType:"Jump"},"Getting Started Guide"),Object(o.b)("p",null,"After you have hands-on experience with Qovery, you can learn more about all the concepts and features in ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/"}),Object(o.b)("em",{parentName:"a"},"Using Qovery")),"\nsubsections:"),Object(o.b)(c.a,{to:"/docs/using-qovery",mdxType:"Jump"},"Using Qovery"))}p.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},p=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||o;return n?a.a.createElement(m,i({ref:t},s,{components:n})):a.a.createElement(m,i({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,c=new Array(o);c[0]=d;var i={};for(var u in t)hasOwnProperty.call(t,u)&&(i[u]=t[u]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var s=2;s0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:l})):o.a.createElement("a",Object(r.a)({},e,{href:l}))}},429:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(427),c=n(420),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,c=e.leftIcon,u=e.rightIcon,s=e.size,l=e.target,p=e.to,f=i()("jump-to","jump-to--"+s,n),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},c&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+c})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return l?a.a.createElement("a",{href:p,target:l,className:f},d):a.a.createElement(o.a,{to:p,className:f},d)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},550:function(e,t,n){"use strict";n(0)}}]); \ No newline at end of file +/*! For license information please see 543e268a.9a09bd3e.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[97],{249:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),a=n(9),o=(n(0),n(425)),c=n(431),i=(n(553),{last_modified_on:"2021-06-19",title:"What's next?",description:"Where should I go to learn more about Qovery?"}),u={id:"getting-started/whats-next",title:"What's next?",description:"Where should I go to learn more about Qovery?",source:"@site/docs/getting-started/whats-next.md",permalink:"/docs/getting-started/whats-next",sidebar:"docs",previous:{title:"Deploy my application",permalink:"/docs/getting-started/deploy-my-app"},next:{title:"Using Qovery",permalink:"/docs/using-qovery"}},s=[],l={rightToc:s};function p(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Before you go any further, make sure you have followed and finished the basic Getting Started Guide:"),Object(o.b)(c.a,{to:"/guides/getting-started/",mdxType:"Jump"},"Getting Started Guide"),Object(o.b)("p",null,"After you have hands-on experience with Qovery, you can learn more about all the concepts and features in ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/"}),Object(o.b)("em",{parentName:"a"},"Using Qovery")),"\nsubsections:"),Object(o.b)(c.a,{to:"/docs/using-qovery",mdxType:"Jump"},"Using Qovery"))}p.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},p=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||o;return n?a.a.createElement(m,i({ref:t},s,{components:n})):a.a.createElement(m,i({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,c=new Array(o);c[0]=d;var i={};for(var u in t)hasOwnProperty.call(t,u)&&(i[u]=t[u]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var s=2;s0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:l})):o.a.createElement("a",Object(r.a)({},e,{href:l}))}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(430),c=n(423),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,c=e.leftIcon,u=e.rightIcon,s=e.size,l=e.target,p=e.to,f=i()("jump-to","jump-to--"+s,n),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},c&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+c})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return l?a.a.createElement("a",{href:p,target:l,className:f},d):a.a.createElement(o.a,{to:p,className:f},d)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},553:function(e,t,n){"use strict";n(0)}}]); \ No newline at end of file diff --git a/55af4c9e.81391f49.js.LICENSE.txt b/543e268a.9a09bd3e.js.LICENSE.txt similarity index 100% rename from 55af4c9e.81391f49.js.LICENSE.txt rename to 543e268a.9a09bd3e.js.LICENSE.txt diff --git a/54ad54c7.c4b67d25.js b/54ad54c7.723b1ad6.js similarity index 86% rename from 54ad54c7.c4b67d25.js rename to 54ad54c7.723b1ad6.js index 1f51d6dd86..ef8e39f61d 100644 --- a/54ad54c7.c4b67d25.js +++ b/54ad54c7.723b1ad6.js @@ -1,2 +1,2 @@ -/*! For license information please see 54ad54c7.c4b67d25.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[96],{248:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return d}));var o=n(1),r=n(9),i=(n(0),n(422)),a=n(431),c=(n(429),n(421)),l=n(426),s={last_modified_on:"2023-09-27",title:"Cronjob",description:"Learn how to configure your Cronjob on Qovery"},u={id:"using-qovery/configuration/cronjob",title:"Cronjob",description:"Learn how to configure your Cronjob on Qovery",source:"@site/docs/using-qovery/configuration/cronjob.md",permalink:"/docs/using-qovery/configuration/cronjob",sidebar:"docs",previous:{title:"Redis",permalink:"/docs/using-qovery/configuration/database/redis"},next:{title:"Lifecycle Job",permalink:"/docs/using-qovery/configuration/lifecycle-job"}},b=[{value:"Deploying from a Git Repository",id:"deploying-from-a-git-repository",children:[]},{value:"Deploying from a Container Registry",id:"deploying-from-a-container-registry",children:[]},{value:"Create a Cronjob",id:"create-a-cronjob",children:[]},{value:"Deployment Management",id:"deployment-management",children:[]},{value:"Force Run",id:"force-run",children:[]},{value:"Configuration",id:"configuration",children:[{value:"General",id:"general",children:[]},{value:"JOB Configuration",id:"job-configuration",children:[]},{value:"Resources",id:"resources",children:[]},{value:"Health Checks",id:"health-checks",children:[]}]},{value:"Environment Variable",id:"environment-variable",children:[]},{value:"Secrets",id:"secrets",children:[]},{value:"Logs",id:"logs",children:[]},{value:"Clone",id:"clone",children:[]},{value:"Delete a job",id:"delete-a-job",children:[]}],p={rightToc:b};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(l.a,{name:"documentation",mdxType:"Assumptions"},Object(i.b)("p",null,"You have created an ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment"),".")),Object(i.b)("p",null,"A ",Object(i.b)("strong",{parentName:"p"},"cronjob")," is a workload that runs on your kubernetes cluster on a regular bases depending on the configured schedule (See ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/"}),"Cronjob on Kubernetes")," for more info). It is useful to execute tasks on a regular bases, like pulling data from an external service every hour or process the last 24hrs of data in your database."),Object(i.b)("p",null,"Qovery allows you to create and deploy cronjobs from two different sources: Git Repository or Container Registry"),Object(i.b)("h2",{id:"deploying-from-a-git-repository"},"Deploying from a Git Repository"),Object(i.b)("p",null,"In this configuration, Qovery will pull the code from the chosen repository, build the application and deploy it on your kubernetes cluster."),Object(i.b)("p",null,"The list of Git repositories available during the setup is strictly tied to the permissions of your git account (by default Qovery can access all your repositories). If you want to restrict the Qovery access only to a few repositories, user the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/git-repository-access/"}),"GitHub Qovery Application")," (only for Github)."),Object(i.b)("h2",{id:"deploying-from-a-container-registry"},"Deploying from a Container Registry"),Object(i.b)("p",null,"In this configuration, Qovery will pull the chosen container registry an image you have pre-built and deploy it on your kubernetes cluster."),Object(i.b)("p",null,"To improve the security and avoid deploying images from non-authorized registries, we have decided to restrict the list of Container Registry you can use during the setup process. Only an administrator with the right permissions can manage it from the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")),Object(i.b)("h2",{id:"create-a-cronjob"},"Create a Cronjob"),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,'Go into the chosen environment and press the "New Service" button and then the "Create Cronjob" button'),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/environments/service_creation.png",alt:"Creation"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Select the following fields:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Name: give a name to your applicaiton"),Object(i.b)("li",{parentName:"ul"},"Source: Chose between Git Repository or Container Registry, depending on the source location of your application")),Object(i.b)("p",null,"If you want to deploy a cronjob from a Git Repository you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Git Repository: Select the git provider hosting your code (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Branch: Select branch that Qovery should use to deploy your code"),Object(i.b)("li",{parentName:"ul"},"Root Application Path: base folder in which the code resides in your repository"),Object(i.b)("li",{parentName:"ul"},"Build Mode: only Docker is supported")),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"A Dockerfile is necessary to build and deploy your job")),Object(i.b)("p",null,"If you want to deploy a cronjob from a Container Registry you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Registry: select the container registry storing the image of your job. Note: only pre-configured registry are available in this list, check the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," for more information."),Object(i.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this job (example: postgres)"),Object(i.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this job (example: 12)")),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"The tag 'latest' is not supported, please use a specific tag.")),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Auto Deploy ")),Object(i.b)("p",null,"See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section.")),Object(i.b)("li",null,'Specify the configuration of your job: - CRON Schedule: specify a valid CRON expression (see [Crontab guru](https://crontab.guru/) for help). After being deployed, the job will be executed following the defined schedule. - Image Entrypoint: the entrypoint to be used to launch your job (not mandatory) - CMD Arguments: the arguments to be passed to launch your job (not mandatory). We expect the format to be an array. Example ["rails", "-h", "0.0.0.0", "-p", "8080", "string"] - Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure) - Max duration time in seconds: Maximum duration allowed for the job to run before killing it and mark it as failed - Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally'),Object(i.b)("li",null,"Within this section, you will need to define the resources to be assigned to your job at run time.",Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"vCPU: the vCPU assigned to each instance of your application. The default is 500m (0.5 vCPU)."),Object(i.b)("li",{parentName:"ul"},"RAM: the amount of RAM assigned to each instance of your application. The default is 512MB.")),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Please note that in this section you configure the CPU/RAM allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU/RAM."))),Object(i.b)("li",null,Object(i.b)("p",null,"Define any input variable required by your job to run. Any declared variable will be injected as environment variables based on the selected scope (project, environment, service)\nAny additional environment variable can be added later from the environment variable section"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/job/variables.png",alt:"Input Variables"}))),Object(i.b)("li",null,Object(i.b)("p",null,"You will find a recap of your job setup and you can now decide to:\n1. Go back to one of the previous steps and change your settings\n2. Create your job without deploying it\n3. Create and deploy your job"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/job/cronjob_recap.png",alt:"Recap"}))))),Object(i.b)("h2",{id:"deployment-management"},"Deployment Management"),Object(i.b)("p",null,"Have a look at the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/"}),"Deployment Management")," section for more information."),Object(i.b)("h2",{id:"force-run"},"Force Run"),Object(i.b)("p",null,"You can force the execution of a job independently its deployment status by:"),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Select the job that you want to force")),Object(i.b)("li",null,Object(i.b)("p",null,"click on the ",Object(i.b)("inlineCode",{parentName:"p"},"Play")," button of the cronjob you want to force and select the ",Object(i.b)("inlineCode",{parentName:"p"},"Force Run")," option. Note: the same option is available on the service list as well")),Object(i.b)("li",null,Object(i.b)("p",null,"Once you click, the job will be deployed and executed once. You will be able to follow its execution within the application logs")))),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"If the cronjob has not yet been deployed, forcing its execution will make it run only once (the scheduling mechanism will not start).")),Object(i.b)("h2",{id:"configuration"},"Configuration"),Object(i.b)("p",null,"Once created, you can access the configuration at any time via the Settings tab available on the service section"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/settings.png",alt:"Settings"})),Object(i.b)("p",null,"You can find below the description of each of the tabs available in this section"),Object(i.b)("h3",{id:"general"},"General"),Object(i.b)("p",null,"General settings section allows you to set up your application name and the source code location (git repository or image registry) ."),Object(i.b)("h4",{id:"git-repository"},"Git Repository"),Object(i.b)("p",null,"If your job is built and deployed from a git repository, within this section you can:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Modify the git provider where your code is stored (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Modify the branch that Qovery should use for deploying your code"),Object(i.b)("li",{parentName:"ul"},"Modify ",Object(i.b)("inlineCode",{parentName:"li"},"Root Application Path")," - base folder in which the application resides in your repository")),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Qovery supports mono repositories. ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/advanced/monorepository/"}),"See our advanced guide for more details."))),Object(i.b)(c.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"If your repository contains private submodules using SSH protocol, you will need to add a secret beginning with GIT",Object(i.b)("em",{parentName:"p"},"SSH_KEY"),", containing a private SSH key with access rights to your sumbodules repositories."),Object(i.b)("p",null,"Secret names examples:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITHUB"),Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITLAB"),Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_MYAPP"))),Object(i.b)("h4",{id:"container-registry"},"Container Registry"),Object(i.b)("p",null,"If your application is deployed from an image registry, within this section you can modify:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Registry: select the container registry storing the image of your application. Note: only pre-configured registry are available in this list, check the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," for more information."),Object(i.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this application (example: postgres)"),Object(i.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this application (example: 12)")),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"The tag 'latest' is not supported, please use a specific tag.")),Object(i.b)("h4",{id:"build-mode"},"Build Mode"),Object(i.b)("p",null,'This option is available only if you have selected "Git Repository" as source. Only Docker is supported'),Object(i.b)("p",null,"Qovery runs your application within the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://www.docker.com/resources/what-container"}),"Container technology"),". To build and run your application, you need to provide a valid ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.docker.com/engine/reference/builder"}),"Dockerfile"),"."),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-Dockerfile",metastring:'title="Valid NodeJS Dockerfile"',title:'"Valid',NodeJS:!0,'Dockerfile"':!0}),"FROM node:13-alpine\nRUN mkdir -p /usr/src/app\nWORKDIR /usr/src/app\nCOPY . .\nRUN npm install\nEXPOSE 3000\nCMD node ./bin/www\n")),Object(i.b)("p",null,"After creating a Dockerfile, specify the location of your Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"Dockefile path")," field."),Object(i.b)("p",null,"Configuration from above will make Qovery look for the Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"/timescale/Dockerfile")," path of your repository (",Object(i.b)("inlineCode",{parentName:"p"},"Root Application Path")," + ",Object(i.b)("inlineCode",{parentName:"p"},"Dockerfile Path"),")."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Auto Deploy ")),Object(i.b)("p",null,"See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section."),Object(i.b)("h3",{id:"job-configuration"},"JOB Configuration"),Object(i.b)("p",null,"You can modify here the configuration of your job:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"CRON Schedule: specify a valid CRON expression (see ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"https://crontab.guru/"}),"Crontab guru")," for help). After being deployed, the job will be executed following the defined schedule."),Object(i.b)("li",{parentName:"ul"},"Image Entrypoint: the entrypoint to be used to launch your job (not mandatory)"),Object(i.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your job (not mandatory). We expect the format to be an array. Example ",'["rails", "-h", "0.0.0.0", "-p", "8080", "string"]'),Object(i.b)("li",{parentName:"ul"},"Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure)"),Object(i.b)("li",{parentName:"ul"},"Max duration time in seconds: Maximum duration allowed for the job to run before killing it and mark it as failed"),Object(i.b)("li",{parentName:"ul"},"Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally")),Object(i.b)("h3",{id:"resources"},"Resources"),Object(i.b)("h4",{id:"cpu"},"CPU"),Object(i.b)("p",null,"To configure the number of CPUs that your job needs, adjust the setting in the ",Object(i.b)("inlineCode",{parentName:"p"},"Resources")," section."),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Default is 500m (0.5 vCPU). ")),Object(i.b)("p",null,"Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU."),Object(i.b)("h4",{id:"ram"},"RAM"),Object(i.b)("p",null,"To configure the amount of RAM that your app needs, adjust the setting in ",Object(i.b)("inlineCode",{parentName:"p"},"Resources")," section."),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Default is 512MB.")),Object(i.b)("p",null,"Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU. If your application requires more RAM than requested, it will be killed by the kubernetes scheduler."),Object(i.b)("h3",{id:"health-checks"},"Health Checks"),Object(i.b)("p",null,"To know more about how to configure your Liveness and Readiness probes, have a look at ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application-health-checks/"}),"the health-checks section")),Object(i.b)("h2",{id:"environment-variable"},"Environment Variable"),Object(i.b)("p",null,"To learn how to set up environment variables in your projects and applications, navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Environment Variables")," section."),Object(i.b)("h2",{id:"secrets"},"Secrets"),Object(i.b)("p",null,"To learn how to set up secrets in your projects and applications, navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Secrets")," section."),Object(i.b)("h2",{id:"logs"},"Logs"),Object(i.b)("p",null,"To learn how to display your application logs, navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#live-logs"}),"logs section")),Object(i.b)("h2",{id:"clone"},"Clone"),Object(i.b)("p",null,"You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/clone_service.png",alt:"Clone Service"})),Object(i.b)("p",null,"The target environment can be the same as the current environment or even another one in a completely different project."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Important information ")),Object(i.b)("p",null,"Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"same environment:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"))),Object(i.b)("li",{parentName:"ul"},"another environment:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"),Object(i.b)("li",{parentName:"ul"},"environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)"),Object(i.b)("li",{parentName:"ul"},"deployment pipeline: stage setup is not copied (since the target stage might not exist)"),Object(i.b)("li",{parentName:"ul"},"number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)")))),Object(i.b)("p",null,"Please check the configuration of the new service before deploying it."),Object(i.b)("h2",{id:"delete-a-job"},"Delete a job"),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Select the job you want to delete")),Object(i.b)("li",null,Object(i.b)("p",null,"In the overview, click on the ",Object(i.b)("inlineCode",{parentName:"p"},"3 dots")," button and remove the job. Note: the same option is available on the service list as well"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-1.png",alt:"Application"}))))))}d.isMDXComponent=!0},420:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},b=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),d=o,h=b["".concat(a,".").concat(d)]||b[d]||p[d]||i;return n?r.a.createElement(h,c({ref:t},s,{components:n})):r.a.createElement(h,c({ref:t},s))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,a[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=a>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var o=n(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var o=n(0),r=n.n(o),i=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var o=n(1),r=n(0),i=n.n(r),a=n(39),c=n(430),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,b=Object(c.a)(u),p=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,b]),u&&b?i.a.createElement(a.b,Object(o.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,o;d&&e&&b&&(n=e,o=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:u})):i.a.createElement("a",Object(o.a)({},e,{href:u}))}},428:function(e,t,n){"use strict";var o=n(432),r=n(51);function i(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(r),i,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[i(t,e),"[",o,"]"].join(""):[i(t,e),"[",i(o,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return i(o,t);if(Array.isArray(r)){var a=[];return r.slice().forEach((function(e){void 0!==e&&a.push(n(o,e,a.length))})),a.join("&")}return i(o,t)+"="+i(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=n(427),a=n(420),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,a=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,b=e.to,p=c()("jump-to","jump-to--"+s,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},a&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+a})),r.a.createElement("div",{className:"jump-to--main"},o?r.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:b,target:u,className:p},d):r.a.createElement(i.a,{to:b,className:p},d)}},430:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},431:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(420),n(428)),a=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(l),u=Object(o.useState)(null),b=u[0],p=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 54ad54c7.723b1ad6.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[98],{250:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return d}));var o=n(1),r=n(9),i=(n(0),n(425)),a=n(434),c=(n(431),n(424)),l=n(429),s={last_modified_on:"2023-09-27",title:"Cronjob",description:"Learn how to configure your Cronjob on Qovery"},u={id:"using-qovery/configuration/cronjob",title:"Cronjob",description:"Learn how to configure your Cronjob on Qovery",source:"@site/docs/using-qovery/configuration/cronjob.md",permalink:"/docs/using-qovery/configuration/cronjob",sidebar:"docs",previous:{title:"Redis",permalink:"/docs/using-qovery/configuration/database/redis"},next:{title:"Lifecycle Job",permalink:"/docs/using-qovery/configuration/lifecycle-job"}},b=[{value:"Deploying from a Git Repository",id:"deploying-from-a-git-repository",children:[]},{value:"Deploying from a Container Registry",id:"deploying-from-a-container-registry",children:[]},{value:"Create a Cronjob",id:"create-a-cronjob",children:[]},{value:"Deployment Management",id:"deployment-management",children:[]},{value:"Force Run",id:"force-run",children:[]},{value:"Configuration",id:"configuration",children:[{value:"General",id:"general",children:[]},{value:"JOB Configuration",id:"job-configuration",children:[]},{value:"Resources",id:"resources",children:[]},{value:"Health Checks",id:"health-checks",children:[]}]},{value:"Environment Variable",id:"environment-variable",children:[]},{value:"Secrets",id:"secrets",children:[]},{value:"Logs",id:"logs",children:[]},{value:"Clone",id:"clone",children:[]},{value:"Delete a job",id:"delete-a-job",children:[]}],p={rightToc:b};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(l.a,{name:"documentation",mdxType:"Assumptions"},Object(i.b)("p",null,"You have created an ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment"),".")),Object(i.b)("p",null,"A ",Object(i.b)("strong",{parentName:"p"},"cronjob")," is a workload that runs on your kubernetes cluster on a regular bases depending on the configured schedule (See ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/"}),"Cronjob on Kubernetes")," for more info). It is useful to execute tasks on a regular bases, like pulling data from an external service every hour or process the last 24hrs of data in your database."),Object(i.b)("p",null,"Qovery allows you to create and deploy cronjobs from two different sources: Git Repository or Container Registry"),Object(i.b)("h2",{id:"deploying-from-a-git-repository"},"Deploying from a Git Repository"),Object(i.b)("p",null,"In this configuration, Qovery will pull the code from the chosen repository, build the application and deploy it on your kubernetes cluster."),Object(i.b)("p",null,"The list of Git repositories available during the setup is strictly tied to the permissions of your git account (by default Qovery can access all your repositories). If you want to restrict the Qovery access only to a few repositories, user the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/git-repository-access/"}),"GitHub Qovery Application")," (only for Github)."),Object(i.b)("h2",{id:"deploying-from-a-container-registry"},"Deploying from a Container Registry"),Object(i.b)("p",null,"In this configuration, Qovery will pull the chosen container registry an image you have pre-built and deploy it on your kubernetes cluster."),Object(i.b)("p",null,"To improve the security and avoid deploying images from non-authorized registries, we have decided to restrict the list of Container Registry you can use during the setup process. Only an administrator with the right permissions can manage it from the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")),Object(i.b)("h2",{id:"create-a-cronjob"},"Create a Cronjob"),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,'Go into the chosen environment and press the "New Service" button and then the "Create Cronjob" button'),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/environments/service_creation.png",alt:"Creation"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Select the following fields:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Name: give a name to your applicaiton"),Object(i.b)("li",{parentName:"ul"},"Source: Chose between Git Repository or Container Registry, depending on the source location of your application")),Object(i.b)("p",null,"If you want to deploy a cronjob from a Git Repository you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Git Repository: Select the git provider hosting your code (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Branch: Select branch that Qovery should use to deploy your code"),Object(i.b)("li",{parentName:"ul"},"Root Application Path: base folder in which the code resides in your repository"),Object(i.b)("li",{parentName:"ul"},"Build Mode: only Docker is supported")),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"A Dockerfile is necessary to build and deploy your job")),Object(i.b)("p",null,"If you want to deploy a cronjob from a Container Registry you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Registry: select the container registry storing the image of your job. Note: only pre-configured registry are available in this list, check the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," for more information."),Object(i.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this job (example: postgres)"),Object(i.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this job (example: 12)")),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"The tag 'latest' is not supported, please use a specific tag.")),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Auto Deploy ")),Object(i.b)("p",null,"See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section.")),Object(i.b)("li",null,'Specify the configuration of your job: - CRON Schedule: specify a valid CRON expression (see [Crontab guru](https://crontab.guru/) for help). After being deployed, the job will be executed following the defined schedule. - Image Entrypoint: the entrypoint to be used to launch your job (not mandatory) - CMD Arguments: the arguments to be passed to launch your job (not mandatory). We expect the format to be an array. Example ["rails", "-h", "0.0.0.0", "-p", "8080", "string"] - Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure) - Max duration time in seconds: Maximum duration allowed for the job to run before killing it and mark it as failed - Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally'),Object(i.b)("li",null,"Within this section, you will need to define the resources to be assigned to your job at run time.",Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"vCPU: the vCPU assigned to each instance of your application. The default is 500m (0.5 vCPU)."),Object(i.b)("li",{parentName:"ul"},"RAM: the amount of RAM assigned to each instance of your application. The default is 512MB.")),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Please note that in this section you configure the CPU/RAM allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU/RAM."))),Object(i.b)("li",null,Object(i.b)("p",null,"Define any input variable required by your job to run. Any declared variable will be injected as environment variables based on the selected scope (project, environment, service)\nAny additional environment variable can be added later from the environment variable section"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/job/variables.png",alt:"Input Variables"}))),Object(i.b)("li",null,Object(i.b)("p",null,"You will find a recap of your job setup and you can now decide to:\n1. Go back to one of the previous steps and change your settings\n2. Create your job without deploying it\n3. Create and deploy your job"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/job/cronjob_recap.png",alt:"Recap"}))))),Object(i.b)("h2",{id:"deployment-management"},"Deployment Management"),Object(i.b)("p",null,"Have a look at the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/"}),"Deployment Management")," section for more information."),Object(i.b)("h2",{id:"force-run"},"Force Run"),Object(i.b)("p",null,"You can force the execution of a job independently its deployment status by:"),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Select the job that you want to force")),Object(i.b)("li",null,Object(i.b)("p",null,"click on the ",Object(i.b)("inlineCode",{parentName:"p"},"Play")," button of the cronjob you want to force and select the ",Object(i.b)("inlineCode",{parentName:"p"},"Force Run")," option. Note: the same option is available on the service list as well")),Object(i.b)("li",null,Object(i.b)("p",null,"Once you click, the job will be deployed and executed once. You will be able to follow its execution within the application logs")))),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"If the cronjob has not yet been deployed, forcing its execution will make it run only once (the scheduling mechanism will not start).")),Object(i.b)("h2",{id:"configuration"},"Configuration"),Object(i.b)("p",null,"Once created, you can access the configuration at any time via the Settings tab available on the service section"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/settings.png",alt:"Settings"})),Object(i.b)("p",null,"You can find below the description of each of the tabs available in this section"),Object(i.b)("h3",{id:"general"},"General"),Object(i.b)("p",null,"General settings section allows you to set up your application name and the source code location (git repository or image registry) ."),Object(i.b)("h4",{id:"git-repository"},"Git Repository"),Object(i.b)("p",null,"If your job is built and deployed from a git repository, within this section you can:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Modify the git provider where your code is stored (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Modify the branch that Qovery should use for deploying your code"),Object(i.b)("li",{parentName:"ul"},"Modify ",Object(i.b)("inlineCode",{parentName:"li"},"Root Application Path")," - base folder in which the application resides in your repository")),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Qovery supports mono repositories. ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/advanced/monorepository/"}),"See our advanced guide for more details."))),Object(i.b)(c.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"If your repository contains private submodules using SSH protocol, you will need to add a secret beginning with GIT",Object(i.b)("em",{parentName:"p"},"SSH_KEY"),", containing a private SSH key with access rights to your sumbodules repositories."),Object(i.b)("p",null,"Secret names examples:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITHUB"),Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITLAB"),Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_MYAPP"))),Object(i.b)("h4",{id:"container-registry"},"Container Registry"),Object(i.b)("p",null,"If your application is deployed from an image registry, within this section you can modify:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Registry: select the container registry storing the image of your application. Note: only pre-configured registry are available in this list, check the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," for more information."),Object(i.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this application (example: postgres)"),Object(i.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this application (example: 12)")),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"The tag 'latest' is not supported, please use a specific tag.")),Object(i.b)("h4",{id:"build-mode"},"Build Mode"),Object(i.b)("p",null,'This option is available only if you have selected "Git Repository" as source. Only Docker is supported'),Object(i.b)("p",null,"Qovery runs your application within the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://www.docker.com/resources/what-container"}),"Container technology"),". To build and run your application, you need to provide a valid ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.docker.com/engine/reference/builder"}),"Dockerfile"),"."),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-Dockerfile",metastring:'title="Valid NodeJS Dockerfile"',title:'"Valid',NodeJS:!0,'Dockerfile"':!0}),"FROM node:13-alpine\nRUN mkdir -p /usr/src/app\nWORKDIR /usr/src/app\nCOPY . .\nRUN npm install\nEXPOSE 3000\nCMD node ./bin/www\n")),Object(i.b)("p",null,"After creating a Dockerfile, specify the location of your Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"Dockefile path")," field."),Object(i.b)("p",null,"Configuration from above will make Qovery look for the Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"/timescale/Dockerfile")," path of your repository (",Object(i.b)("inlineCode",{parentName:"p"},"Root Application Path")," + ",Object(i.b)("inlineCode",{parentName:"p"},"Dockerfile Path"),")."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Auto Deploy ")),Object(i.b)("p",null,"See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section."),Object(i.b)("h3",{id:"job-configuration"},"JOB Configuration"),Object(i.b)("p",null,"You can modify here the configuration of your job:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"CRON Schedule: specify a valid CRON expression (see ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"https://crontab.guru/"}),"Crontab guru")," for help). After being deployed, the job will be executed following the defined schedule."),Object(i.b)("li",{parentName:"ul"},"Image Entrypoint: the entrypoint to be used to launch your job (not mandatory)"),Object(i.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your job (not mandatory). We expect the format to be an array. Example ",'["rails", "-h", "0.0.0.0", "-p", "8080", "string"]'),Object(i.b)("li",{parentName:"ul"},"Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure)"),Object(i.b)("li",{parentName:"ul"},"Max duration time in seconds: Maximum duration allowed for the job to run before killing it and mark it as failed"),Object(i.b)("li",{parentName:"ul"},"Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally")),Object(i.b)("h3",{id:"resources"},"Resources"),Object(i.b)("h4",{id:"cpu"},"CPU"),Object(i.b)("p",null,"To configure the number of CPUs that your job needs, adjust the setting in the ",Object(i.b)("inlineCode",{parentName:"p"},"Resources")," section."),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Default is 500m (0.5 vCPU). ")),Object(i.b)("p",null,"Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU."),Object(i.b)("h4",{id:"ram"},"RAM"),Object(i.b)("p",null,"To configure the amount of RAM that your app needs, adjust the setting in ",Object(i.b)("inlineCode",{parentName:"p"},"Resources")," section."),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Default is 512MB.")),Object(i.b)("p",null,"Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU. If your application requires more RAM than requested, it will be killed by the kubernetes scheduler."),Object(i.b)("h3",{id:"health-checks"},"Health Checks"),Object(i.b)("p",null,"To know more about how to configure your Liveness and Readiness probes, have a look at ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application-health-checks/"}),"the health-checks section")),Object(i.b)("h2",{id:"environment-variable"},"Environment Variable"),Object(i.b)("p",null,"To learn how to set up environment variables in your projects and applications, navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Environment Variables")," section."),Object(i.b)("h2",{id:"secrets"},"Secrets"),Object(i.b)("p",null,"To learn how to set up secrets in your projects and applications, navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Secrets")," section."),Object(i.b)("h2",{id:"logs"},"Logs"),Object(i.b)("p",null,"To learn how to display your application logs, navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#live-logs"}),"logs section")),Object(i.b)("h2",{id:"clone"},"Clone"),Object(i.b)("p",null,"You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/clone_service.png",alt:"Clone Service"})),Object(i.b)("p",null,"The target environment can be the same as the current environment or even another one in a completely different project."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Important information ")),Object(i.b)("p",null,"Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"same environment:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"))),Object(i.b)("li",{parentName:"ul"},"another environment:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"),Object(i.b)("li",{parentName:"ul"},"environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)"),Object(i.b)("li",{parentName:"ul"},"deployment pipeline: stage setup is not copied (since the target stage might not exist)"),Object(i.b)("li",{parentName:"ul"},"number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)")))),Object(i.b)("p",null,"Please check the configuration of the new service before deploying it."),Object(i.b)("h2",{id:"delete-a-job"},"Delete a job"),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Select the job you want to delete")),Object(i.b)("li",null,Object(i.b)("p",null,"In the overview, click on the ",Object(i.b)("inlineCode",{parentName:"p"},"3 dots")," button and remove the job. Note: the same option is available on the service list as well"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-1.png",alt:"Application"}))))))}d.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},b=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),d=o,h=b["".concat(a,".").concat(d)]||b[d]||p[d]||i;return n?r.a.createElement(h,c({ref:t},s,{components:n})):r.a.createElement(h,c({ref:t},s))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,a[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=a>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var o=n(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var o=n(0),r=n.n(o),i=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var o=n(1),r=n(0),i=n.n(r),a=n(39),c=n(432),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,b=Object(c.a)(u),p=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,b]),u&&b?i.a.createElement(a.b,Object(o.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,o;d&&e&&b&&(n=e,o=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:u})):i.a.createElement("a",Object(o.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=n(430),a=n(423),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,a=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,b=e.to,p=c()("jump-to","jump-to--"+s,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},a&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+a})),r.a.createElement("div",{className:"jump-to--main"},o?r.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:b,target:u,className:p},d):r.a.createElement(i.a,{to:b,className:p},d)}},432:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},433:function(e,t,n){"use strict";var o=n(435),r=n(51);function i(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(r),i,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[i(t,e),"[",o,"]"].join(""):[i(t,e),"[",i(o,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return i(o,t);if(Array.isArray(r)){var a=[];return r.slice().forEach((function(e){void 0!==e&&a.push(n(o,e,a.length))})),a.join("&")}return i(o,t)+"="+i(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(423),n(433)),a=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(l),u=Object(o.useState)(null),b=u[0],p=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/55ef6d6a.7a5112f2.js.LICENSE.txt b/54ad54c7.723b1ad6.js.LICENSE.txt similarity index 100% rename from 55ef6d6a.7a5112f2.js.LICENSE.txt rename to 54ad54c7.723b1ad6.js.LICENSE.txt diff --git a/54e7632e.66383920.js b/54e7632e.c06ee927.js similarity index 97% rename from 54e7632e.66383920.js rename to 54e7632e.c06ee927.js index d3d42bfb0b..21504ceb0a 100644 --- a/54e7632e.66383920.js +++ b/54e7632e.c06ee927.js @@ -1,2 +1,2 @@ -/*! For license information please see 54e7632e.66383920.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[97],{416:function(e,u,t){"use strict";t.r(u);var n={};t.r(n),t.d(n,"now",(function(){return g})),t.d(n,"timer",(function(){return w})),t.d(n,"timerFlush",(function(){return E})),t.d(n,"timeout",(function(){return k})),t.d(n,"interval",(function(){return j}));var d,r,a=t(0),c=t.n(a),o=t(558),i=t(442),f=t(427),l=(t(423),t(84),0),s=0,p=0,m=0,h=0,v=0,b="object"==typeof performance&&performance.now?performance:Date,y="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(e){setTimeout(e,17)};function g(){return h||(y(_),h=b.now()+v)}function _(){h=0}function x(){this._call=this._time=this._next=null}function w(e,u,t){var n=new x;return n.restart(e,u,t),n}function E(){g(),++l;for(var e,u=d;u;)(e=h-u._time)>=0&&u._call.call(null,e),u=u._next;--l}function I(){h=(m=b.now())+v,l=s=0;try{E()}finally{l=0,function(){var e,u,t=d,n=1/0;for(;t;)t._call?(n>t._time&&(n=t._time),e=t,t=t._next):(u=t._next,t._next=null,t=e?e._next=u:d=u);r=e,A(n)}(),h=0}}function S(){var e=b.now(),u=e-m;u>1e3&&(v-=u,m=e)}function A(e){l||(s&&(s=clearTimeout(s)),e-h>24?(e<1/0&&(s=setTimeout(I,e-b.now()-v)),p&&(p=clearInterval(p))):(p||(m=b.now(),p=setInterval(S,1e3)),l=1,y(I)))}x.prototype=w.prototype={constructor:x,restart:function(e,u,t){if("function"!=typeof e)throw new TypeError("callback is not a function");t=(null==t?g():+t)+(null==u?0:+u),this._next||r===this||(r?r._next=this:d=this,r=this),this._call=e,this._time=t,A()},stop:function(){this._call&&(this._call=null,this._time=1/0,A())}};var k=function(e,u,t){var n=new x;return u=null==u?0:+u,n.restart((function(t){n.stop(),e(t+u)}),u,t),n},j=function(e,u,t){var n=new x,d=u;return null==u?(n.restart(e,u,t),n):(u=+u,t=null==t?g():+t,n.restart((function r(a){a+=d,n.restart(r,d+=u,t),e(a)}),u,t),n)},O=Object.assign({},n);t(433);u.default=function(e){return Object(a.useEffect)((function(){if("undefined"!=typeof document){var e=function(e){for(var u=e.getContext("2d"),t=e.width,n=e.height,d=2*Math.PI,r=200,a=new Array(r),c=0;ct+45&&(o.x-=t+90),o.y+=o.vy,o.y<-45?o.y+=n+90:o.y>n+45&&(o.y-=n+90),o.vx+=.2*(Math.random()-.5)-.01*o.vx,o.vy+=.2*(Math.random()-.5)-.01*o.vy,u.beginPath(),u.arc(o.x,o.y,3,0,d),u.fillStyle="rgba(40,217,242,0.4)",u.fill()}for(c=0;c3600?(2025-m)/-1575:1,u.beginPath(),u.moveTo(f.x,f.y),u.lineTo(l.x,l.y),u.strokeStyle="rgba(40,217,242,0.3)",u.stroke())}u.restore()}))}(document.querySelector("canvas"));return function(){e.stop()}}}),[]),c.a.createElement(i.a,{title:"Components - Sources, Transforms, & Sinks",description:"Browse and search all of Qovery's components: sources, transforms, and sinks. Filter by event type, guarantee, function, operating system, and provider."},c.a.createElement("header",{className:"hero hero--animated-graph"},c.a.createElement("div",{className:"container container--fluid container--flush"},c.a.createElement("canvas",{width:"2000",height:"200"}),c.a.createElement("div",{className:"overlay"},c.a.createElement("h1",null,"Qovery Components"),c.a.createElement("div",{className:"hero--subtitle"},"Components allow you to collect, transform, and route data with ease. ",c.a.createElement(f.a,{to:"/docs/getting-started/concepts/"},"Learn more"),".")))),c.a.createElement("main",{className:"container"},c.a.createElement(o.a,{filterColumn:!0,headingLevel:2,location:e.location})))}},420:function(e,u,t){var n;!function(){"use strict";var t={}.hasOwnProperty;function d(){for(var e=[],u=0;u1?arguments[1]:void 0,t),o=a>2?arguments[2]:void 0,i=void 0===o?t:d(o,t);i>c;)u[c++]=e;return u}},425:function(e,u,t){var n=t(28).f,d=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in d||t(10)&&n(d,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,u,t){"use strict";var n=t(0),d=t.n(n),r=t(427),a=t(420),c=t.n(a);t(133);u.a=function(e){var u=e.children,t=e.className,n=e.badge,a=e.leftIcon,o=e.rightIcon,i=e.size,f=e.target,l=e.to,s=c()("jump-to","jump-to--"+i,t),p=d.a.createElement("div",{className:"jump-to--inner"},d.a.createElement("div",{className:"jump-to--inner-2"},a&&d.a.createElement("div",{className:"jump-to--left"},d.a.createElement("i",{className:"feather icon-"+a})),d.a.createElement("div",{className:"jump-to--main"},n?d.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",u),d.a.createElement("div",{className:"jump-to--right"},d.a.createElement("i",{className:"feather icon-"+(o||"chevron-right")+" arrow"}))));return f?d.a.createElement("a",{href:l,target:f,className:s},p):d.a.createElement(r.a,{to:l,className:s},p)}},439:function(e,u,t){"use strict";var n=t(8),d=t(483),r=t(55);t(56)("search",1,(function(e,u,t,a){return[function(t){var n=e(this),d=null==t?void 0:t[u];return void 0!==d?d.call(t,n):new RegExp(t)[u](String(n))},function(e){var u=a(t,e,this);if(u.done)return u.value;var c=n(e),o=String(this),i=c.lastIndex;d(i,0)||(c.lastIndex=0);var f=r(c,o);return d(c.lastIndex,i)||(c.lastIndex=i),null===f?-1:f.index}]}))},442:function(e,u,t){"use strict";t(454);var n=t(0),d=t.n(n),r=t(455),a=t(440),c=t(1),o=(t(443),t(444),t(456),t(427)),i=t(457),f=t(437),l=t.n(f),s=t(458),p=t.n(s),m=t(433),h=t(420),v=t.n(h),b=t(135),y=t.n(b),g=function(){return d.a.createElement("span",{className:v()(y.a.toggle,y.a.moon)})},_=function(){return d.a.createElement("span",{className:v()(y.a.toggle,y.a.sun)})},x=function(e){var u=Object(m.a)().isClient;return d.a.createElement(p.a,Object(c.a)({disabled:!u,icons:{checked:d.a.createElement(g,null),unchecked:d.a.createElement(_,null)}},e))};function w(){var e=Object(m.a)().siteConfig,u=(void 0===e?{}:e).customFields.metadata.latest_post,t=Date.parse(u.date),n=new Date,d=Math.abs(n-t),r=Math.ceil(d/864e5),a=null;return"undefined"!=typeof window&&(a=new Date(parseInt(window.localStorage.getItem("blogViewedAt")||"0"))),r<30&&(!a||a0&&d.a.createElement("div",{className:"row footer__links"},d.a.createElement("div",{className:"col col--5 footer__col"},d.a.createElement("div",{className:"margin-bottom--md"},d.a.createElement(l.a,{className:"navbar__logo",src:p,alt:"Qovery",width:"150",height:"auto"})),d.a.createElement("div",{className:"margin-bottom--md"},d.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),d.a.createElement("div",null,d.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},d.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",d.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},d.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",d.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},d.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",d.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},d.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),o.map((function(e,u){return d.a.createElement("div",{key:u,className:"col footer__col"},null!=e.title?d.a.createElement("h4",{className:"footer__title"},e.title):null,null!=e.items&&Array.isArray(e.items)&&e.items.length>0?d.a.createElement("ul",{className:"footer__items"},e.items.map((function(e,u){return e.html?d.a.createElement("li",{key:u,className:"footer__item",dangerouslySetInnerHTML:{__html:e.html}}):d.a.createElement("li",{key:e.href||e.to,className:"footer__item"},d.a.createElement(L,e))}))):null)}))),(f||a)&&d.a.createElement("div",{className:"text--center"},f&&f.src&&d.a.createElement("div",{className:"margin-bottom--sm"},f.href?d.a.createElement("a",{href:f.href,target:"_blank",rel:"noopener noreferrer",className:R.a.footerLogoLink},d.a.createElement(F,{alt:f.alt,url:s})):d.a.createElement(F,{alt:f.alt,url:s})),d.a.createElement("small",null,a),d.a.createElement("br",null))))},D=t(459),U=t(460),z=t(3);t(138);u.a=function(e){var u=Object(m.a)().siteConfig,t=void 0===u?{}:u,n=t.favicon,c=(t.tagline,t.title),o=t.themeConfig.image,i=t.url,f=e.children,l=e.title,s=e.noFooter,p=e.description,h=e.image,v=e.keywords,b=(e.permalink,e.version),y=l?l+" | "+c:c,g=h||o,_=i+Object(I.a)(g),x=Object(I.a)(n),w=Object(z.h)(),E=w?"https://docs.qovery.com"+(w.pathname.endsWith("/")?w.pathname:w.pathname+"/"):null;return d.a.createElement(U.a,null,d.a.createElement(D.a,null,d.a.createElement(a.a,null,d.a.createElement("html",{lang:"en"}),d.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),y&&d.a.createElement("title",null,y),y&&d.a.createElement("meta",{property:"og:title",content:y}),n&&d.a.createElement("link",{rel:"shortcut icon",href:x}),p&&d.a.createElement("meta",{name:"description",content:p}),p&&d.a.createElement("meta",{property:"og:description",content:p}),b&&d.a.createElement("meta",{name:"docsearch:version",content:b}),v&&v.length&&d.a.createElement("meta",{name:"keywords",content:v.join(",")}),g&&d.a.createElement("meta",{property:"og:image",content:_}),g&&d.a.createElement("meta",{property:"twitter:image",content:_}),g&&d.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+y}),E&&d.a.createElement("meta",{property:"og:url",content:E}),d.a.createElement("meta",{name:"twitter:card",content:"summary"}),E&&d.a.createElement("link",{rel:"canonical",href:E})),d.a.createElement(r.a,null),d.a.createElement(P,null),d.a.createElement("div",{className:"main-wrapper"},f),!s&&d.a.createElement(B,null)))}},448:function(e,u,t){(function(e,n){var d;(function(){var r="Expected a function",a="__lodash_placeholder__",c=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],o="[object Arguments]",i="[object Array]",f="[object Boolean]",l="[object Date]",s="[object Error]",p="[object Function]",m="[object GeneratorFunction]",h="[object Map]",v="[object Number]",b="[object Object]",y="[object RegExp]",g="[object Set]",_="[object String]",x="[object Symbol]",w="[object WeakMap]",E="[object ArrayBuffer]",I="[object DataView]",S="[object Float32Array]",A="[object Float64Array]",k="[object Int8Array]",j="[object Int16Array]",O="[object Int32Array]",N="[object Uint8Array]",C="[object Uint16Array]",P="[object Uint32Array]",T=/\b__p \+= '';/g,M=/\b(__p \+=) '' \+/g,R=/(__e\(.*?\)|\b__t\)) \+\n'';/g,L=/&(?:amp|lt|gt|quot|#39);/g,F=/[&<>"']/g,B=RegExp(L.source),D=RegExp(F.source),U=/<%-([\s\S]+?)%>/g,z=/<%([\s\S]+?)%>/g,W=/<%=([\s\S]+?)%>/g,$=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,G=/^\w*$/,q=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,H=/[\\^$.*+?()[\]{}|]/g,K=RegExp(H.source),V=/^\s+|\s+$/g,J=/^\s+/,Z=/\s+$/,Q=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Y=/\{\n\/\* \[wrapped with (.+)\] \*/,X=/,? & /,ee=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,ue=/\\(\\)?/g,te=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,ne=/\w*$/,de=/^[-+]0x[0-9a-f]+$/i,re=/^0b[01]+$/i,ae=/^\[object .+?Constructor\]$/,ce=/^0o[0-7]+$/i,oe=/^(?:0|[1-9]\d*)$/,ie=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,fe=/($^)/,le=/['\n\r\u2028\u2029\\]/g,se="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",pe="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",me="[\\ud800-\\udfff]",he="["+pe+"]",ve="["+se+"]",be="\\d+",ye="[\\u2700-\\u27bf]",ge="[a-z\\xdf-\\xf6\\xf8-\\xff]",_e="[^\\ud800-\\udfff"+pe+be+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",xe="\\ud83c[\\udffb-\\udfff]",we="[^\\ud800-\\udfff]",Ee="(?:\\ud83c[\\udde6-\\uddff]){2}",Ie="[\\ud800-\\udbff][\\udc00-\\udfff]",Se="[A-Z\\xc0-\\xd6\\xd8-\\xde]",Ae="(?:"+ge+"|"+_e+")",ke="(?:"+Se+"|"+_e+")",je="(?:"+ve+"|"+xe+")"+"?",Oe="[\\ufe0e\\ufe0f]?"+je+("(?:\\u200d(?:"+[we,Ee,Ie].join("|")+")[\\ufe0e\\ufe0f]?"+je+")*"),Ne="(?:"+[ye,Ee,Ie].join("|")+")"+Oe,Ce="(?:"+[we+ve+"?",ve,Ee,Ie,me].join("|")+")",Pe=RegExp("['\u2019]","g"),Te=RegExp(ve,"g"),Me=RegExp(xe+"(?="+xe+")|"+Ce+Oe,"g"),Re=RegExp([Se+"?"+ge+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?="+[he,Se,"$"].join("|")+")",ke+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?="+[he,Se+Ae,"$"].join("|")+")",Se+"?"+Ae+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?",Se+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",be,Ne].join("|"),"g"),Le=RegExp("[\\u200d\\ud800-\\udfff"+se+"\\ufe0e\\ufe0f]"),Fe=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Be=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],De=-1,Ue={};Ue[S]=Ue[A]=Ue[k]=Ue[j]=Ue[O]=Ue[N]=Ue["[object Uint8ClampedArray]"]=Ue[C]=Ue[P]=!0,Ue[o]=Ue[i]=Ue[E]=Ue[f]=Ue[I]=Ue[l]=Ue[s]=Ue[p]=Ue[h]=Ue[v]=Ue[b]=Ue[y]=Ue[g]=Ue[_]=Ue[w]=!1;var ze={};ze[o]=ze[i]=ze[E]=ze[I]=ze[f]=ze[l]=ze[S]=ze[A]=ze[k]=ze[j]=ze[O]=ze[h]=ze[v]=ze[b]=ze[y]=ze[g]=ze[_]=ze[x]=ze[N]=ze["[object Uint8ClampedArray]"]=ze[C]=ze[P]=!0,ze[s]=ze[p]=ze[w]=!1;var We={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},$e=parseFloat,Ge=parseInt,qe="object"==typeof e&&e&&e.Object===Object&&e,He="object"==typeof self&&self&&self.Object===Object&&self,Ke=qe||He||Function("return this")(),Ve=u&&!u.nodeType&&u,Je=Ve&&"object"==typeof n&&n&&!n.nodeType&&n,Ze=Je&&Je.exports===Ve,Qe=Ze&&qe.process,Ye=function(){try{var e=Je&&Je.require&&Je.require("util").types;return e||Qe&&Qe.binding&&Qe.binding("util")}catch(u){}}(),Xe=Ye&&Ye.isArrayBuffer,eu=Ye&&Ye.isDate,uu=Ye&&Ye.isMap,tu=Ye&&Ye.isRegExp,nu=Ye&&Ye.isSet,du=Ye&&Ye.isTypedArray;function ru(e,u,t){switch(t.length){case 0:return e.call(u);case 1:return e.call(u,t[0]);case 2:return e.call(u,t[0],t[1]);case 3:return e.call(u,t[0],t[1],t[2])}return e.apply(u,t)}function au(e,u,t,n){for(var d=-1,r=null==e?0:e.length;++d-1}function su(e,u,t){for(var n=-1,d=null==e?0:e.length;++n-1;);return t}function Mu(e,u){for(var t=e.length;t--&&xu(u,e[t],0)>-1;);return t}function Ru(e,u){for(var t=e.length,n=0;t--;)e[t]===u&&++n;return n}var Lu=Au({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),Fu=Au({"&":"&","<":"<",">":">",'"':""","'":"'"});function Bu(e){return"\\"+We[e]}function Du(e){return Le.test(e)}function Uu(e){var u=-1,t=Array(e.size);return e.forEach((function(e,n){t[++u]=[n,e]})),t}function zu(e,u){return function(t){return e(u(t))}}function Wu(e,u){for(var t=-1,n=e.length,d=0,r=[];++t",""":'"',"'":"'"});var Vu=function e(u){var t,n=(u=null==u?Ke:Vu.defaults(Ke.Object(),u,Vu.pick(Ke,Be))).Array,d=u.Date,se=u.Error,pe=u.Function,me=u.Math,he=u.Object,ve=u.RegExp,be=u.String,ye=u.TypeError,ge=n.prototype,_e=pe.prototype,xe=he.prototype,we=u["__core-js_shared__"],Ee=_e.toString,Ie=xe.hasOwnProperty,Se=0,Ae=(t=/[^.]+$/.exec(we&&we.keys&&we.keys.IE_PROTO||""))?"Symbol(src)_1."+t:"",ke=xe.toString,je=Ee.call(he),Oe=Ke._,Ne=ve("^"+Ee.call(Ie).replace(H,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Ce=Ze?u.Buffer:void 0,Me=u.Symbol,Le=u.Uint8Array,We=Ce?Ce.allocUnsafe:void 0,qe=zu(he.getPrototypeOf,he),He=he.create,Ve=xe.propertyIsEnumerable,Je=ge.splice,Qe=Me?Me.isConcatSpreadable:void 0,Ye=Me?Me.iterator:void 0,yu=Me?Me.toStringTag:void 0,Au=function(){try{var e=Xd(he,"defineProperty");return e({},"",{}),e}catch(u){}}(),Ju=u.clearTimeout!==Ke.clearTimeout&&u.clearTimeout,Zu=d&&d.now!==Ke.Date.now&&d.now,Qu=u.setTimeout!==Ke.setTimeout&&u.setTimeout,Yu=me.ceil,Xu=me.floor,et=he.getOwnPropertySymbols,ut=Ce?Ce.isBuffer:void 0,tt=u.isFinite,nt=ge.join,dt=zu(he.keys,he),rt=me.max,at=me.min,ct=d.now,ot=u.parseInt,it=me.random,ft=ge.reverse,lt=Xd(u,"DataView"),st=Xd(u,"Map"),pt=Xd(u,"Promise"),mt=Xd(u,"Set"),ht=Xd(u,"WeakMap"),vt=Xd(he,"create"),bt=ht&&new ht,yt={},gt=Ar(lt),_t=Ar(st),xt=Ar(pt),wt=Ar(mt),Et=Ar(ht),It=Me?Me.prototype:void 0,St=It?It.valueOf:void 0,At=It?It.toString:void 0;function kt(e){if($a(e)&&!Pa(e)&&!(e instanceof Ct)){if(e instanceof Nt)return e;if(Ie.call(e,"__wrapped__"))return kr(e)}return new Nt(e)}var jt=function(){function e(){}return function(u){if(!Wa(u))return{};if(He)return He(u);e.prototype=u;var t=new e;return e.prototype=void 0,t}}();function Ot(){}function Nt(e,u){this.__wrapped__=e,this.__actions__=[],this.__chain__=!!u,this.__index__=0,this.__values__=void 0}function Ct(e){this.__wrapped__=e,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Pt(e){var u=-1,t=null==e?0:e.length;for(this.clear();++u=u?e:u)),e}function Jt(e,u,t,n,d,r){var a,c=1&u,i=2&u,s=4&u;if(t&&(a=d?t(e,n,d,r):t(e)),void 0!==a)return a;if(!Wa(e))return e;var w=Pa(e);if(w){if(a=function(e){var u=e.length,t=new e.constructor(u);u&&"string"==typeof e[0]&&Ie.call(e,"index")&&(t.index=e.index,t.input=e.input);return t}(e),!c)return bd(e,a)}else{var T=tr(e),M=T==p||T==m;if(La(e))return ld(e,c);if(T==b||T==o||M&&!d){if(a=i||M?{}:dr(e),!c)return i?function(e,u){return yd(e,ur(e),u)}(e,function(e,u){return e&&yd(u,_c(u),e)}(a,e)):function(e,u){return yd(e,er(e),u)}(e,qt(a,e))}else{if(!ze[T])return d?e:{};a=function(e,u,t){var n=e.constructor;switch(u){case E:return sd(e);case f:case l:return new n(+e);case I:return function(e,u){var t=u?sd(e.buffer):e.buffer;return new e.constructor(t,e.byteOffset,e.byteLength)}(e,t);case S:case A:case k:case j:case O:case N:case"[object Uint8ClampedArray]":case C:case P:return pd(e,t);case h:return new n;case v:case _:return new n(e);case y:return function(e){var u=new e.constructor(e.source,ne.exec(e));return u.lastIndex=e.lastIndex,u}(e);case g:return new n;case x:return d=e,St?he(St.call(d)):{}}var d}(e,T,c)}}r||(r=new Lt);var R=r.get(e);if(R)return R;r.set(e,a),Va(e)?e.forEach((function(n){a.add(Jt(n,u,t,n,e,r))})):Ga(e)&&e.forEach((function(n,d){a.set(d,Jt(n,u,t,d,e,r))}));var L=w?void 0:(s?i?Hd:qd:i?_c:gc)(e);return cu(L||e,(function(n,d){L&&(n=e[d=n]),Wt(a,d,Jt(n,u,t,d,e,r))})),a}function Zt(e,u,t){var n=t.length;if(null==e)return!n;for(e=he(e);n--;){var d=t[n],r=u[d],a=e[d];if(void 0===a&&!(d in e)||!r(a))return!1}return!0}function Qt(e,u,t){if("function"!=typeof e)throw new ye(r);return gr((function(){e.apply(void 0,t)}),u)}function Yt(e,u,t,n){var d=-1,r=lu,a=!0,c=e.length,o=[],i=u.length;if(!c)return o;t&&(u=pu(u,Nu(t))),n?(r=su,a=!1):u.length>=200&&(r=Pu,a=!1,u=new Rt(u));e:for(;++d-1},Tt.prototype.set=function(e,u){var t=this.__data__,n=$t(t,e);return n<0?(++this.size,t.push([e,u])):t[n][1]=u,this},Mt.prototype.clear=function(){this.size=0,this.__data__={hash:new Pt,map:new(st||Tt),string:new Pt}},Mt.prototype.delete=function(e){var u=Qd(this,e).delete(e);return this.size-=u?1:0,u},Mt.prototype.get=function(e){return Qd(this,e).get(e)},Mt.prototype.has=function(e){return Qd(this,e).has(e)},Mt.prototype.set=function(e,u){var t=Qd(this,e),n=t.size;return t.set(e,u),this.size+=t.size==n?0:1,this},Rt.prototype.add=Rt.prototype.push=function(e){return this.__data__.set(e,"__lodash_hash_undefined__"),this},Rt.prototype.has=function(e){return this.__data__.has(e)},Lt.prototype.clear=function(){this.__data__=new Tt,this.size=0},Lt.prototype.delete=function(e){var u=this.__data__,t=u.delete(e);return this.size=u.size,t},Lt.prototype.get=function(e){return this.__data__.get(e)},Lt.prototype.has=function(e){return this.__data__.has(e)},Lt.prototype.set=function(e,u){var t=this.__data__;if(t instanceof Tt){var n=t.__data__;if(!st||n.length<199)return n.push([e,u]),this.size=++t.size,this;t=this.__data__=new Mt(n)}return t.set(e,u),this.size=t.size,this};var Xt=xd(cn),en=xd(on,!0);function un(e,u){var t=!0;return Xt(e,(function(e,n,d){return t=!!u(e,n,d)})),t}function tn(e,u,t){for(var n=-1,d=e.length;++n0&&t(c)?u>1?dn(c,u-1,t,n,d):mu(d,c):n||(d[d.length]=c)}return d}var rn=wd(),an=wd(!0);function cn(e,u){return e&&rn(e,u,gc)}function on(e,u){return e&&an(e,u,gc)}function fn(e,u){return fu(u,(function(u){return Da(e[u])}))}function ln(e,u){for(var t=0,n=(u=cd(u,e)).length;null!=e&&tu}function hn(e,u){return null!=e&&Ie.call(e,u)}function vn(e,u){return null!=e&&u in he(e)}function bn(e,u,t){for(var d=t?su:lu,r=e[0].length,a=e.length,c=a,o=n(a),i=1/0,f=[];c--;){var l=e[c];c&&u&&(l=pu(l,Nu(u))),i=at(l.length,i),o[c]=!t&&(u||r>=120&&l.length>=120)?new Rt(c&&l):void 0}l=e[0];var s=-1,p=o[0];e:for(;++s=c)return o;var i=t[n];return o*("desc"==i?-1:1)}}return e.index-u.index}(e,u,t)}))}function Tn(e,u,t){for(var n=-1,d=u.length,r={};++n-1;)c!==e&&Je.call(c,o,1),Je.call(e,o,1);return e}function Rn(e,u){for(var t=e?u.length:0,n=t-1;t--;){var d=u[t];if(t==n||d!==r){var r=d;ar(d)?Je.call(e,d,1):Xn(e,d)}}return e}function Ln(e,u){return e+Xu(it()*(u-e+1))}function Fn(e,u){var t="";if(!e||u<1||u>9007199254740991)return t;do{u%2&&(t+=e),(u=Xu(u/2))&&(e+=e)}while(u);return t}function Bn(e,u){return _r(mr(e,u,qc),e+"")}function Dn(e){return Bt(jc(e))}function Un(e,u){var t=jc(e);return Er(t,Vt(u,0,t.length))}function zn(e,u,t,n){if(!Wa(e))return e;for(var d=-1,r=(u=cd(u,e)).length,a=r-1,c=e;null!=c&&++dr?0:r+u),(t=t>r?r:t)<0&&(t+=r),r=u>t?0:t-u>>>0,u>>>=0;for(var a=n(r);++d>>1,a=e[r];null!==a&&!Za(a)&&(t?a<=u:a=200){var i=u?null:Fd(e);if(i)return $u(i);a=!1,d=Pu,o=new Rt}else o=u?[]:c;e:for(;++n=n?e:qn(e,u,t)}var fd=Ju||function(e){return Ke.clearTimeout(e)};function ld(e,u){if(u)return e.slice();var t=e.length,n=We?We(t):new e.constructor(t);return e.copy(n),n}function sd(e){var u=new e.constructor(e.byteLength);return new Le(u).set(new Le(e)),u}function pd(e,u){var t=u?sd(e.buffer):e.buffer;return new e.constructor(t,e.byteOffset,e.length)}function md(e,u){if(e!==u){var t=void 0!==e,n=null===e,d=e==e,r=Za(e),a=void 0!==u,c=null===u,o=u==u,i=Za(u);if(!c&&!i&&!r&&e>u||r&&a&&o&&!c&&!i||n&&a&&o||!t&&o||!d)return 1;if(!n&&!r&&!i&&e1?t[d-1]:void 0,a=d>2?t[2]:void 0;for(r=e.length>3&&"function"==typeof r?(d--,r):void 0,a&&cr(t[0],t[1],a)&&(r=d<3?void 0:r,d=1),u=he(u);++n-1?d[r?u[a]:a]:void 0}}function kd(e){return Gd((function(u){var t=u.length,n=t,d=Nt.prototype.thru;for(e&&u.reverse();n--;){var a=u[n];if("function"!=typeof a)throw new ye(r);if(d&&!c&&"wrapper"==Vd(a))var c=new Nt([],!0)}for(n=c?n:t;++n1&&g.reverse(),l&&ic))return!1;var i=r.get(e);if(i&&r.get(u))return i==u;var f=-1,l=!0,s=2&t?new Rt:void 0;for(r.set(e,u),r.set(u,e);++f-1&&e%1==0&&e1?"& ":"")+u[n],u=u.join(t>2?", ":" "),e.replace(Q,"{\n/* [wrapped with "+u+"] */\n")}(n,function(e,u){return cu(c,(function(t){var n="_."+t[0];u&t[1]&&!lu(e,n)&&e.push(n)})),e.sort()}(function(e){var u=e.match(Y);return u?u[1].split(X):[]}(n),t)))}function wr(e){var u=0,t=0;return function(){var n=ct(),d=16-(n-t);if(t=n,d>0){if(++u>=800)return arguments[0]}else u=0;return e.apply(void 0,arguments)}}function Er(e,u){var t=-1,n=e.length,d=n-1;for(u=void 0===u?n:u;++t1?e[u-1]:void 0;return t="function"==typeof t?(e.pop(),t):void 0,Kr(e,t)}));function ea(e){var u=kt(e);return u.__chain__=!0,u}function ua(e,u){return u(e)}var ta=Gd((function(e){var u=e.length,t=u?e[0]:0,n=this.__wrapped__,d=function(u){return Kt(u,e)};return!(u>1||this.__actions__.length)&&n instanceof Ct&&ar(t)?((n=n.slice(t,+t+(u?1:0))).__actions__.push({func:ua,args:[d],thisArg:void 0}),new Nt(n,this.__chain__).thru((function(e){return u&&!e.length&&e.push(void 0),e}))):this.thru(d)}));var na=gd((function(e,u,t){Ie.call(e,t)?++e[t]:Ht(e,t,1)}));var da=Ad(Cr),ra=Ad(Pr);function aa(e,u){return(Pa(e)?cu:Xt)(e,Zd(u,3))}function ca(e,u){return(Pa(e)?ou:en)(e,Zd(u,3))}var oa=gd((function(e,u,t){Ie.call(e,t)?e[t].push(u):Ht(e,t,[u])}));var ia=Bn((function(e,u,t){var d=-1,r="function"==typeof u,a=Ma(e)?n(e.length):[];return Xt(e,(function(e){a[++d]=r?ru(u,e,t):yn(e,u,t)})),a})),fa=gd((function(e,u,t){Ht(e,t,u)}));function la(e,u){return(Pa(e)?pu:kn)(e,Zd(u,3))}var sa=gd((function(e,u,t){e[t?0:1].push(u)}),(function(){return[[],[]]}));var pa=Bn((function(e,u){if(null==e)return[];var t=u.length;return t>1&&cr(e,u[0],u[1])?u=[]:t>2&&cr(u[0],u[1],u[2])&&(u=[u[0]]),Pn(e,dn(u,1),[])})),ma=Zu||function(){return Ke.Date.now()};function ha(e,u,t){return u=t?void 0:u,Dd(e,128,void 0,void 0,void 0,void 0,u=e&&null==u?e.length:u)}function va(e,u){var t;if("function"!=typeof u)throw new ye(r);return e=tc(e),function(){return--e>0&&(t=u.apply(this,arguments)),e<=1&&(u=void 0),t}}var ba=Bn((function(e,u,t){var n=1;if(t.length){var d=Wu(t,Jd(ba));n|=32}return Dd(e,n,u,t,d)})),ya=Bn((function(e,u,t){var n=3;if(t.length){var d=Wu(t,Jd(ya));n|=32}return Dd(u,n,e,t,d)}));function ga(e,u,t){var n,d,a,c,o,i,f=0,l=!1,s=!1,p=!0;if("function"!=typeof e)throw new ye(r);function m(u){var t=n,r=d;return n=d=void 0,f=u,c=e.apply(r,t)}function h(e){return f=e,o=gr(b,u),l?m(e):c}function v(e){var t=e-i;return void 0===i||t>=u||t<0||s&&e-f>=a}function b(){var e=ma();if(v(e))return y(e);o=gr(b,function(e){var t=u-(e-i);return s?at(t,a-(e-f)):t}(e))}function y(e){return o=void 0,p&&n?m(e):(n=d=void 0,c)}function g(){var e=ma(),t=v(e);if(n=arguments,d=this,i=e,t){if(void 0===o)return h(i);if(s)return fd(o),o=gr(b,u),m(i)}return void 0===o&&(o=gr(b,u)),c}return u=dc(u)||0,Wa(t)&&(l=!!t.leading,a=(s="maxWait"in t)?rt(dc(t.maxWait)||0,u):a,p="trailing"in t?!!t.trailing:p),g.cancel=function(){void 0!==o&&fd(o),f=0,n=i=d=o=void 0},g.flush=function(){return void 0===o?c:y(ma())},g}var _a=Bn((function(e,u){return Qt(e,1,u)})),xa=Bn((function(e,u,t){return Qt(e,dc(u)||0,t)}));function wa(e,u){if("function"!=typeof e||null!=u&&"function"!=typeof u)throw new ye(r);var t=function(){var n=arguments,d=u?u.apply(this,n):n[0],r=t.cache;if(r.has(d))return r.get(d);var a=e.apply(this,n);return t.cache=r.set(d,a)||r,a};return t.cache=new(wa.Cache||Mt),t}function Ea(e){if("function"!=typeof e)throw new ye(r);return function(){var u=arguments;switch(u.length){case 0:return!e.call(this);case 1:return!e.call(this,u[0]);case 2:return!e.call(this,u[0],u[1]);case 3:return!e.call(this,u[0],u[1],u[2])}return!e.apply(this,u)}}wa.Cache=Mt;var Ia=od((function(e,u){var t=(u=1==u.length&&Pa(u[0])?pu(u[0],Nu(Zd())):pu(dn(u,1),Nu(Zd()))).length;return Bn((function(n){for(var d=-1,r=at(n.length,t);++d=u})),Ca=gn(function(){return arguments}())?gn:function(e){return $a(e)&&Ie.call(e,"callee")&&!Ve.call(e,"callee")},Pa=n.isArray,Ta=Xe?Nu(Xe):function(e){return $a(e)&&pn(e)==E};function Ma(e){return null!=e&&za(e.length)&&!Da(e)}function Ra(e){return $a(e)&&Ma(e)}var La=ut||ro,Fa=eu?Nu(eu):function(e){return $a(e)&&pn(e)==l};function Ba(e){if(!$a(e))return!1;var u=pn(e);return u==s||"[object DOMException]"==u||"string"==typeof e.message&&"string"==typeof e.name&&!Ha(e)}function Da(e){if(!Wa(e))return!1;var u=pn(e);return u==p||u==m||"[object AsyncFunction]"==u||"[object Proxy]"==u}function Ua(e){return"number"==typeof e&&e==tc(e)}function za(e){return"number"==typeof e&&e>-1&&e%1==0&&e<=9007199254740991}function Wa(e){var u=typeof e;return null!=e&&("object"==u||"function"==u)}function $a(e){return null!=e&&"object"==typeof e}var Ga=uu?Nu(uu):function(e){return $a(e)&&tr(e)==h};function qa(e){return"number"==typeof e||$a(e)&&pn(e)==v}function Ha(e){if(!$a(e)||pn(e)!=b)return!1;var u=qe(e);if(null===u)return!0;var t=Ie.call(u,"constructor")&&u.constructor;return"function"==typeof t&&t instanceof t&&Ee.call(t)==je}var Ka=tu?Nu(tu):function(e){return $a(e)&&pn(e)==y};var Va=nu?Nu(nu):function(e){return $a(e)&&tr(e)==g};function Ja(e){return"string"==typeof e||!Pa(e)&&$a(e)&&pn(e)==_}function Za(e){return"symbol"==typeof e||$a(e)&&pn(e)==x}var Qa=du?Nu(du):function(e){return $a(e)&&za(e.length)&&!!Ue[pn(e)]};var Ya=Md(An),Xa=Md((function(e,u){return e<=u}));function ec(e){if(!e)return[];if(Ma(e))return Ja(e)?Hu(e):bd(e);if(Ye&&e[Ye])return function(e){for(var u,t=[];!(u=e.next()).done;)t.push(u.value);return t}(e[Ye]());var u=tr(e);return(u==h?Uu:u==g?$u:jc)(e)}function uc(e){return e?(e=dc(e))===1/0||e===-1/0?17976931348623157e292*(e<0?-1:1):e==e?e:0:0===e?e:0}function tc(e){var u=uc(e),t=u%1;return u==u?t?u-t:u:0}function nc(e){return e?Vt(tc(e),0,4294967295):0}function dc(e){if("number"==typeof e)return e;if(Za(e))return NaN;if(Wa(e)){var u="function"==typeof e.valueOf?e.valueOf():e;e=Wa(u)?u+"":u}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(V,"");var t=re.test(e);return t||ce.test(e)?Ge(e.slice(2),t?2:8):de.test(e)?NaN:+e}function rc(e){return yd(e,_c(e))}function ac(e){return null==e?"":Qn(e)}var cc=_d((function(e,u){if(lr(u)||Ma(u))yd(u,gc(u),e);else for(var t in u)Ie.call(u,t)&&Wt(e,t,u[t])})),oc=_d((function(e,u){yd(u,_c(u),e)})),ic=_d((function(e,u,t,n){yd(u,_c(u),e,n)})),fc=_d((function(e,u,t,n){yd(u,gc(u),e,n)})),lc=Gd(Kt);var sc=Bn((function(e,u){e=he(e);var t=-1,n=u.length,d=n>2?u[2]:void 0;for(d&&cr(u[0],u[1],d)&&(n=1);++t1),u})),yd(e,Hd(e),t),n&&(t=Jt(t,7,Wd));for(var d=u.length;d--;)Xn(t,u[d]);return t}));var Ic=Gd((function(e,u){return null==e?{}:function(e,u){return Tn(e,u,(function(u,t){return hc(e,t)}))}(e,u)}));function Sc(e,u){if(null==e)return{};var t=pu(Hd(e),(function(e){return[e]}));return u=Zd(u),Tn(e,t,(function(e,t){return u(e,t[0])}))}var Ac=Bd(gc),kc=Bd(_c);function jc(e){return null==e?[]:Cu(e,gc(e))}var Oc=Id((function(e,u,t){return u=u.toLowerCase(),e+(t?Nc(u):u)}));function Nc(e){return Bc(ac(e).toLowerCase())}function Cc(e){return(e=ac(e))&&e.replace(ie,Lu).replace(Te,"")}var Pc=Id((function(e,u,t){return e+(t?"-":"")+u.toLowerCase()})),Tc=Id((function(e,u,t){return e+(t?" ":"")+u.toLowerCase()})),Mc=Ed("toLowerCase");var Rc=Id((function(e,u,t){return e+(t?"_":"")+u.toLowerCase()}));var Lc=Id((function(e,u,t){return e+(t?" ":"")+Bc(u)}));var Fc=Id((function(e,u,t){return e+(t?" ":"")+u.toUpperCase()})),Bc=Ed("toUpperCase");function Dc(e,u,t){return e=ac(e),void 0===(u=t?void 0:u)?function(e){return Fe.test(e)}(e)?function(e){return e.match(Re)||[]}(e):function(e){return e.match(ee)||[]}(e):e.match(u)||[]}var Uc=Bn((function(e,u){try{return ru(e,void 0,u)}catch(t){return Ba(t)?t:new se(t)}})),zc=Gd((function(e,u){return cu(u,(function(u){u=Sr(u),Ht(e,u,ba(e[u],e))})),e}));function Wc(e){return function(){return e}}var $c=kd(),Gc=kd(!0);function qc(e){return e}function Hc(e){return En("function"==typeof e?e:Jt(e,1))}var Kc=Bn((function(e,u){return function(t){return yn(t,e,u)}})),Vc=Bn((function(e,u){return function(t){return yn(e,t,u)}}));function Jc(e,u,t){var n=gc(u),d=fn(u,n);null!=t||Wa(u)&&(d.length||!n.length)||(t=u,u=e,e=this,d=fn(u,gc(u)));var r=!(Wa(t)&&"chain"in t&&!t.chain),a=Da(e);return cu(d,(function(t){var n=u[t];e[t]=n,a&&(e.prototype[t]=function(){var u=this.__chain__;if(r||u){var t=e(this.__wrapped__),d=t.__actions__=bd(this.__actions__);return d.push({func:n,args:arguments,thisArg:e}),t.__chain__=u,t}return n.apply(e,mu([this.value()],arguments))})})),e}function Zc(){}var Qc=Cd(pu),Yc=Cd(iu),Xc=Cd(bu);function eo(e){return or(e)?Su(Sr(e)):function(e){return function(u){return ln(u,e)}}(e)}var uo=Td(),to=Td(!0);function no(){return[]}function ro(){return!1}var ao=Nd((function(e,u){return e+u}),0),co=Ld("ceil"),oo=Nd((function(e,u){return e/u}),1),io=Ld("floor");var fo,lo=Nd((function(e,u){return e*u}),1),so=Ld("round"),po=Nd((function(e,u){return e-u}),0);return kt.after=function(e,u){if("function"!=typeof u)throw new ye(r);return e=tc(e),function(){if(--e<1)return u.apply(this,arguments)}},kt.ary=ha,kt.assign=cc,kt.assignIn=oc,kt.assignInWith=ic,kt.assignWith=fc,kt.at=lc,kt.before=va,kt.bind=ba,kt.bindAll=zc,kt.bindKey=ya,kt.castArray=function(){if(!arguments.length)return[];var e=arguments[0];return Pa(e)?e:[e]},kt.chain=ea,kt.chunk=function(e,u,t){u=(t?cr(e,u,t):void 0===u)?1:rt(tc(u),0);var d=null==e?0:e.length;if(!d||u<1)return[];for(var r=0,a=0,c=n(Yu(d/u));rd?0:d+t),(n=void 0===n||n>d?d:tc(n))<0&&(n+=d),n=t>n?0:nc(n);t>>0)?(e=ac(e))&&("string"==typeof u||null!=u&&!Ka(u))&&!(u=Qn(u))&&Du(e)?id(Hu(e),0,t):e.split(u,t):[]},kt.spread=function(e,u){if("function"!=typeof e)throw new ye(r);return u=null==u?0:rt(tc(u),0),Bn((function(t){var n=t[u],d=id(t,0,u);return n&&mu(d,n),ru(e,this,d)}))},kt.tail=function(e){var u=null==e?0:e.length;return u?qn(e,1,u):[]},kt.take=function(e,u,t){return e&&e.length?qn(e,0,(u=t||void 0===u?1:tc(u))<0?0:u):[]},kt.takeRight=function(e,u,t){var n=null==e?0:e.length;return n?qn(e,(u=n-(u=t||void 0===u?1:tc(u)))<0?0:u,n):[]},kt.takeRightWhile=function(e,u){return e&&e.length?ud(e,Zd(u,3),!1,!0):[]},kt.takeWhile=function(e,u){return e&&e.length?ud(e,Zd(u,3)):[]},kt.tap=function(e,u){return u(e),e},kt.throttle=function(e,u,t){var n=!0,d=!0;if("function"!=typeof e)throw new ye(r);return Wa(t)&&(n="leading"in t?!!t.leading:n,d="trailing"in t?!!t.trailing:d),ga(e,u,{leading:n,maxWait:u,trailing:d})},kt.thru=ua,kt.toArray=ec,kt.toPairs=Ac,kt.toPairsIn=kc,kt.toPath=function(e){return Pa(e)?pu(e,Sr):Za(e)?[e]:bd(Ir(ac(e)))},kt.toPlainObject=rc,kt.transform=function(e,u,t){var n=Pa(e),d=n||La(e)||Qa(e);if(u=Zd(u,4),null==t){var r=e&&e.constructor;t=d?n?new r:[]:Wa(e)&&Da(r)?jt(qe(e)):{}}return(d?cu:cn)(e,(function(e,n,d){return u(t,e,n,d)})),t},kt.unary=function(e){return ha(e,1)},kt.union=$r,kt.unionBy=Gr,kt.unionWith=qr,kt.uniq=function(e){return e&&e.length?Yn(e):[]},kt.uniqBy=function(e,u){return e&&e.length?Yn(e,Zd(u,2)):[]},kt.uniqWith=function(e,u){return u="function"==typeof u?u:void 0,e&&e.length?Yn(e,void 0,u):[]},kt.unset=function(e,u){return null==e||Xn(e,u)},kt.unzip=Hr,kt.unzipWith=Kr,kt.update=function(e,u,t){return null==e?e:ed(e,u,ad(t))},kt.updateWith=function(e,u,t,n){return n="function"==typeof n?n:void 0,null==e?e:ed(e,u,ad(t),n)},kt.values=jc,kt.valuesIn=function(e){return null==e?[]:Cu(e,_c(e))},kt.without=Vr,kt.words=Dc,kt.wrap=function(e,u){return Sa(ad(u),e)},kt.xor=Jr,kt.xorBy=Zr,kt.xorWith=Qr,kt.zip=Yr,kt.zipObject=function(e,u){return dd(e||[],u||[],Wt)},kt.zipObjectDeep=function(e,u){return dd(e||[],u||[],zn)},kt.zipWith=Xr,kt.entries=Ac,kt.entriesIn=kc,kt.extend=oc,kt.extendWith=ic,Jc(kt,kt),kt.add=ao,kt.attempt=Uc,kt.camelCase=Oc,kt.capitalize=Nc,kt.ceil=co,kt.clamp=function(e,u,t){return void 0===t&&(t=u,u=void 0),void 0!==t&&(t=(t=dc(t))==t?t:0),void 0!==u&&(u=(u=dc(u))==u?u:0),Vt(dc(e),u,t)},kt.clone=function(e){return Jt(e,4)},kt.cloneDeep=function(e){return Jt(e,5)},kt.cloneDeepWith=function(e,u){return Jt(e,5,u="function"==typeof u?u:void 0)},kt.cloneWith=function(e,u){return Jt(e,4,u="function"==typeof u?u:void 0)},kt.conformsTo=function(e,u){return null==u||Zt(e,u,gc(u))},kt.deburr=Cc,kt.defaultTo=function(e,u){return null==e||e!=e?u:e},kt.divide=oo,kt.endsWith=function(e,u,t){e=ac(e),u=Qn(u);var n=e.length,d=t=void 0===t?n:Vt(tc(t),0,n);return(t-=u.length)>=0&&e.slice(t,d)==u},kt.eq=ja,kt.escape=function(e){return(e=ac(e))&&D.test(e)?e.replace(F,Fu):e},kt.escapeRegExp=function(e){return(e=ac(e))&&K.test(e)?e.replace(H,"\\$&"):e},kt.every=function(e,u,t){var n=Pa(e)?iu:un;return t&&cr(e,u,t)&&(u=void 0),n(e,Zd(u,3))},kt.find=da,kt.findIndex=Cr,kt.findKey=function(e,u){return gu(e,Zd(u,3),cn)},kt.findLast=ra,kt.findLastIndex=Pr,kt.findLastKey=function(e,u){return gu(e,Zd(u,3),on)},kt.floor=io,kt.forEach=aa,kt.forEachRight=ca,kt.forIn=function(e,u){return null==e?e:rn(e,Zd(u,3),_c)},kt.forInRight=function(e,u){return null==e?e:an(e,Zd(u,3),_c)},kt.forOwn=function(e,u){return e&&cn(e,Zd(u,3))},kt.forOwnRight=function(e,u){return e&&on(e,Zd(u,3))},kt.get=mc,kt.gt=Oa,kt.gte=Na,kt.has=function(e,u){return null!=e&&nr(e,u,hn)},kt.hasIn=hc,kt.head=Mr,kt.identity=qc,kt.includes=function(e,u,t,n){e=Ma(e)?e:jc(e),t=t&&!n?tc(t):0;var d=e.length;return t<0&&(t=rt(d+t,0)),Ja(e)?t<=d&&e.indexOf(u,t)>-1:!!d&&xu(e,u,t)>-1},kt.indexOf=function(e,u,t){var n=null==e?0:e.length;if(!n)return-1;var d=null==t?0:tc(t);return d<0&&(d=rt(n+d,0)),xu(e,u,d)},kt.inRange=function(e,u,t){return u=uc(u),void 0===t?(t=u,u=0):t=uc(t),function(e,u,t){return e>=at(u,t)&&e=-9007199254740991&&e<=9007199254740991},kt.isSet=Va,kt.isString=Ja,kt.isSymbol=Za,kt.isTypedArray=Qa,kt.isUndefined=function(e){return void 0===e},kt.isWeakMap=function(e){return $a(e)&&tr(e)==w},kt.isWeakSet=function(e){return $a(e)&&"[object WeakSet]"==pn(e)},kt.join=function(e,u){return null==e?"":nt.call(e,u)},kt.kebabCase=Pc,kt.last=Br,kt.lastIndexOf=function(e,u,t){var n=null==e?0:e.length;if(!n)return-1;var d=n;return void 0!==t&&(d=(d=tc(t))<0?rt(n+d,0):at(d,n-1)),u==u?function(e,u,t){for(var n=t+1;n--;)if(e[n]===u)return n;return n}(e,u,d):_u(e,Eu,d,!0)},kt.lowerCase=Tc,kt.lowerFirst=Mc,kt.lt=Ya,kt.lte=Xa,kt.max=function(e){return e&&e.length?tn(e,qc,mn):void 0},kt.maxBy=function(e,u){return e&&e.length?tn(e,Zd(u,2),mn):void 0},kt.mean=function(e){return Iu(e,qc)},kt.meanBy=function(e,u){return Iu(e,Zd(u,2))},kt.min=function(e){return e&&e.length?tn(e,qc,An):void 0},kt.minBy=function(e,u){return e&&e.length?tn(e,Zd(u,2),An):void 0},kt.stubArray=no,kt.stubFalse=ro,kt.stubObject=function(){return{}},kt.stubString=function(){return""},kt.stubTrue=function(){return!0},kt.multiply=lo,kt.nth=function(e,u){return e&&e.length?Cn(e,tc(u)):void 0},kt.noConflict=function(){return Ke._===this&&(Ke._=Oe),this},kt.noop=Zc,kt.now=ma,kt.pad=function(e,u,t){e=ac(e);var n=(u=tc(u))?qu(e):0;if(!u||n>=u)return e;var d=(u-n)/2;return Pd(Xu(d),t)+e+Pd(Yu(d),t)},kt.padEnd=function(e,u,t){e=ac(e);var n=(u=tc(u))?qu(e):0;return u&&nu){var n=e;e=u,u=n}if(t||e%1||u%1){var d=it();return at(e+d*(u-e+$e("1e-"+((d+"").length-1))),u)}return Ln(e,u)},kt.reduce=function(e,u,t){var n=Pa(e)?hu:ku,d=arguments.length<3;return n(e,Zd(u,4),t,d,Xt)},kt.reduceRight=function(e,u,t){var n=Pa(e)?vu:ku,d=arguments.length<3;return n(e,Zd(u,4),t,d,en)},kt.repeat=function(e,u,t){return u=(t?cr(e,u,t):void 0===u)?1:tc(u),Fn(ac(e),u)},kt.replace=function(){var e=arguments,u=ac(e[0]);return e.length<3?u:u.replace(e[1],e[2])},kt.result=function(e,u,t){var n=-1,d=(u=cd(u,e)).length;for(d||(d=1,e=void 0);++n9007199254740991)return[];var t=4294967295,n=at(e,4294967295);e-=4294967295;for(var d=Ou(n,u=Zd(u));++t=r)return e;var c=t-qu(n);if(c<1)return n;var o=a?id(a,0,c).join(""):e.slice(0,c);if(void 0===d)return o+n;if(a&&(c+=o.length-c),Ka(d)){if(e.slice(c).search(d)){var i,f=o;for(d.global||(d=ve(d.source,ac(ne.exec(d))+"g")),d.lastIndex=0;i=d.exec(f);)var l=i.index;o=o.slice(0,void 0===l?c:l)}}else if(e.indexOf(Qn(d),c)!=c){var s=o.lastIndexOf(d);s>-1&&(o=o.slice(0,s))}return o+n},kt.unescape=function(e){return(e=ac(e))&&B.test(e)?e.replace(L,Ku):e},kt.uniqueId=function(e){var u=++Se;return ac(e)+u},kt.upperCase=Fc,kt.upperFirst=Bc,kt.each=aa,kt.eachRight=ca,kt.first=Mr,Jc(kt,(fo={},cn(kt,(function(e,u){Ie.call(kt.prototype,u)||(fo[u]=e)})),fo),{chain:!1}),kt.VERSION="4.17.15",cu(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(e){kt[e].placeholder=kt})),cu(["drop","take"],(function(e,u){Ct.prototype[e]=function(t){t=void 0===t?1:rt(tc(t),0);var n=this.__filtered__&&!u?new Ct(this):this.clone();return n.__filtered__?n.__takeCount__=at(t,n.__takeCount__):n.__views__.push({size:at(t,4294967295),type:e+(n.__dir__<0?"Right":"")}),n},Ct.prototype[e+"Right"]=function(u){return this.reverse()[e](u).reverse()}})),cu(["filter","map","takeWhile"],(function(e,u){var t=u+1,n=1==t||3==t;Ct.prototype[e]=function(e){var u=this.clone();return u.__iteratees__.push({iteratee:Zd(e,3),type:t}),u.__filtered__=u.__filtered__||n,u}})),cu(["head","last"],(function(e,u){var t="take"+(u?"Right":"");Ct.prototype[e]=function(){return this[t](1).value()[0]}})),cu(["initial","tail"],(function(e,u){var t="drop"+(u?"":"Right");Ct.prototype[e]=function(){return this.__filtered__?new Ct(this):this[t](1)}})),Ct.prototype.compact=function(){return this.filter(qc)},Ct.prototype.find=function(e){return this.filter(e).head()},Ct.prototype.findLast=function(e){return this.reverse().find(e)},Ct.prototype.invokeMap=Bn((function(e,u){return"function"==typeof e?new Ct(this):this.map((function(t){return yn(t,e,u)}))})),Ct.prototype.reject=function(e){return this.filter(Ea(Zd(e)))},Ct.prototype.slice=function(e,u){e=tc(e);var t=this;return t.__filtered__&&(e>0||u<0)?new Ct(t):(e<0?t=t.takeRight(-e):e&&(t=t.drop(e)),void 0!==u&&(t=(u=tc(u))<0?t.dropRight(-u):t.take(u-e)),t)},Ct.prototype.takeRightWhile=function(e){return this.reverse().takeWhile(e).reverse()},Ct.prototype.toArray=function(){return this.take(4294967295)},cn(Ct.prototype,(function(e,u){var t=/^(?:filter|find|map|reject)|While$/.test(u),n=/^(?:head|last)$/.test(u),d=kt[n?"take"+("last"==u?"Right":""):u],r=n||/^find/.test(u);d&&(kt.prototype[u]=function(){var u=this.__wrapped__,a=n?[1]:arguments,c=u instanceof Ct,o=a[0],i=c||Pa(u),f=function(e){var u=d.apply(kt,mu([e],a));return n&&l?u[0]:u};i&&t&&"function"==typeof o&&1!=o.length&&(c=i=!1);var l=this.__chain__,s=!!this.__actions__.length,p=r&&!l,m=c&&!s;if(!r&&i){u=m?u:new Ct(this);var h=e.apply(u,a);return h.__actions__.push({func:ua,args:[f],thisArg:void 0}),new Nt(h,l)}return p&&m?e.apply(this,a):(h=this.thru(f),p?n?h.value()[0]:h.value():h)})})),cu(["pop","push","shift","sort","splice","unshift"],(function(e){var u=ge[e],t=/^(?:push|sort|unshift)$/.test(e)?"tap":"thru",n=/^(?:pop|shift)$/.test(e);kt.prototype[e]=function(){var e=arguments;if(n&&!this.__chain__){var d=this.value();return u.apply(Pa(d)?d:[],e)}return this[t]((function(t){return u.apply(Pa(t)?t:[],e)}))}})),cn(Ct.prototype,(function(e,u){var t=kt[u];if(t){var n=t.name+"";Ie.call(yt,n)||(yt[n]=[]),yt[n].push({name:u,func:t})}})),yt[jd(void 0,2).name]=[{name:"wrapper",func:void 0}],Ct.prototype.clone=function(){var e=new Ct(this.__wrapped__);return e.__actions__=bd(this.__actions__),e.__dir__=this.__dir__,e.__filtered__=this.__filtered__,e.__iteratees__=bd(this.__iteratees__),e.__takeCount__=this.__takeCount__,e.__views__=bd(this.__views__),e},Ct.prototype.reverse=function(){if(this.__filtered__){var e=new Ct(this);e.__dir__=-1,e.__filtered__=!0}else(e=this.clone()).__dir__*=-1;return e},Ct.prototype.value=function(){var e=this.__wrapped__.value(),u=this.__dir__,t=Pa(e),n=u<0,d=t?e.length:0,r=function(e,u,t){var n=-1,d=t.length;for(;++n=this.__values__.length;return{done:e,value:e?void 0:this.__values__[this.__index__++]}},kt.prototype.plant=function(e){for(var u,t=this;t instanceof Ot;){var n=kr(t);n.__index__=0,n.__values__=void 0,u?d.__wrapped__=n:u=n;var d=n;t=t.__wrapped__}return d.__wrapped__=e,u},kt.prototype.reverse=function(){var e=this.__wrapped__;if(e instanceof Ct){var u=e;return this.__actions__.length&&(u=new Ct(this)),(u=u.reverse()).__actions__.push({func:ua,args:[Wr],thisArg:void 0}),new Nt(u,this.__chain__)}return this.thru(Wr)},kt.prototype.toJSON=kt.prototype.valueOf=kt.prototype.value=function(){return td(this.__wrapped__,this.__actions__)},kt.prototype.first=kt.prototype.head,Ye&&(kt.prototype[Ye]=function(){return this}),kt}();Ke._=Vu,void 0===(d=function(){return Vu}.call(u,t,u,n))||(n.exports=d)}).call(this)}).call(this,t(76),t(453)(e))},451:function(e,u,t){"use strict";var n=t(0),d=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});u.a=d},453:function(e,u){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),e.webpackPolyfill=1),e}},466:function(e,u,t){"use strict";var n=SyntaxError,d=Function,r=TypeError,a=function(e){try{return d('"use strict"; return ('+e+").constructor;")()}catch(u){}},c=Object.getOwnPropertyDescriptor;if(c)try{c({},"")}catch(k){c=null}var o=function(){throw new r},i=c?function(){try{return o}catch(e){try{return c(arguments,"callee").get}catch(u){return o}}}():o,f=t(504)(),l=Object.getPrototypeOf||function(e){return e.__proto__},s={},p="undefined"==typeof Uint8Array?void 0:l(Uint8Array),m={"%AggregateError%":"undefined"==typeof AggregateError?void 0:AggregateError,"%Array%":Array,"%ArrayBuffer%":"undefined"==typeof ArrayBuffer?void 0:ArrayBuffer,"%ArrayIteratorPrototype%":f?l([][Symbol.iterator]()):void 0,"%AsyncFromSyncIteratorPrototype%":void 0,"%AsyncFunction%":s,"%AsyncGenerator%":s,"%AsyncGeneratorFunction%":s,"%AsyncIteratorPrototype%":s,"%Atomics%":"undefined"==typeof Atomics?void 0:Atomics,"%BigInt%":"undefined"==typeof BigInt?void 0:BigInt,"%Boolean%":Boolean,"%DataView%":"undefined"==typeof DataView?void 0:DataView,"%Date%":Date,"%decodeURI%":decodeURI,"%decodeURIComponent%":decodeURIComponent,"%encodeURI%":encodeURI,"%encodeURIComponent%":encodeURIComponent,"%Error%":Error,"%eval%":eval,"%EvalError%":EvalError,"%Float32Array%":"undefined"==typeof Float32Array?void 0:Float32Array,"%Float64Array%":"undefined"==typeof Float64Array?void 0:Float64Array,"%FinalizationRegistry%":"undefined"==typeof FinalizationRegistry?void 0:FinalizationRegistry,"%Function%":d,"%GeneratorFunction%":s,"%Int8Array%":"undefined"==typeof Int8Array?void 0:Int8Array,"%Int16Array%":"undefined"==typeof Int16Array?void 0:Int16Array,"%Int32Array%":"undefined"==typeof Int32Array?void 0:Int32Array,"%isFinite%":isFinite,"%isNaN%":isNaN,"%IteratorPrototype%":f?l(l([][Symbol.iterator]())):void 0,"%JSON%":"object"==typeof JSON?JSON:void 0,"%Map%":"undefined"==typeof Map?void 0:Map,"%MapIteratorPrototype%":"undefined"!=typeof Map&&f?l((new Map)[Symbol.iterator]()):void 0,"%Math%":Math,"%Number%":Number,"%Object%":Object,"%parseFloat%":parseFloat,"%parseInt%":parseInt,"%Promise%":"undefined"==typeof Promise?void 0:Promise,"%Proxy%":"undefined"==typeof Proxy?void 0:Proxy,"%RangeError%":RangeError,"%ReferenceError%":ReferenceError,"%Reflect%":"undefined"==typeof Reflect?void 0:Reflect,"%RegExp%":RegExp,"%Set%":"undefined"==typeof Set?void 0:Set,"%SetIteratorPrototype%":"undefined"!=typeof Set&&f?l((new Set)[Symbol.iterator]()):void 0,"%SharedArrayBuffer%":"undefined"==typeof SharedArrayBuffer?void 0:SharedArrayBuffer,"%String%":String,"%StringIteratorPrototype%":f?l(""[Symbol.iterator]()):void 0,"%Symbol%":f?Symbol:void 0,"%SyntaxError%":n,"%ThrowTypeError%":i,"%TypedArray%":p,"%TypeError%":r,"%Uint8Array%":"undefined"==typeof Uint8Array?void 0:Uint8Array,"%Uint8ClampedArray%":"undefined"==typeof Uint8ClampedArray?void 0:Uint8ClampedArray,"%Uint16Array%":"undefined"==typeof Uint16Array?void 0:Uint16Array,"%Uint32Array%":"undefined"==typeof Uint32Array?void 0:Uint32Array,"%URIError%":URIError,"%WeakMap%":"undefined"==typeof WeakMap?void 0:WeakMap,"%WeakRef%":"undefined"==typeof WeakRef?void 0:WeakRef,"%WeakSet%":"undefined"==typeof WeakSet?void 0:WeakSet},h={"%ArrayBufferPrototype%":["ArrayBuffer","prototype"],"%ArrayPrototype%":["Array","prototype"],"%ArrayProto_entries%":["Array","prototype","entries"],"%ArrayProto_forEach%":["Array","prototype","forEach"],"%ArrayProto_keys%":["Array","prototype","keys"],"%ArrayProto_values%":["Array","prototype","values"],"%AsyncFunctionPrototype%":["AsyncFunction","prototype"],"%AsyncGenerator%":["AsyncGeneratorFunction","prototype"],"%AsyncGeneratorPrototype%":["AsyncGeneratorFunction","prototype","prototype"],"%BooleanPrototype%":["Boolean","prototype"],"%DataViewPrototype%":["DataView","prototype"],"%DatePrototype%":["Date","prototype"],"%ErrorPrototype%":["Error","prototype"],"%EvalErrorPrototype%":["EvalError","prototype"],"%Float32ArrayPrototype%":["Float32Array","prototype"],"%Float64ArrayPrototype%":["Float64Array","prototype"],"%FunctionPrototype%":["Function","prototype"],"%Generator%":["GeneratorFunction","prototype"],"%GeneratorPrototype%":["GeneratorFunction","prototype","prototype"],"%Int8ArrayPrototype%":["Int8Array","prototype"],"%Int16ArrayPrototype%":["Int16Array","prototype"],"%Int32ArrayPrototype%":["Int32Array","prototype"],"%JSONParse%":["JSON","parse"],"%JSONStringify%":["JSON","stringify"],"%MapPrototype%":["Map","prototype"],"%NumberPrototype%":["Number","prototype"],"%ObjectPrototype%":["Object","prototype"],"%ObjProto_toString%":["Object","prototype","toString"],"%ObjProto_valueOf%":["Object","prototype","valueOf"],"%PromisePrototype%":["Promise","prototype"],"%PromiseProto_then%":["Promise","prototype","then"],"%Promise_all%":["Promise","all"],"%Promise_reject%":["Promise","reject"],"%Promise_resolve%":["Promise","resolve"],"%RangeErrorPrototype%":["RangeError","prototype"],"%ReferenceErrorPrototype%":["ReferenceError","prototype"],"%RegExpPrototype%":["RegExp","prototype"],"%SetPrototype%":["Set","prototype"],"%SharedArrayBufferPrototype%":["SharedArrayBuffer","prototype"],"%StringPrototype%":["String","prototype"],"%SymbolPrototype%":["Symbol","prototype"],"%SyntaxErrorPrototype%":["SyntaxError","prototype"],"%TypedArrayPrototype%":["TypedArray","prototype"],"%TypeErrorPrototype%":["TypeError","prototype"],"%Uint8ArrayPrototype%":["Uint8Array","prototype"],"%Uint8ClampedArrayPrototype%":["Uint8ClampedArray","prototype"],"%Uint16ArrayPrototype%":["Uint16Array","prototype"],"%Uint32ArrayPrototype%":["Uint32Array","prototype"],"%URIErrorPrototype%":["URIError","prototype"],"%WeakMapPrototype%":["WeakMap","prototype"],"%WeakSetPrototype%":["WeakSet","prototype"]},v=t(467),b=t(507),y=v.call(Function.call,Array.prototype.concat),g=v.call(Function.apply,Array.prototype.splice),_=v.call(Function.call,String.prototype.replace),x=v.call(Function.call,String.prototype.slice),w=v.call(Function.call,RegExp.prototype.exec),E=/[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g,I=/\\(\\)?/g,S=function(e){var u=x(e,0,1),t=x(e,-1);if("%"===u&&"%"!==t)throw new n("invalid intrinsic syntax, expected closing `%`");if("%"===t&&"%"!==u)throw new n("invalid intrinsic syntax, expected opening `%`");var d=[];return _(e,E,(function(e,u,t,n){d[d.length]=t?_(n,I,"$1"):u||e})),d},A=function(e,u){var t,d=e;if(b(h,d)&&(d="%"+(t=h[d])[0]+"%"),b(m,d)){var c=m[d];if(c===s&&(c=function e(u){var t;if("%AsyncFunction%"===u)t=a("async function () {}");else if("%GeneratorFunction%"===u)t=a("function* () {}");else if("%AsyncGeneratorFunction%"===u)t=a("async function* () {}");else if("%AsyncGenerator%"===u){var n=e("%AsyncGeneratorFunction%");n&&(t=n.prototype)}else if("%AsyncIteratorPrototype%"===u){var d=e("%AsyncGenerator%");d&&(t=l(d.prototype))}return m[u]=t,t}(d)),void 0===c&&!u)throw new r("intrinsic "+e+" exists, but is not available. Please file an issue!");return{alias:t,name:d,value:c}}throw new n("intrinsic "+e+" does not exist!")};e.exports=function(e,u){if("string"!=typeof e||0===e.length)throw new r("intrinsic name must be a non-empty string");if(arguments.length>1&&"boolean"!=typeof u)throw new r('"allowMissing" argument must be a boolean');if(null===w(/^%?[^%]*%?$/,e))throw new n("`%` may not be present anywhere but at the beginning and end of the intrinsic name");var t=S(e),d=t.length>0?t[0]:"",a=A("%"+d+"%",u),o=a.name,i=a.value,f=!1,l=a.alias;l&&(d=l[0],g(t,y([0,1],l)));for(var s=1,p=!0;s=t.length){var E=c(i,h);i=(p=!!E)&&"get"in E&&!("originalValue"in E.get)?E.get:i[h]}else p=b(i,h),i=i[h];p&&!f&&(m[o]=i)}}return i}},467:function(e,u,t){"use strict";var n=t(506);e.exports=Function.prototype.bind||n},468:function(e,u,t){"use strict";var n=String.prototype.replace,d=/%20/g,r="RFC1738",a="RFC3986";e.exports={default:a,formatters:{RFC1738:function(e){return n.call(e,d,"+")},RFC3986:function(e){return String(e)}},RFC1738:r,RFC3986:a}},475:function(e,u,t){"use strict";var n=t(468),d=Object.prototype.hasOwnProperty,r=Array.isArray,a=function(){for(var e=[],u=0;u<256;++u)e.push("%"+((u<16?"0":"")+u.toString(16)).toUpperCase());return e}(),c=function(e,u){for(var t=u&&u.plainObjects?Object.create(null):{},n=0;n1;){var u=e.pop(),t=u.obj[u.prop];if(r(t)){for(var n=[],d=0;d=48&&f<=57||f>=65&&f<=90||f>=97&&f<=122||r===n.RFC1738&&(40===f||41===f)?o+=c.charAt(i):f<128?o+=a[f]:f<2048?o+=a[192|f>>6]+a[128|63&f]:f<55296||f>=57344?o+=a[224|f>>12]+a[128|f>>6&63]+a[128|63&f]:(i+=1,f=65536+((1023&f)<<10|1023&c.charCodeAt(i)),o+=a[240|f>>18]+a[128|f>>12&63]+a[128|f>>6&63]+a[128|63&f])}return o},isBuffer:function(e){return!(!e||"object"!=typeof e)&&!!(e.constructor&&e.constructor.isBuffer&&e.constructor.isBuffer(e))},isRegExp:function(e){return"[object RegExp]"===Object.prototype.toString.call(e)},maybeMap:function(e,u){if(r(e)){for(var t=[],n=0;n{if("string"!=typeof e)throw new TypeError("Expected a string");return e=(e=(e=n(e)).toLowerCase().replace(/[_-]+/g," ").replace(/\s{2,}/g," ").trim()).charAt(0).toUpperCase()+e.slice(1)};e.exports=d,e.exports.default=d},483:function(e,u){e.exports=Object.is||function(e,u){return e===u?0!==e||1/e==1/u:e!=e&&u!=u}},486:function(e,u,t){"use strict";var n=t(30),d=t(12),r=t(27),a=t(91),c=t(92),o=t(26),i=t(542),f=t(93);d(d.S+d.F*!t(83)((function(e){Array.from(e)})),"Array",{from:function(e){var u,t,d,l,s=r(e),p="function"==typeof this?this:Array,m=arguments.length,h=m>1?arguments[1]:void 0,v=void 0!==h,b=0,y=f(s);if(v&&(h=n(h,m>2?arguments[2]:void 0,2)),null==y||p==Array&&c(y))for(t=new p(u=o(s.length));u>b;b++)i(t,b,v?h(s[b],b):s[b]);else for(l=y.call(s),t=new p;!(d=l.next()).done;b++)i(t,b,v?a(l,h,[d.value,b],!0):d.value);return t.length=b,t}})},487:function(e,u,t){"use strict";var n=t(543),d=t(489);e.exports=t(544)("Set",(function(e){return function(){return e(this,arguments.length>0?arguments[0]:void 0)}}),{add:function(e){return n.def(d(this,"Set"),e=0===e?0:e,e)}},n)},488:function(e,u,t){var n=t(40)("meta"),d=t(13),r=t(31),a=t(28).f,c=0,o=Object.isExtensible||function(){return!0},i=!t(14)((function(){return o(Object.preventExtensions({}))})),f=function(e){a(e,n,{value:{i:"O"+ ++c,w:{}}})},l=e.exports={KEY:n,NEED:!1,fastKey:function(e,u){if(!d(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!r(e,n)){if(!o(e))return"F";if(!u)return"E";f(e)}return e[n].i},getWeak:function(e,u){if(!r(e,n)){if(!o(e))return!0;if(!u)return!1;f(e)}return e[n].w},onFreeze:function(e){return i&&l.NEED&&o(e)&&!r(e,n)&&f(e),e}}},489:function(e,u,t){var n=t(13);e.exports=function(e,u){if(!n(e)||e._t!==u)throw TypeError("Incompatible receiver, "+u+" required!");return e}},490:function(e,u,t){"use strict";const n=t(491);e.exports=(e,u)=>{if("string"!=typeof e)throw new TypeError("Expected a string");u=void 0===u?"_":u;const t=n("([\\p{Ll}\\d])(\\p{Lu})","g"),d=n("(\\p{Lu}+)(\\p{Lu}[\\p{Ll}\\d]+)","g");return e.replace(t,`$1${u}$2`).replace(d,`$1${u}$2`).toLowerCase()}},491:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0});var n=l(t(492)),d=l(t(493)),r=l(t(494)),a=l(t(495)),c=l(t(496)),o=l(t(497)),i=l(t(498)),f=l(t(499));function l(e){return e&&e.__esModule?e:{default:e}}(0,d.default)(n.default),(0,r.default)(n.default),(0,a.default)(n.default),(0,c.default)(n.default),(0,o.default)(n.default),(0,i.default)(n.default),(0,f.default)(n.default),u.default=n.default,e.exports=u.default},492:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0});var n={astral:!1},d={exec:RegExp.prototype.exec,test:RegExp.prototype.test,match:String.prototype.match,replace:String.prototype.replace,split:String.prototype.split},r={},a={},c={},o=[],i={default:/\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|\(\?(?:[:=!]|<[=!])|[?*+]\?|{\d+(?:,\d*)?}\??|[\s\S]/,class:/\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|[\s\S]/},f=/\$(?:{([\w$]+)}|<([\w$]+)>|(\d\d?|[\s\S]))/g,l=void 0===d.exec.call(/()??/,"")[1],s=void 0!==/x/.flags,p={}.toString;function m(e){var u=!0;try{new RegExp("",e)}catch(t){u=!1}return u}var h=m("u"),v=m("y"),b={g:!0,i:!0,m:!0,u:h,y:v};function y(e,u,t,n,d){var r=void 0;if(e.xregexp={captureNames:u},d)return e;if(e.__proto__)e.__proto__=C.prototype;else for(r in C.prototype)e[r]=C.prototype[r];return e.xregexp.source=t,e.xregexp.flags=n?n.split("").sort().join(""):n,e}function g(e){return d.replace.call(e,/([\s\S])(?=[\s\S]*\1)/g,"")}function _(e,u){if(!C.isRegExp(e))throw new TypeError("Type RegExp expected");var t=e.xregexp||{},n=function(e){return s?e.flags:d.exec.call(/\/([a-z]*)$/i,RegExp.prototype.toString.call(e))[1]}(e),r="",a="",c=null,o=null;return(u=u||{}).removeG&&(a+="g"),u.removeY&&(a+="y"),a&&(n=d.replace.call(n,new RegExp("["+a+"]+","g"),"")),u.addG&&(r+="g"),u.addY&&(r+="y"),r&&(n=g(n+r)),u.isInternalOnly||(void 0!==t.source&&(c=t.source),null!=t.flags&&(o=r?g(t.flags+r):t.flags)),e=y(new RegExp(u.source||e.source,n),function(e){return!(!e.xregexp||!e.xregexp.captureNames)}(e)?t.captureNames.slice(0):null,c,o,u.isInternalOnly)}function x(e){return parseInt(e,16)}function w(e,u,t){return"("===e.input[e.index-1]||")"===e.input[e.index+e[0].length]||function(e,u,t){return d.test.call(-1!==t.indexOf("x")?/^(?:\s|#[^#\n]*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/:/^(?:\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/,e.slice(u))}(e.input,e.index+e[0].length,t)?"":"(?:)"}function E(e){return parseInt(e,10).toString(16)}function I(e,u){return p.call(e)==="[object "+u+"]"}function S(e){for(;e.length<4;)e="0"+e;return e}function A(e){var u={};return I(e,"String")?(C.forEach(e,/[^\s,]+/,(function(e){u[e]=!0})),u):e}function k(e){if(!/^[\w$]$/.test(e))throw new Error("Flag must be a single character A-Za-z0-9_$");b[e]=!0}function j(e,u,t,n,d){for(var r=o.length,a=e[t],c=null,i=void 0,f=void 0;r--;)if(!((f=o[r]).leadChar&&f.leadChar!==a||f.scope!==n&&"all"!==f.scope||f.flag&&-1===u.indexOf(f.flag))&&(i=C.exec(e,f.regex,t,"sticky"))){c={matchLength:i[0].length,output:f.handler.call(d,i,n,u),reparse:f.reparse};break}return c}function O(e){n.astral=e}function N(e){if(null==e)throw new TypeError("Cannot convert null or undefined to object");return e}function C(e,u){if(C.isRegExp(e)){if(void 0!==u)throw new TypeError("Cannot supply flags when copying a RegExp");return _(e)}if(e=void 0===e?"":String(e),u=void 0===u?"":String(u),C.isInstalled("astral")&&-1===u.indexOf("A")&&(u+="A"),c[e]||(c[e]={}),!c[e][u]){for(var t={hasNamedCapture:!1,captureNames:[]},n="default",r="",a=0,o=void 0,f=function(e,u){var t=void 0;if(g(u)!==u)throw new SyntaxError("Invalid duplicate regex flag "+u);for(e=d.replace.call(e,/^\(\?([\w$]+)\)/,(function(e,t){if(d.test.call(/[gy]/,t))throw new SyntaxError("Cannot use flag g or y in mode modifier "+e);return u=g(u+t),""})),t=0;t"}else if(t)return"\\"+(+t+a);return e}if(!I(e,"Array")||!e.length)throw new TypeError("Must provide a nonempty array of patterns to merge");for(var i=/(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*\]/g,f=[],l=void 0,s=0;s1&&-1!==t.indexOf("")){var n=_(this,{removeG:!0,isInternalOnly:!0});d.replace.call(String(e).slice(t.index),n,(function(){for(var e=arguments.length,u=Array(e),n=0;nt.index&&(this.lastIndex=t.index)}return this.global||(this.lastIndex=u),t},r.test=function(e){return!!r.exec.call(this,e)},r.match=function(e){if(C.isRegExp(e)){if(e.global){var u=d.match.apply(this,arguments);return e.lastIndex=0,u}}else e=new RegExp(e);return r.exec.call(e,N(this))},r.replace=function(e,u){var t=C.isRegExp(e),n=void 0,r=void 0,a=void 0;return t?(e.xregexp&&(r=e.xregexp.captureNames),n=e.lastIndex):e+="",a=I(u,"Function")?d.replace.call(String(this),e,(function(){for(var n=arguments.length,d=Array(n),a=0;at.length-3)throw new SyntaxError("Backreference to undefined group "+e);return t[d]||""}throw new SyntaxError("Invalid token "+e)}})),t&&(e.global?e.lastIndex=0:e.lastIndex=n),a},r.split=function(e,u){if(!C.isRegExp(e))return d.split.apply(this,arguments);var t=String(this),n=[],r=e.lastIndex,a=0,c=void 0;return u=(void 0===u?-1:u)>>>0,C.forEach(t,e,(function(e){e.index+e[0].length>a&&(n.push(t.slice(a,e.index)),e.length>1&&e.indexu?n.slice(0,u):n},C.addToken(/\\([ABCE-RTUVXYZaeg-mopqyz]|c(?![A-Za-z])|u(?![\dA-Fa-f]{4}|{[\dA-Fa-f]+})|x(?![\dA-Fa-f]{2}))/,(function(e,u){if("B"===e[1]&&"default"===u)return e[0];throw new SyntaxError("Invalid escape "+e[0])}),{scope:"all",leadChar:"\\"}),C.addToken(/\\u{([\dA-Fa-f]+)}/,(function(e,u,t){var n=x(e[1]);if(n>1114111)throw new SyntaxError("Invalid Unicode code point "+e[0]);if(n<=65535)return"\\u"+S(E(n));if(h&&-1!==t.indexOf("u"))return e[0];throw new SyntaxError("Cannot use Unicode code point above \\u{FFFF} without flag u")}),{scope:"all",leadChar:"\\"}),C.addToken(/\[(\^?)\]/,(function(e){return e[1]?"[\\s\\S]":"\\b\\B"}),{leadChar:"["}),C.addToken(/\(\?#[^)]*\)/,w,{leadChar:"("}),C.addToken(/\s+|#[^\n]*\n?/,w,{flag:"x"}),C.addToken(/\./,(function(){return"[\\s\\S]"}),{flag:"s",leadChar:"."}),C.addToken(/\\k<([\w$]+)>/,(function(e){var u=isNaN(e[1])?this.captureNames.indexOf(e[1])+1:+e[1],t=e.index+e[0].length;if(!u||u>this.captureNames.length)throw new SyntaxError("Backreference to undefined group "+e[0]);return"\\"+u+(t===e.input.length||isNaN(e.input[t])?"":"(?:)")}),{leadChar:"\\"}),C.addToken(/\\(\d+)/,(function(e,u){if(!("default"===u&&/^[1-9]/.test(e[1])&&+e[1]<=this.captureNames.length)&&"0"!==e[1])throw new SyntaxError("Cannot use octal escape or backreference to undefined group "+e[0]);return e[0]}),{scope:"all",leadChar:"\\"}),C.addToken(/\(\?P?<([\w$]+)>/,(function(e){if(!isNaN(e[1]))throw new SyntaxError("Cannot use integer as capture name "+e[0]);if("length"===e[1]||"__proto__"===e[1])throw new SyntaxError("Cannot use reserved word as capture name "+e[0]);if(-1!==this.captureNames.indexOf(e[1]))throw new SyntaxError("Cannot use same name for multiple groups "+e[0]);return this.captureNames.push(e[1]),this.hasNamedCapture=!0,"("}),{leadChar:"("}),C.addToken(/\((?!\?)/,(function(e,u,t){return-1!==t.indexOf("n")?"(?:":(this.captureNames.push(null),"(")}),{optionalFlags:"n",leadChar:"("}),u.default=C,e.exports=u.default},493:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0}),u.default=function(e){var u=/(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*\]/g,t=e.union([/\({{([\w$]+)}}\)|{{([\w$]+)}}/,u],"g",{conjunction:"or"});function n(e){var u=/^(?:\(\?:\))*\^/,t=/\$(?:\(\?:\))*$/;return u.test(e)&&t.test(e)&&t.test(e.replace(/\\[\s\S]/g,""))?e.replace(u,"").replace(t,""):e}function d(u,t){var n=t?"x":"";return e.isRegExp(u)?u.xregexp&&u.xregexp.captureNames?u:e(u.source,n):e(u,n)}function r(u){return u instanceof RegExp?u:e.escape(u)}function a(e,u,t){return e["subpattern"+t]=u,e}function c(e,u,t){return e+(u1?n-1:0),o=1;o"):o="(?:",h=m,""+o+f[a].pattern.replace(u,(function(e,u,t){if(u){if(c=f[a].names[m-h],++m,c)return"(?<"+c+">"}else if(t)return i=+t-1,f[a].names[i]?"\\k<"+f[a].names[i]+">":"\\"+(+t+h);return e}))+")"}if(d){if(c=y[v],b[++v]=++m,c)return"(?<"+c+">"}else if(r)return y[i=+r-1]?"\\k<"+y[i]+">":"\\"+b[+r];return e}));return e(g,c)}},e.exports=u.default},494:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0}),u.default=function(e){function u(e,u,t,n){return{name:e,value:u,start:t,end:n}}e.matchRecursive=function(t,n,d,r,a){a=a||{};var c=-1!==(r=r||"").indexOf("g"),o=-1!==r.indexOf("y"),i=r.replace(/y/g,""),f=a.escapeChar,l=a.valueNames,s=[],p=0,m=0,h=0,v=0,b=void 0,y=void 0,g=void 0,_=void 0,x=void 0;if(n=e(n,i),d=e(d,i),f){if(f.length>1)throw new Error("Cannot use more than one escape character");f=e.escape(f),x=new RegExp("(?:"+f+"[\\S\\s]|(?:(?!"+e.union([n,d],"",{conjunction:"or"}).source+")[^"+f+"])+)+",r.replace(/[^imu]+/g,""))}for(;;){if(f&&(h+=(e.exec(t,x,h,"sticky")||[""])[0].length),g=e.exec(t,n,h),_=e.exec(t,d,h),g&&_&&(g.index<=_.index?_=null:g=null),g||_)h=(m=(g||_).index)+(g||_)[0].length;else if(!p)break;if(o&&!p&&m>v)break;if(g)p||(b=m,y=h),++p;else{if(!_||!p)throw new Error("Unbalanced delimiter found in string");if(!--p&&(l?(l[0]&&b>v&&s.push(u(l[0],t.slice(v,b),v,b)),l[1]&&s.push(u(l[1],t.slice(b,y),b,y)),l[2]&&s.push(u(l[2],t.slice(y,m),y,m)),l[3]&&s.push(u(l[3],t.slice(m,h),m,h))):s.push(t.slice(y,m)),v=h,!c))break}m===h&&++h}return c&&!o&&l&&l[0]&&t.length>v&&s.push(u(l[0],t.slice(v),v,t.length)),s}},e.exports=u.default},495:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0}),u.default=function(e){var u={},t=e._dec,n=e._hex,d=e._pad4;function r(e){return e.replace(/[- _]+/g,"").toLowerCase()}function a(e){var u=/^\\[xu](.+)/.exec(e);return u?t(u[1]):e.charCodeAt("\\"===e[0]?1:0)}function c(t){var r,c,o;return u[t]["b!"]||(u[t]["b!"]=(r=u[t].bmp,c="",o=-1,e.forEach(r,/(\\x..|\\u....|\\?[\s\S])(?:-(\\x..|\\u....|\\?[\s\S]))?/,(function(e){var u=a(e[1]);u>o+1&&(c+="\\u"+d(n(o+1)),u>o+2&&(c+="-\\u"+d(n(u-1)))),o=a(e[2]||e[1])})),o<65535&&(c+="\\u"+d(n(o+1)),o<65534&&(c+="-\\uFFFF")),c))}function o(e,t){var n=t?"a!":"a=";return u[e][n]||(u[e][n]=function(e,t){var n=u[e],d="";return n.bmp&&!n.isBmpLast&&(d="["+n.bmp+"]"+(n.astral?"|":"")),n.astral&&(d+=n.astral),n.isBmpLast&&n.bmp&&(d+=(n.astral?"|":"")+"["+n.bmp+"]"),t?"(?:(?!"+d+")(?:[\ud800-\udbff][\udc00-\udfff]|[\0-\uffff]))":"(?:"+d+")"}(e,t))}e.addToken(/\\([pP])(?:{(\^?)([^}]*)}|([A-Za-z]))/,(function(e,t,n){var d="P"===e[1]||!!e[2],a=-1!==n.indexOf("A"),i=r(e[4]||e[3]),f=u[i];if("P"===e[1]&&e[2])throw new SyntaxError("Invalid double negation "+e[0]);if(!u.hasOwnProperty(i))throw new SyntaxError("Unknown Unicode token "+e[0]);if(f.inverseOf){if(i=r(f.inverseOf),!u.hasOwnProperty(i))throw new ReferenceError("Unicode token missing data "+e[0]+" -> "+f.inverseOf);f=u[i],d=!d}if(!f.bmp&&!a)throw new SyntaxError("Astral mode required for Unicode token "+e[0]);if(a){if("class"===t)throw new SyntaxError("Astral mode does not support Unicode tokens within character classes");return o(i,d)}return"class"===t?d?c(i):f.bmp:(d?"[^":"[")+f.bmp+"]"}),{scope:"all",optionalFlags:"A",leadChar:"\\"}),e.addUnicodeData=function(t){for(var n=void 0,d=0;d\\x5E`\\x7C~\xa2-\xa6\xa8\xa9\xac\xae-\xb1\xb4\xb8\xd7\xf7\u02c2-\u02c5\u02d2-\u02df\u02e5-\u02eb\u02ed\u02ef-\u02ff\u0375\u0384\u0385\u03f6\u0482\u058d-\u058f\u0606-\u0608\u060b\u060e\u060f\u06de\u06e9\u06fd\u06fe\u07f6\u09f2\u09f3\u09fa\u09fb\u0af1\u0b70\u0bf3-\u0bfa\u0c7f\u0d4f\u0d79\u0e3f\u0f01-\u0f03\u0f13\u0f15-\u0f17\u0f1a-\u0f1f\u0f34\u0f36\u0f38\u0fbe-\u0fc5\u0fc7-\u0fcc\u0fce\u0fcf\u0fd5-\u0fd8\u109e\u109f\u1390-\u1399\u17db\u1940\u19de-\u19ff\u1b61-\u1b6a\u1b74-\u1b7c\u1fbd\u1fbf-\u1fc1\u1fcd-\u1fcf\u1fdd-\u1fdf\u1fed-\u1fef\u1ffd\u1ffe\u2044\u2052\u207a-\u207c\u208a-\u208c\u20a0-\u20be\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116-\u2118\u211e-\u2123\u2125\u2127\u2129\u212e\u213a\u213b\u2140-\u2144\u214a-\u214d\u214f\u218a\u218b\u2190-\u2307\u230c-\u2328\u232b-\u23fe\u2400-\u2426\u2440-\u244a\u249c-\u24e9\u2500-\u2767\u2794-\u27c4\u27c7-\u27e5\u27f0-\u2982\u2999-\u29d7\u29dc-\u29fb\u29fe-\u2b73\u2b76-\u2b95\u2b98-\u2bb9\u2bbd-\u2bc8\u2bca-\u2bd1\u2bec-\u2bef\u2ce5-\u2cea\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u2ff0-\u2ffb\u3004\u3012\u3013\u3020\u3036\u3037\u303e\u303f\u309b\u309c\u3190\u3191\u3196-\u319f\u31c0-\u31e3\u3200-\u321e\u322a-\u3247\u3250\u3260-\u327f\u328a-\u32b0\u32c0-\u32fe\u3300-\u33ff\u4dc0-\u4dff\ua490-\ua4c6\ua700-\ua716\ua720\ua721\ua789\ua78a\ua828-\ua82b\ua836-\ua839\uaa77-\uaa79\uab5b\ufb29\ufbb2-\ufbc1\ufdfc\ufdfd\ufe62\ufe64-\ufe66\ufe69\uff04\uff0b\uff1c-\uff1e\uff3e\uff40\uff5c\uff5e\uffe0-\uffe6\uffe8-\uffee\ufffc\ufffd",astral:"\ud800[\udd37-\udd3f\udd79-\udd89\udd8c-\udd8e\udd90-\udd9b\udda0\uddd0-\uddfc]|\ud802[\udc77\udc78\udec8]|\ud805\udf3f|\ud81a[\udf3c-\udf3f\udf45]|\ud82f\udc9c|\ud834[\udc00-\udcf5\udd00-\udd26\udd29-\udd64\udd6a-\udd6c\udd83\udd84\udd8c-\udda9\uddae-\udde8\ude00-\ude41\ude45\udf00-\udf56]|\ud835[\udec1\udedb\udefb\udf15\udf35\udf4f\udf6f\udf89\udfa9\udfc3]|\ud836[\udc00-\uddff\ude37-\ude3a\ude6d-\ude74\ude76-\ude83\ude85\ude86]|\ud83b[\udef0\udef1]|\ud83c[\udc00-\udc2b\udc30-\udc93\udca0-\udcae\udcb1-\udcbf\udcc1-\udccf\udcd1-\udcf5\udd10-\udd2e\udd30-\udd6b\udd70-\uddac\udde6-\ude02\ude10-\ude3b\ude40-\ude48\ude50\ude51\udf00-\udfff]|\ud83d[\udc00-\uded2\udee0-\udeec\udef0-\udef6\udf00-\udf73\udf80-\udfd4]|\ud83e[\udc00-\udc0b\udc10-\udc47\udc50-\udc59\udc60-\udc87\udc90-\udcad\udd10-\udd1e\udd20-\udd27\udd30\udd33-\udd3e\udd40-\udd4b\udd50-\udd5e\udd80-\udd91\uddc0]"},{name:"Sc",alias:"Currency_Symbol",bmp:"\\x24\xa2-\xa5\u058f\u060b\u09f2\u09f3\u09fb\u0af1\u0bf9\u0e3f\u17db\u20a0-\u20be\ua838\ufdfc\ufe69\uff04\uffe0\uffe1\uffe5\uffe6"},{name:"Sk",alias:"Modifier_Symbol",bmp:"\\x5E`\xa8\xaf\xb4\xb8\u02c2-\u02c5\u02d2-\u02df\u02e5-\u02eb\u02ed\u02ef-\u02ff\u0375\u0384\u0385\u1fbd\u1fbf-\u1fc1\u1fcd-\u1fcf\u1fdd-\u1fdf\u1fed-\u1fef\u1ffd\u1ffe\u309b\u309c\ua700-\ua716\ua720\ua721\ua789\ua78a\uab5b\ufbb2-\ufbc1\uff3e\uff40\uffe3",astral:"\ud83c[\udffb-\udfff]"},{name:"Sm",alias:"Math_Symbol",bmp:"\\x2B<->\\x7C~\xac\xb1\xd7\xf7\u03f6\u0606-\u0608\u2044\u2052\u207a-\u207c\u208a-\u208c\u2118\u2140-\u2144\u214b\u2190-\u2194\u219a\u219b\u21a0\u21a3\u21a6\u21ae\u21ce\u21cf\u21d2\u21d4\u21f4-\u22ff\u2320\u2321\u237c\u239b-\u23b3\u23dc-\u23e1\u25b7\u25c1\u25f8-\u25ff\u266f\u27c0-\u27c4\u27c7-\u27e5\u27f0-\u27ff\u2900-\u2982\u2999-\u29d7\u29dc-\u29fb\u29fe-\u2aff\u2b30-\u2b44\u2b47-\u2b4c\ufb29\ufe62\ufe64-\ufe66\uff0b\uff1c-\uff1e\uff5c\uff5e\uffe2\uffe9-\uffec",astral:"\ud835[\udec1\udedb\udefb\udf15\udf35\udf4f\udf6f\udf89\udfa9\udfc3]|\ud83b[\udef0\udef1]"},{name:"So",alias:"Other_Symbol",bmp:"\xa6\xa9\xae\xb0\u0482\u058d\u058e\u060e\u060f\u06de\u06e9\u06fd\u06fe\u07f6\u09fa\u0b70\u0bf3-\u0bf8\u0bfa\u0c7f\u0d4f\u0d79\u0f01-\u0f03\u0f13\u0f15-\u0f17\u0f1a-\u0f1f\u0f34\u0f36\u0f38\u0fbe-\u0fc5\u0fc7-\u0fcc\u0fce\u0fcf\u0fd5-\u0fd8\u109e\u109f\u1390-\u1399\u1940\u19de-\u19ff\u1b61-\u1b6a\u1b74-\u1b7c\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116\u2117\u211e-\u2123\u2125\u2127\u2129\u212e\u213a\u213b\u214a\u214c\u214d\u214f\u218a\u218b\u2195-\u2199\u219c-\u219f\u21a1\u21a2\u21a4\u21a5\u21a7-\u21ad\u21af-\u21cd\u21d0\u21d1\u21d3\u21d5-\u21f3\u2300-\u2307\u230c-\u231f\u2322-\u2328\u232b-\u237b\u237d-\u239a\u23b4-\u23db\u23e2-\u23fe\u2400-\u2426\u2440-\u244a\u249c-\u24e9\u2500-\u25b6\u25b8-\u25c0\u25c2-\u25f7\u2600-\u266e\u2670-\u2767\u2794-\u27bf\u2800-\u28ff\u2b00-\u2b2f\u2b45\u2b46\u2b4d-\u2b73\u2b76-\u2b95\u2b98-\u2bb9\u2bbd-\u2bc8\u2bca-\u2bd1\u2bec-\u2bef\u2ce5-\u2cea\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u2ff0-\u2ffb\u3004\u3012\u3013\u3020\u3036\u3037\u303e\u303f\u3190\u3191\u3196-\u319f\u31c0-\u31e3\u3200-\u321e\u322a-\u3247\u3250\u3260-\u327f\u328a-\u32b0\u32c0-\u32fe\u3300-\u33ff\u4dc0-\u4dff\ua490-\ua4c6\ua828-\ua82b\ua836\ua837\ua839\uaa77-\uaa79\ufdfd\uffe4\uffe8\uffed\uffee\ufffc\ufffd",astral:"\ud800[\udd37-\udd3f\udd79-\udd89\udd8c-\udd8e\udd90-\udd9b\udda0\uddd0-\uddfc]|\ud802[\udc77\udc78\udec8]|\ud805\udf3f|\ud81a[\udf3c-\udf3f\udf45]|\ud82f\udc9c|\ud834[\udc00-\udcf5\udd00-\udd26\udd29-\udd64\udd6a-\udd6c\udd83\udd84\udd8c-\udda9\uddae-\udde8\ude00-\ude41\ude45\udf00-\udf56]|\ud836[\udc00-\uddff\ude37-\ude3a\ude6d-\ude74\ude76-\ude83\ude85\ude86]|\ud83c[\udc00-\udc2b\udc30-\udc93\udca0-\udcae\udcb1-\udcbf\udcc1-\udccf\udcd1-\udcf5\udd10-\udd2e\udd30-\udd6b\udd70-\uddac\udde6-\ude02\ude10-\ude3b\ude40-\ude48\ude50\ude51\udf00-\udffa]|\ud83d[\udc00-\uded2\udee0-\udeec\udef0-\udef6\udf00-\udf73\udf80-\udfd4]|\ud83e[\udc00-\udc0b\udc10-\udc47\udc50-\udc59\udc60-\udc87\udc90-\udcad\udd10-\udd1e\udd20-\udd27\udd30\udd33-\udd3e\udd40-\udd4b\udd50-\udd5e\udd80-\udd91\uddc0]"},{name:"Z",alias:"Separator",bmp:" \xa0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000"},{name:"Zl",alias:"Line_Separator",bmp:"\u2028"},{name:"Zp",alias:"Paragraph_Separator",bmp:"\u2029"},{name:"Zs",alias:"Space_Separator",bmp:" \xa0\u1680\u2000-\u200a\u202f\u205f\u3000"}])},e.exports=u.default},498:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0}),u.default=function(e){if(!e.addUnicodeData)throw new ReferenceError("Unicode Base must be loaded before Unicode Properties");var u=[{name:"ASCII",bmp:"\0-\x7f"},{name:"Alphabetic",bmp:"A-Za-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0345\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0561-\u0587\u05b0-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0657\u0659-\u065f\u066e-\u06d3\u06d5-\u06dc\u06e1-\u06e8\u06ed-\u06ef\u06fa-\u06fc\u06ff\u0710-\u073f\u074d-\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0817\u081a-\u082c\u0840-\u0858\u08a0-\u08b4\u08b6-\u08bd\u08d4-\u08df\u08e3-\u08e9\u08f0-\u093b\u093d-\u094c\u094e-\u0950\u0955-\u0963\u0971-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd-\u09c4\u09c7\u09c8\u09cb\u09cc\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09f0\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3e-\u0a42\u0a47\u0a48\u0a4b\u0a4c\u0a51\u0a59-\u0a5c\u0a5e\u0a70-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd-\u0ac5\u0ac7-\u0ac9\u0acb\u0acc\u0ad0\u0ae0-\u0ae3\u0af9\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d-\u0b44\u0b47\u0b48\u0b4b\u0b4c\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcc\u0bd0\u0bd7\u0c00-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4c\u0c55\u0c56\u0c58-\u0c5a\u0c60-\u0c63\u0c80-\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccc\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0cf1\u0cf2\u0d01-\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4c\u0d4e\u0d54-\u0d57\u0d5f-\u0d63\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e46\u0e4d\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ecd\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f71-\u0f81\u0f88-\u0f97\u0f99-\u0fbc\u1000-\u1036\u1038\u103b-\u103f\u1050-\u1062\u1065-\u1068\u106e-\u1086\u108e\u109c\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135f\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1713\u1720-\u1733\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17b3\u17b6-\u17c8\u17d7\u17dc\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191e\u1920-\u192b\u1930-\u1938\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a1b\u1a20-\u1a5e\u1a61-\u1a74\u1aa7\u1b00-\u1b33\u1b35-\u1b43\u1b45-\u1b4b\u1b80-\u1ba9\u1bac-\u1baf\u1bba-\u1be5\u1be7-\u1bf1\u1c00-\u1c35\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1d00-\u1dbf\u1de7-\u1df4\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u24b6-\u24e9\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fd5\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua674-\ua67b\ua67f-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7ae\ua7b0-\ua7b7\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua827\ua840-\ua873\ua880-\ua8c3\ua8c5\ua8f2-\ua8f7\ua8fb\ua8fd\ua90a-\ua92a\ua930-\ua952\ua960-\ua97c\ua980-\ua9b2\ua9b4-\ua9bf\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa36\uaa40-\uaa4d\uaa60-\uaa76\uaa7a\uaa7e-\uaabe\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf5\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab65\uab70-\uabea\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc",astral:"\ud800[\udc00-\udc0b\udc0d-\udc26\udc28-\udc3a\udc3c\udc3d\udc3f-\udc4d\udc50-\udc5d\udc80-\udcfa\udd40-\udd74\ude80-\ude9c\udea0-\uded0\udf00-\udf1f\udf30-\udf4a\udf50-\udf7a\udf80-\udf9d\udfa0-\udfc3\udfc8-\udfcf\udfd1-\udfd5]|\ud801[\udc00-\udc9d\udcb0-\udcd3\udcd8-\udcfb\udd00-\udd27\udd30-\udd63\ude00-\udf36\udf40-\udf55\udf60-\udf67]|\ud802[\udc00-\udc05\udc08\udc0a-\udc35\udc37\udc38\udc3c\udc3f-\udc55\udc60-\udc76\udc80-\udc9e\udce0-\udcf2\udcf4\udcf5\udd00-\udd15\udd20-\udd39\udd80-\uddb7\uddbe\uddbf\ude00-\ude03\ude05\ude06\ude0c-\ude13\ude15-\ude17\ude19-\ude33\ude60-\ude7c\ude80-\ude9c\udec0-\udec7\udec9-\udee4\udf00-\udf35\udf40-\udf55\udf60-\udf72\udf80-\udf91]|\ud803[\udc00-\udc48\udc80-\udcb2\udcc0-\udcf2]|\ud804[\udc00-\udc45\udc82-\udcb8\udcd0-\udce8\udd00-\udd32\udd50-\udd72\udd76\udd80-\uddbf\uddc1-\uddc4\uddda\udddc\ude00-\ude11\ude13-\ude34\ude37\ude3e\ude80-\ude86\ude88\ude8a-\ude8d\ude8f-\ude9d\ude9f-\udea8\udeb0-\udee8\udf00-\udf03\udf05-\udf0c\udf0f\udf10\udf13-\udf28\udf2a-\udf30\udf32\udf33\udf35-\udf39\udf3d-\udf44\udf47\udf48\udf4b\udf4c\udf50\udf57\udf5d-\udf63]|\ud805[\udc00-\udc41\udc43-\udc45\udc47-\udc4a\udc80-\udcc1\udcc4\udcc5\udcc7\udd80-\uddb5\uddb8-\uddbe\uddd8-\udddd\ude00-\ude3e\ude40\ude44\ude80-\udeb5\udf00-\udf19\udf1d-\udf2a]|\ud806[\udca0-\udcdf\udcff\udec0-\udef8]|\ud807[\udc00-\udc08\udc0a-\udc36\udc38-\udc3e\udc40\udc72-\udc8f\udc92-\udca7\udca9-\udcb6]|\ud808[\udc00-\udf99]|\ud809[\udc00-\udc6e\udc80-\udd43]|[\ud80c\ud81c-\ud820\ud840-\ud868\ud86a-\ud86c\ud86f-\ud872][\udc00-\udfff]|\ud80d[\udc00-\udc2e]|\ud811[\udc00-\ude46]|\ud81a[\udc00-\ude38\ude40-\ude5e\uded0-\udeed\udf00-\udf36\udf40-\udf43\udf63-\udf77\udf7d-\udf8f]|\ud81b[\udf00-\udf44\udf50-\udf7e\udf93-\udf9f\udfe0]|\ud821[\udc00-\udfec]|\ud822[\udc00-\udef2]|\ud82c[\udc00\udc01]|\ud82f[\udc00-\udc6a\udc70-\udc7c\udc80-\udc88\udc90-\udc99\udc9e]|\ud835[\udc00-\udc54\udc56-\udc9c\udc9e\udc9f\udca2\udca5\udca6\udca9-\udcac\udcae-\udcb9\udcbb\udcbd-\udcc3\udcc5-\udd05\udd07-\udd0a\udd0d-\udd14\udd16-\udd1c\udd1e-\udd39\udd3b-\udd3e\udd40-\udd44\udd46\udd4a-\udd50\udd52-\udea5\udea8-\udec0\udec2-\udeda\udedc-\udefa\udefc-\udf14\udf16-\udf34\udf36-\udf4e\udf50-\udf6e\udf70-\udf88\udf8a-\udfa8\udfaa-\udfc2\udfc4-\udfcb]|\ud838[\udc00-\udc06\udc08-\udc18\udc1b-\udc21\udc23\udc24\udc26-\udc2a]|\ud83a[\udc00-\udcc4\udd00-\udd43\udd47]|\ud83b[\ude00-\ude03\ude05-\ude1f\ude21\ude22\ude24\ude27\ude29-\ude32\ude34-\ude37\ude39\ude3b\ude42\ude47\ude49\ude4b\ude4d-\ude4f\ude51\ude52\ude54\ude57\ude59\ude5b\ude5d\ude5f\ude61\ude62\ude64\ude67-\ude6a\ude6c-\ude72\ude74-\ude77\ude79-\ude7c\ude7e\ude80-\ude89\ude8b-\ude9b\udea1-\udea3\udea5-\udea9\udeab-\udebb]|\ud83c[\udd30-\udd49\udd50-\udd69\udd70-\udd89]|\ud869[\udc00-\uded6\udf00-\udfff]|\ud86d[\udc00-\udf34\udf40-\udfff]|\ud86e[\udc00-\udc1d\udc20-\udfff]|\ud873[\udc00-\udea1]|\ud87e[\udc00-\ude1d]"},{name:"Any",isBmpLast:!0,bmp:"\0-\uffff",astral:"[\ud800-\udbff][\udc00-\udfff]"},{name:"Default_Ignorable_Code_Point",bmp:"\xad\u034f\u061c\u115f\u1160\u17b4\u17b5\u180b-\u180e\u200b-\u200f\u202a-\u202e\u2060-\u206f\u3164\ufe00-\ufe0f\ufeff\uffa0\ufff0-\ufff8",astral:"\ud82f[\udca0-\udca3]|\ud834[\udd73-\udd7a]|[\udb40-\udb43][\udc00-\udfff]"},{name:"Lowercase",bmp:"a-z\xaa\xb5\xba\xdf-\xf6\xf8-\xff\u0101\u0103\u0105\u0107\u0109\u010b\u010d\u010f\u0111\u0113\u0115\u0117\u0119\u011b\u011d\u011f\u0121\u0123\u0125\u0127\u0129\u012b\u012d\u012f\u0131\u0133\u0135\u0137\u0138\u013a\u013c\u013e\u0140\u0142\u0144\u0146\u0148\u0149\u014b\u014d\u014f\u0151\u0153\u0155\u0157\u0159\u015b\u015d\u015f\u0161\u0163\u0165\u0167\u0169\u016b\u016d\u016f\u0171\u0173\u0175\u0177\u017a\u017c\u017e-\u0180\u0183\u0185\u0188\u018c\u018d\u0192\u0195\u0199-\u019b\u019e\u01a1\u01a3\u01a5\u01a8\u01aa\u01ab\u01ad\u01b0\u01b4\u01b6\u01b9\u01ba\u01bd-\u01bf\u01c6\u01c9\u01cc\u01ce\u01d0\u01d2\u01d4\u01d6\u01d8\u01da\u01dc\u01dd\u01df\u01e1\u01e3\u01e5\u01e7\u01e9\u01eb\u01ed\u01ef\u01f0\u01f3\u01f5\u01f9\u01fb\u01fd\u01ff\u0201\u0203\u0205\u0207\u0209\u020b\u020d\u020f\u0211\u0213\u0215\u0217\u0219\u021b\u021d\u021f\u0221\u0223\u0225\u0227\u0229\u022b\u022d\u022f\u0231\u0233-\u0239\u023c\u023f\u0240\u0242\u0247\u0249\u024b\u024d\u024f-\u0293\u0295-\u02b8\u02c0\u02c1\u02e0-\u02e4\u0345\u0371\u0373\u0377\u037a-\u037d\u0390\u03ac-\u03ce\u03d0\u03d1\u03d5-\u03d7\u03d9\u03db\u03dd\u03df\u03e1\u03e3\u03e5\u03e7\u03e9\u03eb\u03ed\u03ef-\u03f3\u03f5\u03f8\u03fb\u03fc\u0430-\u045f\u0461\u0463\u0465\u0467\u0469\u046b\u046d\u046f\u0471\u0473\u0475\u0477\u0479\u047b\u047d\u047f\u0481\u048b\u048d\u048f\u0491\u0493\u0495\u0497\u0499\u049b\u049d\u049f\u04a1\u04a3\u04a5\u04a7\u04a9\u04ab\u04ad\u04af\u04b1\u04b3\u04b5\u04b7\u04b9\u04bb\u04bd\u04bf\u04c2\u04c4\u04c6\u04c8\u04ca\u04cc\u04ce\u04cf\u04d1\u04d3\u04d5\u04d7\u04d9\u04db\u04dd\u04df\u04e1\u04e3\u04e5\u04e7\u04e9\u04eb\u04ed\u04ef\u04f1\u04f3\u04f5\u04f7\u04f9\u04fb\u04fd\u04ff\u0501\u0503\u0505\u0507\u0509\u050b\u050d\u050f\u0511\u0513\u0515\u0517\u0519\u051b\u051d\u051f\u0521\u0523\u0525\u0527\u0529\u052b\u052d\u052f\u0561-\u0587\u13f8-\u13fd\u1c80-\u1c88\u1d00-\u1dbf\u1e01\u1e03\u1e05\u1e07\u1e09\u1e0b\u1e0d\u1e0f\u1e11\u1e13\u1e15\u1e17\u1e19\u1e1b\u1e1d\u1e1f\u1e21\u1e23\u1e25\u1e27\u1e29\u1e2b\u1e2d\u1e2f\u1e31\u1e33\u1e35\u1e37\u1e39\u1e3b\u1e3d\u1e3f\u1e41\u1e43\u1e45\u1e47\u1e49\u1e4b\u1e4d\u1e4f\u1e51\u1e53\u1e55\u1e57\u1e59\u1e5b\u1e5d\u1e5f\u1e61\u1e63\u1e65\u1e67\u1e69\u1e6b\u1e6d\u1e6f\u1e71\u1e73\u1e75\u1e77\u1e79\u1e7b\u1e7d\u1e7f\u1e81\u1e83\u1e85\u1e87\u1e89\u1e8b\u1e8d\u1e8f\u1e91\u1e93\u1e95-\u1e9d\u1e9f\u1ea1\u1ea3\u1ea5\u1ea7\u1ea9\u1eab\u1ead\u1eaf\u1eb1\u1eb3\u1eb5\u1eb7\u1eb9\u1ebb\u1ebd\u1ebf\u1ec1\u1ec3\u1ec5\u1ec7\u1ec9\u1ecb\u1ecd\u1ecf\u1ed1\u1ed3\u1ed5\u1ed7\u1ed9\u1edb\u1edd\u1edf\u1ee1\u1ee3\u1ee5\u1ee7\u1ee9\u1eeb\u1eed\u1eef\u1ef1\u1ef3\u1ef5\u1ef7\u1ef9\u1efb\u1efd\u1eff-\u1f07\u1f10-\u1f15\u1f20-\u1f27\u1f30-\u1f37\u1f40-\u1f45\u1f50-\u1f57\u1f60-\u1f67\u1f70-\u1f7d\u1f80-\u1f87\u1f90-\u1f97\u1fa0-\u1fa7\u1fb0-\u1fb4\u1fb6\u1fb7\u1fbe\u1fc2-\u1fc4\u1fc6\u1fc7\u1fd0-\u1fd3\u1fd6\u1fd7\u1fe0-\u1fe7\u1ff2-\u1ff4\u1ff6\u1ff7\u2071\u207f\u2090-\u209c\u210a\u210e\u210f\u2113\u212f\u2134\u2139\u213c\u213d\u2146-\u2149\u214e\u2170-\u217f\u2184\u24d0-\u24e9\u2c30-\u2c5e\u2c61\u2c65\u2c66\u2c68\u2c6a\u2c6c\u2c71\u2c73\u2c74\u2c76-\u2c7d\u2c81\u2c83\u2c85\u2c87\u2c89\u2c8b\u2c8d\u2c8f\u2c91\u2c93\u2c95\u2c97\u2c99\u2c9b\u2c9d\u2c9f\u2ca1\u2ca3\u2ca5\u2ca7\u2ca9\u2cab\u2cad\u2caf\u2cb1\u2cb3\u2cb5\u2cb7\u2cb9\u2cbb\u2cbd\u2cbf\u2cc1\u2cc3\u2cc5\u2cc7\u2cc9\u2ccb\u2ccd\u2ccf\u2cd1\u2cd3\u2cd5\u2cd7\u2cd9\u2cdb\u2cdd\u2cdf\u2ce1\u2ce3\u2ce4\u2cec\u2cee\u2cf3\u2d00-\u2d25\u2d27\u2d2d\ua641\ua643\ua645\ua647\ua649\ua64b\ua64d\ua64f\ua651\ua653\ua655\ua657\ua659\ua65b\ua65d\ua65f\ua661\ua663\ua665\ua667\ua669\ua66b\ua66d\ua681\ua683\ua685\ua687\ua689\ua68b\ua68d\ua68f\ua691\ua693\ua695\ua697\ua699\ua69b-\ua69d\ua723\ua725\ua727\ua729\ua72b\ua72d\ua72f-\ua731\ua733\ua735\ua737\ua739\ua73b\ua73d\ua73f\ua741\ua743\ua745\ua747\ua749\ua74b\ua74d\ua74f\ua751\ua753\ua755\ua757\ua759\ua75b\ua75d\ua75f\ua761\ua763\ua765\ua767\ua769\ua76b\ua76d\ua76f-\ua778\ua77a\ua77c\ua77f\ua781\ua783\ua785\ua787\ua78c\ua78e\ua791\ua793-\ua795\ua797\ua799\ua79b\ua79d\ua79f\ua7a1\ua7a3\ua7a5\ua7a7\ua7a9\ua7b5\ua7b7\ua7f8-\ua7fa\uab30-\uab5a\uab5c-\uab65\uab70-\uabbf\ufb00-\ufb06\ufb13-\ufb17\uff41-\uff5a",astral:"\ud801[\udc28-\udc4f\udcd8-\udcfb]|\ud803[\udcc0-\udcf2]|\ud806[\udcc0-\udcdf]|\ud835[\udc1a-\udc33\udc4e-\udc54\udc56-\udc67\udc82-\udc9b\udcb6-\udcb9\udcbb\udcbd-\udcc3\udcc5-\udccf\udcea-\udd03\udd1e-\udd37\udd52-\udd6b\udd86-\udd9f\uddba-\uddd3\uddee-\ude07\ude22-\ude3b\ude56-\ude6f\ude8a-\udea5\udec2-\udeda\udedc-\udee1\udefc-\udf14\udf16-\udf1b\udf36-\udf4e\udf50-\udf55\udf70-\udf88\udf8a-\udf8f\udfaa-\udfc2\udfc4-\udfc9\udfcb]|\ud83a[\udd22-\udd43]"},{name:"Noncharacter_Code_Point",bmp:"\ufdd0-\ufdef\ufffe\uffff",astral:"[\ud83f\ud87f\ud8bf\ud8ff\ud93f\ud97f\ud9bf\ud9ff\uda3f\uda7f\udabf\udaff\udb3f\udb7f\udbbf\udbff][\udffe\udfff]"},{name:"Uppercase",bmp:"A-Z\xc0-\xd6\xd8-\xde\u0100\u0102\u0104\u0106\u0108\u010a\u010c\u010e\u0110\u0112\u0114\u0116\u0118\u011a\u011c\u011e\u0120\u0122\u0124\u0126\u0128\u012a\u012c\u012e\u0130\u0132\u0134\u0136\u0139\u013b\u013d\u013f\u0141\u0143\u0145\u0147\u014a\u014c\u014e\u0150\u0152\u0154\u0156\u0158\u015a\u015c\u015e\u0160\u0162\u0164\u0166\u0168\u016a\u016c\u016e\u0170\u0172\u0174\u0176\u0178\u0179\u017b\u017d\u0181\u0182\u0184\u0186\u0187\u0189-\u018b\u018e-\u0191\u0193\u0194\u0196-\u0198\u019c\u019d\u019f\u01a0\u01a2\u01a4\u01a6\u01a7\u01a9\u01ac\u01ae\u01af\u01b1-\u01b3\u01b5\u01b7\u01b8\u01bc\u01c4\u01c7\u01ca\u01cd\u01cf\u01d1\u01d3\u01d5\u01d7\u01d9\u01db\u01de\u01e0\u01e2\u01e4\u01e6\u01e8\u01ea\u01ec\u01ee\u01f1\u01f4\u01f6-\u01f8\u01fa\u01fc\u01fe\u0200\u0202\u0204\u0206\u0208\u020a\u020c\u020e\u0210\u0212\u0214\u0216\u0218\u021a\u021c\u021e\u0220\u0222\u0224\u0226\u0228\u022a\u022c\u022e\u0230\u0232\u023a\u023b\u023d\u023e\u0241\u0243-\u0246\u0248\u024a\u024c\u024e\u0370\u0372\u0376\u037f\u0386\u0388-\u038a\u038c\u038e\u038f\u0391-\u03a1\u03a3-\u03ab\u03cf\u03d2-\u03d4\u03d8\u03da\u03dc\u03de\u03e0\u03e2\u03e4\u03e6\u03e8\u03ea\u03ec\u03ee\u03f4\u03f7\u03f9\u03fa\u03fd-\u042f\u0460\u0462\u0464\u0466\u0468\u046a\u046c\u046e\u0470\u0472\u0474\u0476\u0478\u047a\u047c\u047e\u0480\u048a\u048c\u048e\u0490\u0492\u0494\u0496\u0498\u049a\u049c\u049e\u04a0\u04a2\u04a4\u04a6\u04a8\u04aa\u04ac\u04ae\u04b0\u04b2\u04b4\u04b6\u04b8\u04ba\u04bc\u04be\u04c0\u04c1\u04c3\u04c5\u04c7\u04c9\u04cb\u04cd\u04d0\u04d2\u04d4\u04d6\u04d8\u04da\u04dc\u04de\u04e0\u04e2\u04e4\u04e6\u04e8\u04ea\u04ec\u04ee\u04f0\u04f2\u04f4\u04f6\u04f8\u04fa\u04fc\u04fe\u0500\u0502\u0504\u0506\u0508\u050a\u050c\u050e\u0510\u0512\u0514\u0516\u0518\u051a\u051c\u051e\u0520\u0522\u0524\u0526\u0528\u052a\u052c\u052e\u0531-\u0556\u10a0-\u10c5\u10c7\u10cd\u13a0-\u13f5\u1e00\u1e02\u1e04\u1e06\u1e08\u1e0a\u1e0c\u1e0e\u1e10\u1e12\u1e14\u1e16\u1e18\u1e1a\u1e1c\u1e1e\u1e20\u1e22\u1e24\u1e26\u1e28\u1e2a\u1e2c\u1e2e\u1e30\u1e32\u1e34\u1e36\u1e38\u1e3a\u1e3c\u1e3e\u1e40\u1e42\u1e44\u1e46\u1e48\u1e4a\u1e4c\u1e4e\u1e50\u1e52\u1e54\u1e56\u1e58\u1e5a\u1e5c\u1e5e\u1e60\u1e62\u1e64\u1e66\u1e68\u1e6a\u1e6c\u1e6e\u1e70\u1e72\u1e74\u1e76\u1e78\u1e7a\u1e7c\u1e7e\u1e80\u1e82\u1e84\u1e86\u1e88\u1e8a\u1e8c\u1e8e\u1e90\u1e92\u1e94\u1e9e\u1ea0\u1ea2\u1ea4\u1ea6\u1ea8\u1eaa\u1eac\u1eae\u1eb0\u1eb2\u1eb4\u1eb6\u1eb8\u1eba\u1ebc\u1ebe\u1ec0\u1ec2\u1ec4\u1ec6\u1ec8\u1eca\u1ecc\u1ece\u1ed0\u1ed2\u1ed4\u1ed6\u1ed8\u1eda\u1edc\u1ede\u1ee0\u1ee2\u1ee4\u1ee6\u1ee8\u1eea\u1eec\u1eee\u1ef0\u1ef2\u1ef4\u1ef6\u1ef8\u1efa\u1efc\u1efe\u1f08-\u1f0f\u1f18-\u1f1d\u1f28-\u1f2f\u1f38-\u1f3f\u1f48-\u1f4d\u1f59\u1f5b\u1f5d\u1f5f\u1f68-\u1f6f\u1fb8-\u1fbb\u1fc8-\u1fcb\u1fd8-\u1fdb\u1fe8-\u1fec\u1ff8-\u1ffb\u2102\u2107\u210b-\u210d\u2110-\u2112\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u2130-\u2133\u213e\u213f\u2145\u2160-\u216f\u2183\u24b6-\u24cf\u2c00-\u2c2e\u2c60\u2c62-\u2c64\u2c67\u2c69\u2c6b\u2c6d-\u2c70\u2c72\u2c75\u2c7e-\u2c80\u2c82\u2c84\u2c86\u2c88\u2c8a\u2c8c\u2c8e\u2c90\u2c92\u2c94\u2c96\u2c98\u2c9a\u2c9c\u2c9e\u2ca0\u2ca2\u2ca4\u2ca6\u2ca8\u2caa\u2cac\u2cae\u2cb0\u2cb2\u2cb4\u2cb6\u2cb8\u2cba\u2cbc\u2cbe\u2cc0\u2cc2\u2cc4\u2cc6\u2cc8\u2cca\u2ccc\u2cce\u2cd0\u2cd2\u2cd4\u2cd6\u2cd8\u2cda\u2cdc\u2cde\u2ce0\u2ce2\u2ceb\u2ced\u2cf2\ua640\ua642\ua644\ua646\ua648\ua64a\ua64c\ua64e\ua650\ua652\ua654\ua656\ua658\ua65a\ua65c\ua65e\ua660\ua662\ua664\ua666\ua668\ua66a\ua66c\ua680\ua682\ua684\ua686\ua688\ua68a\ua68c\ua68e\ua690\ua692\ua694\ua696\ua698\ua69a\ua722\ua724\ua726\ua728\ua72a\ua72c\ua72e\ua732\ua734\ua736\ua738\ua73a\ua73c\ua73e\ua740\ua742\ua744\ua746\ua748\ua74a\ua74c\ua74e\ua750\ua752\ua754\ua756\ua758\ua75a\ua75c\ua75e\ua760\ua762\ua764\ua766\ua768\ua76a\ua76c\ua76e\ua779\ua77b\ua77d\ua77e\ua780\ua782\ua784\ua786\ua78b\ua78d\ua790\ua792\ua796\ua798\ua79a\ua79c\ua79e\ua7a0\ua7a2\ua7a4\ua7a6\ua7a8\ua7aa-\ua7ae\ua7b0-\ua7b4\ua7b6\uff21-\uff3a",astral:"\ud801[\udc00-\udc27\udcb0-\udcd3]|\ud803[\udc80-\udcb2]|\ud806[\udca0-\udcbf]|\ud835[\udc00-\udc19\udc34-\udc4d\udc68-\udc81\udc9c\udc9e\udc9f\udca2\udca5\udca6\udca9-\udcac\udcae-\udcb5\udcd0-\udce9\udd04\udd05\udd07-\udd0a\udd0d-\udd14\udd16-\udd1c\udd38\udd39\udd3b-\udd3e\udd40-\udd44\udd46\udd4a-\udd50\udd6c-\udd85\udda0-\uddb9\uddd4-\udded\ude08-\ude21\ude3c-\ude55\ude70-\ude89\udea8-\udec0\udee2-\udefa\udf1c-\udf34\udf56-\udf6e\udf90-\udfa8\udfca]|\ud83a[\udd00-\udd21]|\ud83c[\udd30-\udd49\udd50-\udd69\udd70-\udd89]"},{name:"White_Space",bmp:"\t-\r \x85\xa0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000"}];u.push({name:"Assigned",inverseOf:"Cn"}),e.addUnicodeData(u)},e.exports=u.default},499:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0}),u.default=function(e){if(!e.addUnicodeData)throw new ReferenceError("Unicode Base must be loaded before Unicode Scripts");e.addUnicodeData([{name:"Adlam",astral:"\ud83a[\udd00-\udd4a\udd50-\udd59\udd5e\udd5f]"},{name:"Ahom",astral:"\ud805[\udf00-\udf19\udf1d-\udf2b\udf30-\udf3f]"},{name:"Anatolian_Hieroglyphs",astral:"\ud811[\udc00-\ude46]"},{name:"Arabic",bmp:"\u0600-\u0604\u0606-\u060b\u060d-\u061a\u061e\u0620-\u063f\u0641-\u064a\u0656-\u066f\u0671-\u06dc\u06de-\u06ff\u0750-\u077f\u08a0-\u08b4\u08b6-\u08bd\u08d4-\u08e1\u08e3-\u08ff\ufb50-\ufbc1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfd\ufe70-\ufe74\ufe76-\ufefc",astral:"\ud803[\ude60-\ude7e]|\ud83b[\ude00-\ude03\ude05-\ude1f\ude21\ude22\ude24\ude27\ude29-\ude32\ude34-\ude37\ude39\ude3b\ude42\ude47\ude49\ude4b\ude4d-\ude4f\ude51\ude52\ude54\ude57\ude59\ude5b\ude5d\ude5f\ude61\ude62\ude64\ude67-\ude6a\ude6c-\ude72\ude74-\ude77\ude79-\ude7c\ude7e\ude80-\ude89\ude8b-\ude9b\udea1-\udea3\udea5-\udea9\udeab-\udebb\udef0\udef1]"},{name:"Armenian",bmp:"\u0531-\u0556\u0559-\u055f\u0561-\u0587\u058a\u058d-\u058f\ufb13-\ufb17"},{name:"Avestan",astral:"\ud802[\udf00-\udf35\udf39-\udf3f]"},{name:"Balinese",bmp:"\u1b00-\u1b4b\u1b50-\u1b7c"},{name:"Bamum",bmp:"\ua6a0-\ua6f7",astral:"\ud81a[\udc00-\ude38]"},{name:"Bassa_Vah",astral:"\ud81a[\uded0-\udeed\udef0-\udef5]"},{name:"Batak",bmp:"\u1bc0-\u1bf3\u1bfc-\u1bff"},{name:"Bengali",bmp:"\u0980-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09fb"},{name:"Bhaiksuki",astral:"\ud807[\udc00-\udc08\udc0a-\udc36\udc38-\udc45\udc50-\udc6c]"},{name:"Bopomofo",bmp:"\u02ea\u02eb\u3105-\u312d\u31a0-\u31ba"},{name:"Brahmi",astral:"\ud804[\udc00-\udc4d\udc52-\udc6f\udc7f]"},{name:"Braille",bmp:"\u2800-\u28ff"},{name:"Buginese",bmp:"\u1a00-\u1a1b\u1a1e\u1a1f"},{name:"Buhid",bmp:"\u1740-\u1753"},{name:"Canadian_Aboriginal",bmp:"\u1400-\u167f\u18b0-\u18f5"},{name:"Carian",astral:"\ud800[\udea0-\uded0]"},{name:"Caucasian_Albanian",astral:"\ud801[\udd30-\udd63\udd6f]"},{name:"Chakma",astral:"\ud804[\udd00-\udd34\udd36-\udd43]"},{name:"Cham",bmp:"\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa5c-\uaa5f"},{name:"Cherokee",bmp:"\u13a0-\u13f5\u13f8-\u13fd\uab70-\uabbf"},{name:"Common",bmp:"\0-@\\x5B-`\\x7B-\xa9\xab-\xb9\xbb-\xbf\xd7\xf7\u02b9-\u02df\u02e5-\u02e9\u02ec-\u02ff\u0374\u037e\u0385\u0387\u0589\u0605\u060c\u061b\u061c\u061f\u0640\u06dd\u08e2\u0964\u0965\u0e3f\u0fd5-\u0fd8\u10fb\u16eb-\u16ed\u1735\u1736\u1802\u1803\u1805\u1cd3\u1ce1\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u2000-\u200b\u200e-\u2064\u2066-\u2070\u2074-\u207e\u2080-\u208e\u20a0-\u20be\u2100-\u2125\u2127-\u2129\u212c-\u2131\u2133-\u214d\u214f-\u215f\u2189-\u218b\u2190-\u23fe\u2400-\u2426\u2440-\u244a\u2460-\u27ff\u2900-\u2b73\u2b76-\u2b95\u2b98-\u2bb9\u2bbd-\u2bc8\u2bca-\u2bd1\u2bec-\u2bef\u2e00-\u2e44\u2ff0-\u2ffb\u3000-\u3004\u3006\u3008-\u3020\u3030-\u3037\u303c-\u303f\u309b\u309c\u30a0\u30fb\u30fc\u3190-\u319f\u31c0-\u31e3\u3220-\u325f\u327f-\u32cf\u3358-\u33ff\u4dc0-\u4dff\ua700-\ua721\ua788-\ua78a\ua830-\ua839\ua92e\ua9cf\uab5b\ufd3e\ufd3f\ufe10-\ufe19\ufe30-\ufe52\ufe54-\ufe66\ufe68-\ufe6b\ufeff\uff01-\uff20\uff3b-\uff40\uff5b-\uff65\uff70\uff9e\uff9f\uffe0-\uffe6\uffe8-\uffee\ufff9-\ufffd",astral:"\ud800[\udd00-\udd02\udd07-\udd33\udd37-\udd3f\udd90-\udd9b\uddd0-\uddfc\udee1-\udefb]|\ud82f[\udca0-\udca3]|\ud834[\udc00-\udcf5\udd00-\udd26\udd29-\udd66\udd6a-\udd7a\udd83\udd84\udd8c-\udda9\uddae-\udde8\udf00-\udf56\udf60-\udf71]|\ud835[\udc00-\udc54\udc56-\udc9c\udc9e\udc9f\udca2\udca5\udca6\udca9-\udcac\udcae-\udcb9\udcbb\udcbd-\udcc3\udcc5-\udd05\udd07-\udd0a\udd0d-\udd14\udd16-\udd1c\udd1e-\udd39\udd3b-\udd3e\udd40-\udd44\udd46\udd4a-\udd50\udd52-\udea5\udea8-\udfcb\udfce-\udfff]|\ud83c[\udc00-\udc2b\udc30-\udc93\udca0-\udcae\udcb1-\udcbf\udcc1-\udccf\udcd1-\udcf5\udd00-\udd0c\udd10-\udd2e\udd30-\udd6b\udd70-\uddac\udde6-\uddff\ude01\ude02\ude10-\ude3b\ude40-\ude48\ude50\ude51\udf00-\udfff]|\ud83d[\udc00-\uded2\udee0-\udeec\udef0-\udef6\udf00-\udf73\udf80-\udfd4]|\ud83e[\udc00-\udc0b\udc10-\udc47\udc50-\udc59\udc60-\udc87\udc90-\udcad\udd10-\udd1e\udd20-\udd27\udd30\udd33-\udd3e\udd40-\udd4b\udd50-\udd5e\udd80-\udd91\uddc0]|\udb40[\udc01\udc20-\udc7f]"},{name:"Coptic",bmp:"\u03e2-\u03ef\u2c80-\u2cf3\u2cf9-\u2cff"},{name:"Cuneiform",astral:"\ud808[\udc00-\udf99]|\ud809[\udc00-\udc6e\udc70-\udc74\udc80-\udd43]"},{name:"Cypriot",astral:"\ud802[\udc00-\udc05\udc08\udc0a-\udc35\udc37\udc38\udc3c\udc3f]"},{name:"Cyrillic",bmp:"\u0400-\u0484\u0487-\u052f\u1c80-\u1c88\u1d2b\u1d78\u2de0-\u2dff\ua640-\ua69f\ufe2e\ufe2f"},{name:"Deseret",astral:"\ud801[\udc00-\udc4f]"},{name:"Devanagari",bmp:"\u0900-\u0950\u0953-\u0963\u0966-\u097f\ua8e0-\ua8fd"},{name:"Duployan",astral:"\ud82f[\udc00-\udc6a\udc70-\udc7c\udc80-\udc88\udc90-\udc99\udc9c-\udc9f]"},{name:"Egyptian_Hieroglyphs",astral:"\ud80c[\udc00-\udfff]|\ud80d[\udc00-\udc2e]"},{name:"Elbasan",astral:"\ud801[\udd00-\udd27]"},{name:"Ethiopic",bmp:"\u1200-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u137c\u1380-\u1399\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e"},{name:"Georgian",bmp:"\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u10ff\u2d00-\u2d25\u2d27\u2d2d"},{name:"Glagolitic",bmp:"\u2c00-\u2c2e\u2c30-\u2c5e",astral:"\ud838[\udc00-\udc06\udc08-\udc18\udc1b-\udc21\udc23\udc24\udc26-\udc2a]"},{name:"Gothic",astral:"\ud800[\udf30-\udf4a]"},{name:"Grantha",astral:"\ud804[\udf00-\udf03\udf05-\udf0c\udf0f\udf10\udf13-\udf28\udf2a-\udf30\udf32\udf33\udf35-\udf39\udf3c-\udf44\udf47\udf48\udf4b-\udf4d\udf50\udf57\udf5d-\udf63\udf66-\udf6c\udf70-\udf74]"},{name:"Greek",bmp:"\u0370-\u0373\u0375-\u0377\u037a-\u037d\u037f\u0384\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03e1\u03f0-\u03ff\u1d26-\u1d2a\u1d5d-\u1d61\u1d66-\u1d6a\u1dbf\u1f00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fc4\u1fc6-\u1fd3\u1fd6-\u1fdb\u1fdd-\u1fef\u1ff2-\u1ff4\u1ff6-\u1ffe\u2126\uab65",astral:"\ud800[\udd40-\udd8e\udda0]|\ud834[\ude00-\ude45]"},{name:"Gujarati",bmp:"\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0af1\u0af9"},{name:"Gurmukhi",bmp:"\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75"},{name:"Han",bmp:"\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u3005\u3007\u3021-\u3029\u3038-\u303b\u3400-\u4db5\u4e00-\u9fd5\uf900-\ufa6d\ufa70-\ufad9",astral:"[\ud840-\ud868\ud86a-\ud86c\ud86f-\ud872][\udc00-\udfff]|\ud869[\udc00-\uded6\udf00-\udfff]|\ud86d[\udc00-\udf34\udf40-\udfff]|\ud86e[\udc00-\udc1d\udc20-\udfff]|\ud873[\udc00-\udea1]|\ud87e[\udc00-\ude1d]"},{name:"Hangul",bmp:"\u1100-\u11ff\u302e\u302f\u3131-\u318e\u3200-\u321e\u3260-\u327e\ua960-\ua97c\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uffa0-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc"},{name:"Hanunoo",bmp:"\u1720-\u1734"},{name:"Hatran",astral:"\ud802[\udce0-\udcf2\udcf4\udcf5\udcfb-\udcff]"},{name:"Hebrew",bmp:"\u0591-\u05c7\u05d0-\u05ea\u05f0-\u05f4\ufb1d-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufb4f"},{name:"Hiragana",bmp:"\u3041-\u3096\u309d-\u309f",astral:"\ud82c\udc01|\ud83c\ude00"},{name:"Imperial_Aramaic",astral:"\ud802[\udc40-\udc55\udc57-\udc5f]"},{name:"Inherited",bmp:"\u0300-\u036f\u0485\u0486\u064b-\u0655\u0670\u0951\u0952\u1ab0-\u1abe\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1cf4\u1cf8\u1cf9\u1dc0-\u1df5\u1dfb-\u1dff\u200c\u200d\u20d0-\u20f0\u302a-\u302d\u3099\u309a\ufe00-\ufe0f\ufe20-\ufe2d",astral:"\ud800[\uddfd\udee0]|\ud834[\udd67-\udd69\udd7b-\udd82\udd85-\udd8b\uddaa-\uddad]|\udb40[\udd00-\uddef]"},{name:"Inscriptional_Pahlavi",astral:"\ud802[\udf60-\udf72\udf78-\udf7f]"},{name:"Inscriptional_Parthian",astral:"\ud802[\udf40-\udf55\udf58-\udf5f]"},{name:"Javanese",bmp:"\ua980-\ua9cd\ua9d0-\ua9d9\ua9de\ua9df"},{name:"Kaithi",astral:"\ud804[\udc80-\udcc1]"},{name:"Kannada",bmp:"\u0c80-\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2"},{name:"Katakana",bmp:"\u30a1-\u30fa\u30fd-\u30ff\u31f0-\u31ff\u32d0-\u32fe\u3300-\u3357\uff66-\uff6f\uff71-\uff9d",astral:"\ud82c\udc00"},{name:"Kayah_Li",bmp:"\ua900-\ua92d\ua92f"},{name:"Kharoshthi",astral:"\ud802[\ude00-\ude03\ude05\ude06\ude0c-\ude13\ude15-\ude17\ude19-\ude33\ude38-\ude3a\ude3f-\ude47\ude50-\ude58]"},{name:"Khmer",bmp:"\u1780-\u17dd\u17e0-\u17e9\u17f0-\u17f9\u19e0-\u19ff"},{name:"Khojki",astral:"\ud804[\ude00-\ude11\ude13-\ude3e]"},{name:"Khudawadi",astral:"\ud804[\udeb0-\udeea\udef0-\udef9]"},{name:"Lao",bmp:"\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf"},{name:"Latin",bmp:"A-Za-z\xaa\xba\xc0-\xd6\xd8-\xf6\xf8-\u02b8\u02e0-\u02e4\u1d00-\u1d25\u1d2c-\u1d5c\u1d62-\u1d65\u1d6b-\u1d77\u1d79-\u1dbe\u1e00-\u1eff\u2071\u207f\u2090-\u209c\u212a\u212b\u2132\u214e\u2160-\u2188\u2c60-\u2c7f\ua722-\ua787\ua78b-\ua7ae\ua7b0-\ua7b7\ua7f7-\ua7ff\uab30-\uab5a\uab5c-\uab64\ufb00-\ufb06\uff21-\uff3a\uff41-\uff5a"},{name:"Lepcha",bmp:"\u1c00-\u1c37\u1c3b-\u1c49\u1c4d-\u1c4f"},{name:"Limbu",bmp:"\u1900-\u191e\u1920-\u192b\u1930-\u193b\u1940\u1944-\u194f"},{name:"Linear_A",astral:"\ud801[\ude00-\udf36\udf40-\udf55\udf60-\udf67]"},{name:"Linear_B",astral:"\ud800[\udc00-\udc0b\udc0d-\udc26\udc28-\udc3a\udc3c\udc3d\udc3f-\udc4d\udc50-\udc5d\udc80-\udcfa]"},{name:"Lisu",bmp:"\ua4d0-\ua4ff"},{name:"Lycian",astral:"\ud800[\ude80-\ude9c]"},{name:"Lydian",astral:"\ud802[\udd20-\udd39\udd3f]"},{name:"Mahajani",astral:"\ud804[\udd50-\udd76]"},{name:"Malayalam",bmp:"\u0d01-\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4f\u0d54-\u0d63\u0d66-\u0d7f"},{name:"Mandaic",bmp:"\u0840-\u085b\u085e"},{name:"Manichaean",astral:"\ud802[\udec0-\udee6\udeeb-\udef6]"},{name:"Marchen",astral:"\ud807[\udc70-\udc8f\udc92-\udca7\udca9-\udcb6]"},{name:"Meetei_Mayek",bmp:"\uaae0-\uaaf6\uabc0-\uabed\uabf0-\uabf9"},{name:"Mende_Kikakui",astral:"\ud83a[\udc00-\udcc4\udcc7-\udcd6]"},{name:"Meroitic_Cursive",astral:"\ud802[\udda0-\uddb7\uddbc-\uddcf\uddd2-\uddff]"},{name:"Meroitic_Hieroglyphs",astral:"\ud802[\udd80-\udd9f]"},{name:"Miao",astral:"\ud81b[\udf00-\udf44\udf50-\udf7e\udf8f-\udf9f]"},{name:"Modi",astral:"\ud805[\ude00-\ude44\ude50-\ude59]"},{name:"Mongolian",bmp:"\u1800\u1801\u1804\u1806-\u180e\u1810-\u1819\u1820-\u1877\u1880-\u18aa",astral:"\ud805[\ude60-\ude6c]"},{name:"Mro",astral:"\ud81a[\ude40-\ude5e\ude60-\ude69\ude6e\ude6f]"},{name:"Multani",astral:"\ud804[\ude80-\ude86\ude88\ude8a-\ude8d\ude8f-\ude9d\ude9f-\udea9]"},{name:"Myanmar",bmp:"\u1000-\u109f\ua9e0-\ua9fe\uaa60-\uaa7f"},{name:"Nabataean",astral:"\ud802[\udc80-\udc9e\udca7-\udcaf]"},{name:"New_Tai_Lue",bmp:"\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19da\u19de\u19df"},{name:"Newa",astral:"\ud805[\udc00-\udc59\udc5b\udc5d]"},{name:"Nko",bmp:"\u07c0-\u07fa"},{name:"Ogham",bmp:"\u1680-\u169c"},{name:"Ol_Chiki",bmp:"\u1c50-\u1c7f"},{name:"Old_Hungarian",astral:"\ud803[\udc80-\udcb2\udcc0-\udcf2\udcfa-\udcff]"},{name:"Old_Italic",astral:"\ud800[\udf00-\udf23]"},{name:"Old_North_Arabian",astral:"\ud802[\ude80-\ude9f]"},{name:"Old_Permic",astral:"\ud800[\udf50-\udf7a]"},{name:"Old_Persian",astral:"\ud800[\udfa0-\udfc3\udfc8-\udfd5]"},{name:"Old_South_Arabian",astral:"\ud802[\ude60-\ude7f]"},{name:"Old_Turkic",astral:"\ud803[\udc00-\udc48]"},{name:"Oriya",bmp:"\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b77"},{name:"Osage",astral:"\ud801[\udcb0-\udcd3\udcd8-\udcfb]"},{name:"Osmanya",astral:"\ud801[\udc80-\udc9d\udca0-\udca9]"},{name:"Pahawh_Hmong",astral:"\ud81a[\udf00-\udf45\udf50-\udf59\udf5b-\udf61\udf63-\udf77\udf7d-\udf8f]"},{name:"Palmyrene",astral:"\ud802[\udc60-\udc7f]"},{name:"Pau_Cin_Hau",astral:"\ud806[\udec0-\udef8]"},{name:"Phags_Pa",bmp:"\ua840-\ua877"},{name:"Phoenician",astral:"\ud802[\udd00-\udd1b\udd1f]"},{name:"Psalter_Pahlavi",astral:"\ud802[\udf80-\udf91\udf99-\udf9c\udfa9-\udfaf]"},{name:"Rejang",bmp:"\ua930-\ua953\ua95f"},{name:"Runic",bmp:"\u16a0-\u16ea\u16ee-\u16f8"},{name:"Samaritan",bmp:"\u0800-\u082d\u0830-\u083e"},{name:"Saurashtra",bmp:"\ua880-\ua8c5\ua8ce-\ua8d9"},{name:"Sharada",astral:"\ud804[\udd80-\uddcd\uddd0-\udddf]"},{name:"Shavian",astral:"\ud801[\udc50-\udc7f]"},{name:"Siddham",astral:"\ud805[\udd80-\uddb5\uddb8-\udddd]"},{name:"SignWriting",astral:"\ud836[\udc00-\ude8b\ude9b-\ude9f\udea1-\udeaf]"},{name:"Sinhala",bmp:"\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2-\u0df4",astral:"\ud804[\udde1-\uddf4]"},{name:"Sora_Sompeng",astral:"\ud804[\udcd0-\udce8\udcf0-\udcf9]"},{name:"Sundanese",bmp:"\u1b80-\u1bbf\u1cc0-\u1cc7"},{name:"Syloti_Nagri",bmp:"\ua800-\ua82b"},{name:"Syriac",bmp:"\u0700-\u070d\u070f-\u074a\u074d-\u074f"},{name:"Tagalog",bmp:"\u1700-\u170c\u170e-\u1714"},{name:"Tagbanwa",bmp:"\u1760-\u176c\u176e-\u1770\u1772\u1773"},{name:"Tai_Le",bmp:"\u1950-\u196d\u1970-\u1974"},{name:"Tai_Tham",bmp:"\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa0-\u1aad"},{name:"Tai_Viet",bmp:"\uaa80-\uaac2\uaadb-\uaadf"},{name:"Takri",astral:"\ud805[\ude80-\udeb7\udec0-\udec9]"},{name:"Tamil",bmp:"\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bfa"},{name:"Tangut",astral:"\ud81b\udfe0|[\ud81c-\ud820][\udc00-\udfff]|\ud821[\udc00-\udfec]|\ud822[\udc00-\udef2]"},{name:"Telugu",bmp:"\u0c00-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58-\u0c5a\u0c60-\u0c63\u0c66-\u0c6f\u0c78-\u0c7f"},{name:"Thaana",bmp:"\u0780-\u07b1"},{name:"Thai",bmp:"\u0e01-\u0e3a\u0e40-\u0e5b"},{name:"Tibetan",bmp:"\u0f00-\u0f47\u0f49-\u0f6c\u0f71-\u0f97\u0f99-\u0fbc\u0fbe-\u0fcc\u0fce-\u0fd4\u0fd9\u0fda"},{name:"Tifinagh",bmp:"\u2d30-\u2d67\u2d6f\u2d70\u2d7f"},{name:"Tirhuta",astral:"\ud805[\udc80-\udcc7\udcd0-\udcd9]"},{name:"Ugaritic",astral:"\ud800[\udf80-\udf9d\udf9f]"},{name:"Vai",bmp:"\ua500-\ua62b"},{name:"Warang_Citi",astral:"\ud806[\udca0-\udcf2\udcff]"},{name:"Yi",bmp:"\ua000-\ua48c\ua490-\ua4c6"}])},e.exports=u.default},500:function(e,u,t){"use strict";var n=t(0),d=t.n(n);u.a=function(e){var u=e.text;return d.a.createElement("section",{className:"empty"},d.a.createElement("div",{className:"icon"},d.a.createElement("img",{src:"/img/logo-square.svg",alt:"The Qovery Logo"})),d.a.createElement("div",{className:"text"},u))}},501:function(e,u,t){"use strict";var n=t(502),d=t(512),r=t(468);e.exports={formats:r,parse:d,stringify:n}},502:function(e,u,t){"use strict";var n=t(503),d=t(475),r=t(468),a=Object.prototype.hasOwnProperty,c={brackets:function(e){return e+"[]"},comma:"comma",indices:function(e,u){return e+"["+u+"]"},repeat:function(e){return e}},o=Array.isArray,i=String.prototype.split,f=Array.prototype.push,l=function(e,u){f.apply(e,o(u)?u:[u])},s=Date.prototype.toISOString,p=r.default,m={addQueryPrefix:!1,allowDots:!1,charset:"utf-8",charsetSentinel:!1,delimiter:"&",encode:!0,encoder:d.encode,encodeValuesOnly:!1,format:p,formatter:r.formatters[p],indices:!1,serializeDate:function(e){return s.call(e)},skipNulls:!1,strictNullHandling:!1},h={},v=function e(u,t,r,a,c,f,s,p,v,b,y,g,_,x,w,E){for(var I,S=u,A=E,k=0,j=!1;void 0!==(A=A.get(h))&&!j;){var O=A.get(u);if(k+=1,void 0!==O){if(O===k)throw new RangeError("Cyclic object value");j=!0}void 0===A.get(h)&&(k=0)}if("function"==typeof p?S=p(t,S):S instanceof Date?S=y(S):"comma"===r&&o(S)&&(S=d.maybeMap(S,(function(e){return e instanceof Date?y(e):e}))),null===S){if(c)return s&&!x?s(t,m.encoder,w,"key",g):t;S=""}if("string"==typeof(I=S)||"number"==typeof I||"boolean"==typeof I||"symbol"==typeof I||"bigint"==typeof I||d.isBuffer(S)){if(s){var N=x?t:s(t,m.encoder,w,"key",g);if("comma"===r&&x){for(var C=i.call(String(S),","),P="",T=0;T0?S.join(",")||null:void 0}];else if(o(p))M=p;else{var L=Object.keys(S);M=v?L.sort(v):L}for(var F=a&&o(S)&&1===S.length?t+"[]":t,B=0;B0?x+_:""}},503:function(e,u,t){"use strict";var n=t(466),d=t(508),r=t(510),a=n("%TypeError%"),c=n("%WeakMap%",!0),o=n("%Map%",!0),i=d("WeakMap.prototype.get",!0),f=d("WeakMap.prototype.set",!0),l=d("WeakMap.prototype.has",!0),s=d("Map.prototype.get",!0),p=d("Map.prototype.set",!0),m=d("Map.prototype.has",!0),h=function(e,u){for(var t,n=e;null!==(t=n.next);n=t)if(t.key===u)return n.next=t.next,t.next=e.next,e.next=t,t};e.exports=function(){var e,u,t,n={assert:function(e){if(!n.has(e))throw new a("Side channel does not contain "+r(e))},get:function(n){if(c&&n&&("object"==typeof n||"function"==typeof n)){if(e)return i(e,n)}else if(o){if(u)return s(u,n)}else if(t)return function(e,u){var t=h(e,u);return t&&t.value}(t,n)},has:function(n){if(c&&n&&("object"==typeof n||"function"==typeof n)){if(e)return l(e,n)}else if(o){if(u)return m(u,n)}else if(t)return function(e,u){return!!h(e,u)}(t,n);return!1},set:function(n,d){c&&n&&("object"==typeof n||"function"==typeof n)?(e||(e=new c),f(e,n,d)):o?(u||(u=new o),p(u,n,d)):(t||(t={key:{},next:null}),function(e,u,t){var n=h(e,u);n?n.value=t:e.next={key:u,next:e.next,value:t}}(t,n,d))}};return n}},504:function(e,u,t){"use strict";var n="undefined"!=typeof Symbol&&Symbol,d=t(505);e.exports=function(){return"function"==typeof n&&("function"==typeof Symbol&&("symbol"==typeof n("foo")&&("symbol"==typeof Symbol("bar")&&d())))}},505:function(e,u,t){"use strict";e.exports=function(){if("function"!=typeof Symbol||"function"!=typeof Object.getOwnPropertySymbols)return!1;if("symbol"==typeof Symbol.iterator)return!0;var e={},u=Symbol("test"),t=Object(u);if("string"==typeof u)return!1;if("[object Symbol]"!==Object.prototype.toString.call(u))return!1;if("[object Symbol]"!==Object.prototype.toString.call(t))return!1;for(u in e[u]=42,e)return!1;if("function"==typeof Object.keys&&0!==Object.keys(e).length)return!1;if("function"==typeof Object.getOwnPropertyNames&&0!==Object.getOwnPropertyNames(e).length)return!1;var n=Object.getOwnPropertySymbols(e);if(1!==n.length||n[0]!==u)return!1;if(!Object.prototype.propertyIsEnumerable.call(e,u))return!1;if("function"==typeof Object.getOwnPropertyDescriptor){var d=Object.getOwnPropertyDescriptor(e,u);if(42!==d.value||!0!==d.enumerable)return!1}return!0}},506:function(e,u,t){"use strict";var n="Function.prototype.bind called on incompatible ",d=Array.prototype.slice,r=Object.prototype.toString;e.exports=function(e){var u=this;if("function"!=typeof u||"[object Function]"!==r.call(u))throw new TypeError(n+u);for(var t,a=d.call(arguments,1),c=function(){if(this instanceof t){var n=u.apply(this,a.concat(d.call(arguments)));return Object(n)===n?n:this}return u.apply(e,a.concat(d.call(arguments)))},o=Math.max(0,u.length-a.length),i=[],f=0;f-1?d(t):t}},509:function(e,u,t){"use strict";var n=t(467),d=t(466),r=d("%Function.prototype.apply%"),a=d("%Function.prototype.call%"),c=d("%Reflect.apply%",!0)||n.call(a,r),o=d("%Object.getOwnPropertyDescriptor%",!0),i=d("%Object.defineProperty%",!0),f=d("%Math.max%");if(i)try{i({},"a",{value:1})}catch(s){i=null}e.exports=function(e){var u=c(n,a,arguments);if(o&&i){var t=o(u,"length");t.configurable&&i(u,"length",{value:1+f(0,e.length-(arguments.length-1))})}return u};var l=function(){return c(n,r,arguments)};i?i(e.exports,"apply",{value:l}):e.exports.apply=l},510:function(e,u,t){var n="function"==typeof Map&&Map.prototype,d=Object.getOwnPropertyDescriptor&&n?Object.getOwnPropertyDescriptor(Map.prototype,"size"):null,r=n&&d&&"function"==typeof d.get?d.get:null,a=n&&Map.prototype.forEach,c="function"==typeof Set&&Set.prototype,o=Object.getOwnPropertyDescriptor&&c?Object.getOwnPropertyDescriptor(Set.prototype,"size"):null,i=c&&o&&"function"==typeof o.get?o.get:null,f=c&&Set.prototype.forEach,l="function"==typeof WeakMap&&WeakMap.prototype?WeakMap.prototype.has:null,s="function"==typeof WeakSet&&WeakSet.prototype?WeakSet.prototype.has:null,p="function"==typeof WeakRef&&WeakRef.prototype?WeakRef.prototype.deref:null,m=Boolean.prototype.valueOf,h=Object.prototype.toString,v=Function.prototype.toString,b=String.prototype.match,y=String.prototype.slice,g=String.prototype.replace,_=String.prototype.toUpperCase,x=String.prototype.toLowerCase,w=RegExp.prototype.test,E=Array.prototype.concat,I=Array.prototype.join,S=Array.prototype.slice,A=Math.floor,k="function"==typeof BigInt?BigInt.prototype.valueOf:null,j=Object.getOwnPropertySymbols,O="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?Symbol.prototype.toString:null,N="function"==typeof Symbol&&"object"==typeof Symbol.iterator,C="function"==typeof Symbol&&Symbol.toStringTag&&(typeof Symbol.toStringTag===N||"symbol")?Symbol.toStringTag:null,P=Object.prototype.propertyIsEnumerable,T=("function"==typeof Reflect?Reflect.getPrototypeOf:Object.getPrototypeOf)||([].__proto__===Array.prototype?function(e){return e.__proto__}:null);function M(e,u){if(e===1/0||e===-1/0||e!=e||e&&e>-1e3&&e<1e3||w.call(/e/,u))return u;var t=/[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;if("number"==typeof e){var n=e<0?-A(-e):A(e);if(n!==e){var d=String(n),r=y.call(u,d.length+1);return g.call(d,t,"$&_")+"."+g.call(g.call(r,/([0-9]{3})/g,"$&_"),/_$/,"")}}return g.call(u,t,"$&_")}var R=t(511),L=R.custom,F=W(L)?L:null;function B(e,u,t){var n="double"===(t.quoteStyle||u)?'"':"'";return n+e+n}function D(e){return g.call(String(e),/"/g,""")}function U(e){return!("[object Array]"!==q(e)||C&&"object"==typeof e&&C in e)}function z(e){return!("[object RegExp]"!==q(e)||C&&"object"==typeof e&&C in e)}function W(e){if(N)return e&&"object"==typeof e&&e instanceof Symbol;if("symbol"==typeof e)return!0;if(!e||"object"!=typeof e||!O)return!1;try{return O.call(e),!0}catch(u){}return!1}e.exports=function e(u,t,n,d){var c=t||{};if(G(c,"quoteStyle")&&"single"!==c.quoteStyle&&"double"!==c.quoteStyle)throw new TypeError('option "quoteStyle" must be "single" or "double"');if(G(c,"maxStringLength")&&("number"==typeof c.maxStringLength?c.maxStringLength<0&&c.maxStringLength!==1/0:null!==c.maxStringLength))throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`');var o=!G(c,"customInspect")||c.customInspect;if("boolean"!=typeof o&&"symbol"!==o)throw new TypeError("option \"customInspect\", if provided, must be `true`, `false`, or `'symbol'`");if(G(c,"indent")&&null!==c.indent&&"\t"!==c.indent&&!(parseInt(c.indent,10)===c.indent&&c.indent>0))throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`');if(G(c,"numericSeparator")&&"boolean"!=typeof c.numericSeparator)throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`');var h=c.numericSeparator;if(void 0===u)return"undefined";if(null===u)return"null";if("boolean"==typeof u)return u?"true":"false";if("string"==typeof u)return function e(u,t){if(u.length>t.maxStringLength){var n=u.length-t.maxStringLength,d="... "+n+" more character"+(n>1?"s":"");return e(y.call(u,0,t.maxStringLength),t)+d}return B(g.call(g.call(u,/(['\\])/g,"\\$1"),/[\x00-\x1f]/g,K),"single",t)}(u,c);if("number"==typeof u){if(0===u)return 1/0/u>0?"0":"-0";var _=String(u);return h?M(u,_):_}if("bigint"==typeof u){var w=String(u)+"n";return h?M(u,w):w}var A=void 0===c.depth?5:c.depth;if(void 0===n&&(n=0),n>=A&&A>0&&"object"==typeof u)return U(u)?"[Array]":"[Object]";var j=function(e,u){var t;if("\t"===e.indent)t="\t";else{if(!("number"==typeof e.indent&&e.indent>0))return null;t=I.call(Array(e.indent+1)," ")}return{base:t,prev:I.call(Array(u+1),t)}}(c,n);if(void 0===d)d=[];else if(H(d,u)>=0)return"[Circular]";function L(u,t,r){if(t&&(d=S.call(d)).push(t),r){var a={depth:c.depth};return G(c,"quoteStyle")&&(a.quoteStyle=c.quoteStyle),e(u,a,n+1,d)}return e(u,c,n+1,d)}if("function"==typeof u&&!z(u)){var $=function(e){if(e.name)return e.name;var u=b.call(v.call(e),/^function\s*([\w$]+)/);if(u)return u[1];return null}(u),X=Y(u,L);return"[Function"+($?": "+$:" (anonymous)")+"]"+(X.length>0?" { "+I.call(X,", ")+" }":"")}if(W(u)){var ee=N?g.call(String(u),/^(Symbol\(.*\))_[^)]*$/,"$1"):O.call(u);return"object"!=typeof u||N?ee:V(ee)}if(function(e){if(!e||"object"!=typeof e)return!1;if("undefined"!=typeof HTMLElement&&e instanceof HTMLElement)return!0;return"string"==typeof e.nodeName&&"function"==typeof e.getAttribute}(u)){for(var ue="<"+x.call(String(u.nodeName)),te=u.attributes||[],ne=0;ne"}if(U(u)){if(0===u.length)return"[]";var de=Y(u,L);return j&&!function(e){for(var u=0;u=0)return!1;return!0}(de)?"["+Q(de,j)+"]":"[ "+I.call(de,", ")+" ]"}if(function(e){return!("[object Error]"!==q(e)||C&&"object"==typeof e&&C in e)}(u)){var re=Y(u,L);return"cause"in Error.prototype||!("cause"in u)||P.call(u,"cause")?0===re.length?"["+String(u)+"]":"{ ["+String(u)+"] "+I.call(re,", ")+" }":"{ ["+String(u)+"] "+I.call(E.call("[cause]: "+L(u.cause),re),", ")+" }"}if("object"==typeof u&&o){if(F&&"function"==typeof u[F]&&R)return R(u,{depth:A-n});if("symbol"!==o&&"function"==typeof u.inspect)return u.inspect()}if(function(e){if(!r||!e||"object"!=typeof e)return!1;try{r.call(e);try{i.call(e)}catch(ue){return!0}return e instanceof Map}catch(u){}return!1}(u)){var ae=[];return a.call(u,(function(e,t){ae.push(L(t,u,!0)+" => "+L(e,u))})),Z("Map",r.call(u),ae,j)}if(function(e){if(!i||!e||"object"!=typeof e)return!1;try{i.call(e);try{r.call(e)}catch(u){return!0}return e instanceof Set}catch(t){}return!1}(u)){var ce=[];return f.call(u,(function(e){ce.push(L(e,u))})),Z("Set",i.call(u),ce,j)}if(function(e){if(!l||!e||"object"!=typeof e)return!1;try{l.call(e,l);try{s.call(e,s)}catch(ue){return!0}return e instanceof WeakMap}catch(u){}return!1}(u))return J("WeakMap");if(function(e){if(!s||!e||"object"!=typeof e)return!1;try{s.call(e,s);try{l.call(e,l)}catch(ue){return!0}return e instanceof WeakSet}catch(u){}return!1}(u))return J("WeakSet");if(function(e){if(!p||!e||"object"!=typeof e)return!1;try{return p.call(e),!0}catch(u){}return!1}(u))return J("WeakRef");if(function(e){return!("[object Number]"!==q(e)||C&&"object"==typeof e&&C in e)}(u))return V(L(Number(u)));if(function(e){if(!e||"object"!=typeof e||!k)return!1;try{return k.call(e),!0}catch(u){}return!1}(u))return V(L(k.call(u)));if(function(e){return!("[object Boolean]"!==q(e)||C&&"object"==typeof e&&C in e)}(u))return V(m.call(u));if(function(e){return!("[object String]"!==q(e)||C&&"object"==typeof e&&C in e)}(u))return V(L(String(u)));if(!function(e){return!("[object Date]"!==q(e)||C&&"object"==typeof e&&C in e)}(u)&&!z(u)){var oe=Y(u,L),ie=T?T(u)===Object.prototype:u instanceof Object||u.constructor===Object,fe=u instanceof Object?"":"null prototype",le=!ie&&C&&Object(u)===u&&C in u?y.call(q(u),8,-1):fe?"Object":"",se=(ie||"function"!=typeof u.constructor?"":u.constructor.name?u.constructor.name+" ":"")+(le||fe?"["+I.call(E.call([],le||[],fe||[]),": ")+"] ":"");return 0===oe.length?se+"{}":j?se+"{"+Q(oe,j)+"}":se+"{ "+I.call(oe,", ")+" }"}return String(u)};var $=Object.prototype.hasOwnProperty||function(e){return e in this};function G(e,u){return $.call(e,u)}function q(e){return h.call(e)}function H(e,u){if(e.indexOf)return e.indexOf(u);for(var t=0,n=e.length;t-1?e.split(","):e},i=function(e,u,t,n){if(e){var r=t.allowDots?e.replace(/\.([^.[]+)/g,"[$1]"):e,a=/(\[[^[\]]*])/g,c=t.depth>0&&/(\[[^[\]]*])/.exec(r),i=c?r.slice(0,c.index):r,f=[];if(i){if(!t.plainObjects&&d.call(Object.prototype,i)&&!t.allowPrototypes)return;f.push(i)}for(var l=0;t.depth>0&&null!==(c=a.exec(r))&&l=0;--r){var a,c=e[r];if("[]"===c&&t.parseArrays)a=[].concat(d);else{a=t.plainObjects?Object.create(null):{};var i="["===c.charAt(0)&&"]"===c.charAt(c.length-1)?c.slice(1,-1):c,f=parseInt(i,10);t.parseArrays||""!==i?!isNaN(f)&&c!==i&&String(f)===i&&f>=0&&t.parseArrays&&f<=t.arrayLimit?(a=[])[f]=d:"__proto__"!==i&&(a[i]=d):a={0:d}}d=a}return d}(f,u,t,n)}};e.exports=function(e,u){var t=function(e){if(!e)return a;if(null!==e.decoder&&void 0!==e.decoder&&"function"!=typeof e.decoder)throw new TypeError("Decoder has to be a function.");if(void 0!==e.charset&&"utf-8"!==e.charset&&"iso-8859-1"!==e.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var u=void 0===e.charset?a.charset:e.charset;return{allowDots:void 0===e.allowDots?a.allowDots:!!e.allowDots,allowPrototypes:"boolean"==typeof e.allowPrototypes?e.allowPrototypes:a.allowPrototypes,allowSparse:"boolean"==typeof e.allowSparse?e.allowSparse:a.allowSparse,arrayLimit:"number"==typeof e.arrayLimit?e.arrayLimit:a.arrayLimit,charset:u,charsetSentinel:"boolean"==typeof e.charsetSentinel?e.charsetSentinel:a.charsetSentinel,comma:"boolean"==typeof e.comma?e.comma:a.comma,decoder:"function"==typeof e.decoder?e.decoder:a.decoder,delimiter:"string"==typeof e.delimiter||n.isRegExp(e.delimiter)?e.delimiter:a.delimiter,depth:"number"==typeof e.depth||!1===e.depth?+e.depth:a.depth,ignoreQueryPrefix:!0===e.ignoreQueryPrefix,interpretNumericEntities:"boolean"==typeof e.interpretNumericEntities?e.interpretNumericEntities:a.interpretNumericEntities,parameterLimit:"number"==typeof e.parameterLimit?e.parameterLimit:a.parameterLimit,parseArrays:!1!==e.parseArrays,plainObjects:"boolean"==typeof e.plainObjects?e.plainObjects:a.plainObjects,strictNullHandling:"boolean"==typeof e.strictNullHandling?e.strictNullHandling:a.strictNullHandling}}(u);if(""===e||null==e)return t.plainObjects?Object.create(null):{};for(var f="string"==typeof e?function(e,u){var t,i={},f=u.ignoreQueryPrefix?e.replace(/^\?/,""):e,l=u.parameterLimit===1/0?void 0:u.parameterLimit,s=f.split(u.delimiter,l),p=-1,m=u.charset;if(u.charsetSentinel)for(t=0;t-1&&(v=r(v)?[v]:v),d.call(i,h)?i[h]=n.combine(i[h],v):i[h]=v}return i}(e,t):e,l=t.plainObjects?Object.create(null):{},s=Object.keys(f),p=0;p1?arguments[1]:void 0,3);t=t?t.n:this._f;)for(n(t.v,t.k,this);t&&t.r;)t=t.p},has:function(e){return!!v(m(this,u),e)}}),s&&n(f.prototype,"size",{get:function(){return m(this,u)[h]}}),f},def:function(e,u,t){var n,d,r=v(e,u);return r?r.v=t:(e._l=r={i:d=p(u,!0),k:u,v:t,p:n=e._l,n:void 0,r:!1},e._f||(e._f=r),n&&(n.n=r),e[h]++,"F"!==d&&(e._i[d]=r)),e},getEntry:v,setStrong:function(e,u,t){i(e,u,(function(e,t){this._t=m(e,u),this._k=t,this._l=void 0}),(function(){for(var e=this._k,u=this._l;u&&u.r;)u=u.p;return this._t&&(this._l=u=u?u.n:this._t._f)?f(0,"keys"==e?u.k:"values"==e?u.v:[u.k,u.v]):(this._t=void 0,f(1))}),t?"entries":"values",!t,!0),l(u)}}},544:function(e,u,t){"use strict";var n=t(5),d=t(12),r=t(16),a=t(82),c=t(488),o=t(81),i=t(80),f=t(13),l=t(14),s=t(83),p=t(41),m=t(545);e.exports=function(e,u,t,h,v,b){var y=n[e],g=y,_=v?"set":"add",x=g&&g.prototype,w={},E=function(e){var u=x[e];r(x,e,"delete"==e||"has"==e?function(e){return!(b&&!f(e))&&u.call(this,0===e?0:e)}:"get"==e?function(e){return b&&!f(e)?void 0:u.call(this,0===e?0:e)}:"add"==e?function(e){return u.call(this,0===e?0:e),this}:function(e,t){return u.call(this,0===e?0:e,t),this})};if("function"==typeof g&&(b||x.forEach&&!l((function(){(new g).entries().next()})))){var I=new g,S=I[_](b?{}:-0,1)!=I,A=l((function(){I.has(1)})),k=s((function(e){new g(e)})),j=!b&&l((function(){for(var e=new g,u=5;u--;)e[_](u,u);return!e.has(-0)}));k||((g=u((function(u,t){i(u,g,e);var n=m(new y,u,g);return null!=t&&o(t,v,n[_],n),n}))).prototype=x,x.constructor=g),(A||j)&&(E("delete"),E("has"),v&&E("get")),(j||S)&&E(_),b&&x.clear&&delete x.clear}else g=h.getConstructor(u,e,v,_),a(g.prototype,t),c.NEED=!0;return p(g,e),w[e]=g,d(d.G+d.W+d.F*(g!=y),w),b||h.setStrong(g,e,v),g}},545:function(e,u,t){var n=t(13),d=t(546).set;e.exports=function(e,u,t){var r,a=u.constructor;return a!==t&&"function"==typeof a&&(r=a.prototype)!==t.prototype&&n(r)&&d&&d(e,r),e}},546:function(e,u,t){var n=t(13),d=t(8),r=function(e,u){if(d(e),!n(u)&&null!==u)throw TypeError(u+": can't set as prototype!")};e.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(e,u,n){try{(n=t(30)(Function.call,t(547).f(Object.prototype,"__proto__").set,2))(e,[]),u=!(e instanceof Array)}catch(d){u=!0}return function(e,t){return r(e,t),u?e.__proto__=t:n(e,t),e}}({},!1):void 0),check:r}},547:function(e,u,t){var n=t(62),d=t(57),r=t(33),a=t(87),c=t(31),o=t(86),i=Object.getOwnPropertyDescriptor;u.f=t(10)?i:function(e,u){if(e=r(e),u=a(u,!0),o)try{return i(e,u)}catch(t){}if(c(e,u))return d(!n.f.call(e,u),e[u])}},548:function(e,u,t){"use strict";var n=t(12),d=t(32),r=t(27),a=t(14),c=[].sort,o=[1,2,3];n(n.P+n.F*(a((function(){o.sort(void 0)}))||!a((function(){o.sort(null)}))||!t(549)(c)),"Array",{sort:function(e){return void 0===e?c.call(r(this)):c.call(r(this),d(e))}})},549:function(e,u,t){"use strict";var n=t(14);e.exports=function(e,u){return!!e&&n((function(){u?e.call(null,(function(){}),1):e.call(null)}))}},558:function(e,u,t){"use strict";t(486),t(79),t(487),t(548),t(29),t(22),t(21),t(85),t(439);var n=t(1),d=(t(443),t(444),t(77),t(425),t(0)),r=t.n(d),a=t(478),c=t.n(a);t(150);var o=function(e){var u=e.humanize,t=e.icon,n=e.values,d=e.currentState,a=e.setState;if(0==n.size)return null;var o=Array.from(n);return r.a.createElement(r.a.Fragment,null,o.map((function(e,n){var o="string"==typeof e&&u?c()(e):e;return r.a.createElement("label",{key:n},r.a.createElement("input",{type:"checkbox",onChange:function(u){var t=new Set(d);u.currentTarget.checked?t.add(e):t.delete(e),a(t)},checked:d.has(e)}),o&&r.a.createElement(r.a.Fragment,null,t?r.a.createElement("i",{className:"feather icon-"+t}):""," ",o))})))},i=t(500),f=t(429),l=t(427),s=(t(437),t(448)),p=t.n(s),m=t(420),h=t.n(m),v=t(501),b=t.n(v),y=t(433);t(151);function g(e){var u=e.delivery_guarantee,t=e.description,n=e.event_types,d=e.function_category,a=(e.logo_path,e.name),c=e.pathTemplate,o=e.status,i=e.title,f=e.type,s=c;s||("source"==f&&(s="/docs/reference/sources//"),"transform"==f&&(s="/docs/reference/transforms//"),"sink"==f&&(s="/docs/reference/sinks//"));var p=s.replace("",a);return r.a.createElement(l.a,{to:p,className:"qovery-component",title:t},r.a.createElement("div",{className:"qovery-component--header"},r.a.createElement("div",{className:"qovery-component--name"},i)),r.a.createElement("div",{className:"qovery-component--badges"},"beta"==o?r.a.createElement("span",{className:"badge badge--warning",title:"This component is in beta and is not recommended for production environments"},r.a.createElement("i",{className:"feather icon-alert-triangle"})):r.a.createElement("span",{className:"badge badge--primary",title:"This component has passed reliability standards that make it production ready"},r.a.createElement("i",{className:"feather icon-award"})),"best_effort"==u?r.a.createElement("span",{className:"badge badge--warning",title:"This component makes a best-effort delivery guarantee, and in rare cases can lose data"},r.a.createElement("i",{className:"feather icon-shield-off"})):r.a.createElement("span",{className:"badge badge--primary",title:"This component offers an at-least-once delivery guarantee"},r.a.createElement("i",{className:"feather icon-shield"})),n.includes("log")?r.a.createElement("span",{className:"badge badge--primary",title:"This component works with log event types"},"log"):"",n.includes("metric")?r.a.createElement("span",{className:"badge badge--primary",title:"This component works with metric event types"},"metric"):"",r.a.createElement("span",{className:"badge badge--primary"},d)))}function _(e){var u=e.components,t=e.headingLevel,d=e.pathTemplate,a=e.titles,c=u.filter((function(e){return"source"==e.type})),o=u.filter((function(e){return"transform"==e.type})),l=u.filter((function(e){return"sink"==e.type})),s="h"+(t||3);return u.length>0?r.a.createElement(r.a.Fragment,null,c.length>0?r.a.createElement(r.a.Fragment,null,a&&r.a.createElement(s,null,c.length," Sources"),r.a.createElement("div",{className:"qovery-components--grid"},c.map((function(e,u){return r.a.createElement(g,Object(n.a)({key:u,pathTemplate:d},e))})))):"",o.length>0?r.a.createElement(r.a.Fragment,null,a&&r.a.createElement(s,null,o.length," Transforms"),r.a.createElement("div",{className:"qovery-components--grid"},o.map((function(e,u){return r.a.createElement(g,Object(n.a)({key:u,pathTemplate:d},e))})))):"",l.length>0?r.a.createElement(r.a.Fragment,null,a&&r.a.createElement(s,null,l.length," Sinks"),r.a.createElement("div",{className:"qovery-components--grid"},l.map((function(e,u){return r.a.createElement(g,Object(n.a)({key:u,pathTemplate:d},e))})))):"",r.a.createElement("hr",null),r.a.createElement(f.a,{to:"https://github.com/qovery/documentation/issues/new?labels=type%3A+new+feature",target:"_blank",rightIcon:"plus-circle"},"Request a new component")):r.a.createElement(i.a,{text:"no components found"})}u.a=function(e){var u=Object(y.a)().siteConfig.customFields.metadata,t=u.sources,n=u.transforms,a=u.sinks,c=e.titles||null==e.titles,i=1==e.filterColumn,f=e.pathTemplate,s=e.location?b.a.parse(e.location.search,{ignoreQueryPrefix:!0}):{},m=[];(e.sources||null==e.sources)&&(m=m.concat(Object.values(t))),(e.transforms||null==e.transforms)&&(m=m.concat(Object.values(n))),(e.sinks||null==e.sinks)&&(m=m.concat(Object.values(a))),m=m.sort((function(e,u){return e.name>u.name?1:-1}));var v=Object(d.useState)("true"==s["at-least-once"]),g=v[0],x=v[1],w=Object(d.useState)(new Set(s["event-types"]||e.eventTypes)),E=w[0],I=w[1],S=Object(d.useState)(new Set(s.functions)),A=S[0],k=S[1],j=Object(d.useState)(new Set(s["operating-systems"])),O=j[0],N=j[1],C=Object(d.useState)("true"==s["prod-ready"]),P=C[0],T=C[1],M=Object(d.useState)(new Set(s.providers)),R=M[0],L=M[1],F=Object(d.useState)(s.search),B=F[0],D=F[1];B&&(m=m.filter((function(e){return(e.name.toLowerCase()+" "+e.type.toLowerCase()).includes(B.toLowerCase())}))),g&&(m=m.filter((function(e){return"at_least_once"==e.delivery_guarantee}))),E.size>0&&(m=m.filter((function(e){return Array.from(E).some((function(u){return e.event_types.includes(u)}))}))),A.size>0&&(m=m.filter((function(e){return A.has(e.function_category)}))),O.size>0&&(m=m.filter((function(e){return Array.from(O).every((function(u){return e.operating_systems.includes(u)}))}))),P&&(m=m.filter((function(e){return"prod-ready"==e.status}))),R.size>0&&(m=m.filter((function(e){return Array.from(R).every((function(u){return e.service_providers&&e.service_providers.includes(u)}))}))),e.exceptNames&&e.exceptNames.length>0&&(m=m.filter((function(u){return!e.exceptNames.includes(u.name)}))),e.exceptFunctions&&e.exceptFunctions.length>0&&(m=m.filter((function(u){return!e.exceptFunctions.includes(u.function_category)})));var U=E.size>0?E:new Set(p()(m).map((function(e){return e.event_types})).flatten().uniq().compact().sort().value()),z=new Set(p()(m).map((function(e){return e.operating_systems})).flatten().uniq().compact().sort().value()),W=new Set(p()(m).map((function(e){return e.service_providers})).flatten().uniq().compact().sort().value()),$=new Set(p()(m).filter((function(e){return"source"==e.type})).map((function(e){return e.function_category})).uniq().compact().sort().value()),G=new Set(p()(m).filter((function(e){return"transform"==e.type})).map((function(e){return e.function_category})).uniq().compact().sort().value()),q=new Set(p()(m).filter((function(e){return"sink"==e.type})).map((function(e){return e.function_category})).uniq().compact().sort().value());return r.a.createElement("div",{className:h()("qovery-components",{"qovery-components--cols":i})},r.a.createElement("div",{className:"filters"},r.a.createElement("div",{className:"search"},r.a.createElement("input",{className:"input--text input--lg",type:"text",onChange:function(e){return D(e.currentTarget.value)},placeholder:"\ud83d\udd0d Search..."})),r.a.createElement("div",{className:"filter"},r.a.createElement("div",{className:"filter--label"},r.a.createElement(l.a,{to:"/docs/getting-started/data-model/",title:"Learn more about Qovery's event types"},"Event types ",r.a.createElement("i",{className:"feather icon-info"}))),r.a.createElement("div",{className:"filter--choices"},r.a.createElement(o,{label:"Event Types",icon:"database",values:U,humanize:!0,currentState:E,setState:I}))),r.a.createElement("div",{className:"filter"},r.a.createElement("div",{className:"filter--label"},r.a.createElement(l.a,{to:"/docs/getting-started/whats-next/",title:"Learn more about Qovery's guarantees"},"Guarantees ",r.a.createElement("i",{className:"feather icon-info"}))),r.a.createElement("div",{className:"filter--choices"},r.a.createElement("label",{title:"Show only components that offer an at-least-once delivery guarantee."},r.a.createElement("input",{type:"checkbox",onChange:function(e){return x(e.currentTarget.checked)},checked:g}),r.a.createElement("i",{className:"feather icon-shield"})," At-least-once"),r.a.createElement("label",{title:"Show only production ready components."},r.a.createElement("input",{type:"checkbox",onChange:function(e){return T(e.currentTarget.checked)},checked:P}),r.a.createElement("i",{className:"feather icon-award"})," Prod-ready"))),$.size>0&&r.a.createElement("div",{className:"filter"},r.a.createElement("div",{className:"filter--label"},"Source Functions"),r.a.createElement("div",{className:"filter--choices"},r.a.createElement(o,{label:"Functions",icon:"settings",values:$,humanize:!0,currentState:A,setState:k}))),G.size>0&&r.a.createElement("div",{className:"filter"},r.a.createElement("div",{className:"filter--label"},"Transform Functions"),r.a.createElement("div",{className:"filter--choices"},r.a.createElement(o,{label:"Functions",icon:"settings",values:G,humanize:!0,currentState:A,setState:k}))),q.size>0&&r.a.createElement("div",{className:"filter"},r.a.createElement("div",{className:"filter--label"},"Sink Functions"),r.a.createElement("div",{className:"filter--choices"},r.a.createElement(o,{label:"Functions",icon:"settings",values:q,humanize:!0,currentState:A,setState:k}))),W.size>0&&r.a.createElement("div",{className:"filter"},r.a.createElement("div",{className:"filter--label"},"Providers"),r.a.createElement("div",{className:"filter--choices"},r.a.createElement(o,{label:"Providers",icon:"cloud",values:W,currentState:R,setState:L}))),z.size>0&&r.a.createElement("div",{className:"filter"},r.a.createElement("div",{className:"filter--label"},r.a.createElement(l.a,{to:"/docs/setup/installation/operating-systems/",title:"Learn more about Qovery's operating systems"},"Operating Systems")),r.a.createElement("div",{className:"filter--choices"},r.a.createElement(o,{label:"Operating Systems",icon:"cpu",values:z,currentState:O,setState:N})))),r.a.createElement("div",{className:"qovery-components--results"},r.a.createElement(_,{components:m,headingLevel:e.headingLevel,pathTemplate:f,titles:c})))}}}]); \ No newline at end of file +/*! For license information please see 54e7632e.c06ee927.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[99],{419:function(e,u,t){"use strict";t.r(u);var n={};t.r(n),t.d(n,"now",(function(){return g})),t.d(n,"timer",(function(){return w})),t.d(n,"timerFlush",(function(){return E})),t.d(n,"timeout",(function(){return k})),t.d(n,"interval",(function(){return j}));var d,r,a=t(0),c=t.n(a),o=t(561),i=t(445),f=t(430),l=(t(426),t(84),0),s=0,p=0,m=0,h=0,v=0,b="object"==typeof performance&&performance.now?performance:Date,y="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(e){setTimeout(e,17)};function g(){return h||(y(_),h=b.now()+v)}function _(){h=0}function x(){this._call=this._time=this._next=null}function w(e,u,t){var n=new x;return n.restart(e,u,t),n}function E(){g(),++l;for(var e,u=d;u;)(e=h-u._time)>=0&&u._call.call(null,e),u=u._next;--l}function I(){h=(m=b.now())+v,l=s=0;try{E()}finally{l=0,function(){var e,u,t=d,n=1/0;for(;t;)t._call?(n>t._time&&(n=t._time),e=t,t=t._next):(u=t._next,t._next=null,t=e?e._next=u:d=u);r=e,A(n)}(),h=0}}function S(){var e=b.now(),u=e-m;u>1e3&&(v-=u,m=e)}function A(e){l||(s&&(s=clearTimeout(s)),e-h>24?(e<1/0&&(s=setTimeout(I,e-b.now()-v)),p&&(p=clearInterval(p))):(p||(m=b.now(),p=setInterval(S,1e3)),l=1,y(I)))}x.prototype=w.prototype={constructor:x,restart:function(e,u,t){if("function"!=typeof e)throw new TypeError("callback is not a function");t=(null==t?g():+t)+(null==u?0:+u),this._next||r===this||(r?r._next=this:d=this,r=this),this._call=e,this._time=t,A()},stop:function(){this._call&&(this._call=null,this._time=1/0,A())}};var k=function(e,u,t){var n=new x;return u=null==u?0:+u,n.restart((function(t){n.stop(),e(t+u)}),u,t),n},j=function(e,u,t){var n=new x,d=u;return null==u?(n.restart(e,u,t),n):(u=+u,t=null==t?g():+t,n.restart((function r(a){a+=d,n.restart(r,d+=u,t),e(a)}),u,t),n)},O=Object.assign({},n);t(436);u.default=function(e){return Object(a.useEffect)((function(){if("undefined"!=typeof document){var e=function(e){for(var u=e.getContext("2d"),t=e.width,n=e.height,d=2*Math.PI,r=200,a=new Array(r),c=0;ct+45&&(o.x-=t+90),o.y+=o.vy,o.y<-45?o.y+=n+90:o.y>n+45&&(o.y-=n+90),o.vx+=.2*(Math.random()-.5)-.01*o.vx,o.vy+=.2*(Math.random()-.5)-.01*o.vy,u.beginPath(),u.arc(o.x,o.y,3,0,d),u.fillStyle="rgba(40,217,242,0.4)",u.fill()}for(c=0;c3600?(2025-m)/-1575:1,u.beginPath(),u.moveTo(f.x,f.y),u.lineTo(l.x,l.y),u.strokeStyle="rgba(40,217,242,0.3)",u.stroke())}u.restore()}))}(document.querySelector("canvas"));return function(){e.stop()}}}),[]),c.a.createElement(i.a,{title:"Components - Sources, Transforms, & Sinks",description:"Browse and search all of Qovery's components: sources, transforms, and sinks. Filter by event type, guarantee, function, operating system, and provider."},c.a.createElement("header",{className:"hero hero--animated-graph"},c.a.createElement("div",{className:"container container--fluid container--flush"},c.a.createElement("canvas",{width:"2000",height:"200"}),c.a.createElement("div",{className:"overlay"},c.a.createElement("h1",null,"Qovery Components"),c.a.createElement("div",{className:"hero--subtitle"},"Components allow you to collect, transform, and route data with ease. ",c.a.createElement(f.a,{to:"/docs/getting-started/concepts/"},"Learn more"),".")))),c.a.createElement("main",{className:"container"},c.a.createElement(o.a,{filterColumn:!0,headingLevel:2,location:e.location})))}},423:function(e,u,t){var n;!function(){"use strict";var t={}.hasOwnProperty;function d(){for(var e=[],u=0;u1?arguments[1]:void 0,t),o=a>2?arguments[2]:void 0,i=void 0===o?t:d(o,t);i>c;)u[c++]=e;return u}},428:function(e,u,t){var n=t(28).f,d=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in d||t(10)&&n(d,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},431:function(e,u,t){"use strict";var n=t(0),d=t.n(n),r=t(430),a=t(423),c=t.n(a);t(133);u.a=function(e){var u=e.children,t=e.className,n=e.badge,a=e.leftIcon,o=e.rightIcon,i=e.size,f=e.target,l=e.to,s=c()("jump-to","jump-to--"+i,t),p=d.a.createElement("div",{className:"jump-to--inner"},d.a.createElement("div",{className:"jump-to--inner-2"},a&&d.a.createElement("div",{className:"jump-to--left"},d.a.createElement("i",{className:"feather icon-"+a})),d.a.createElement("div",{className:"jump-to--main"},n?d.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",u),d.a.createElement("div",{className:"jump-to--right"},d.a.createElement("i",{className:"feather icon-"+(o||"chevron-right")+" arrow"}))));return f?d.a.createElement("a",{href:l,target:f,className:s},p):d.a.createElement(r.a,{to:l,className:s},p)}},442:function(e,u,t){"use strict";var n=t(8),d=t(486),r=t(55);t(56)("search",1,(function(e,u,t,a){return[function(t){var n=e(this),d=null==t?void 0:t[u];return void 0!==d?d.call(t,n):new RegExp(t)[u](String(n))},function(e){var u=a(t,e,this);if(u.done)return u.value;var c=n(e),o=String(this),i=c.lastIndex;d(i,0)||(c.lastIndex=0);var f=r(c,o);return d(c.lastIndex,i)||(c.lastIndex=i),null===f?-1:f.index}]}))},445:function(e,u,t){"use strict";t(457);var n=t(0),d=t.n(n),r=t(458),a=t(443),c=t(1),o=(t(446),t(447),t(459),t(430)),i=t(460),f=t(440),l=t.n(f),s=t(461),p=t.n(s),m=t(436),h=t(423),v=t.n(h),b=t(135),y=t.n(b),g=function(){return d.a.createElement("span",{className:v()(y.a.toggle,y.a.moon)})},_=function(){return d.a.createElement("span",{className:v()(y.a.toggle,y.a.sun)})},x=function(e){var u=Object(m.a)().isClient;return d.a.createElement(p.a,Object(c.a)({disabled:!u,icons:{checked:d.a.createElement(g,null),unchecked:d.a.createElement(_,null)}},e))};function w(){var e=Object(m.a)().siteConfig,u=(void 0===e?{}:e).customFields.metadata.latest_post,t=Date.parse(u.date),n=new Date,d=Math.abs(n-t),r=Math.ceil(d/864e5),a=null;return"undefined"!=typeof window&&(a=new Date(parseInt(window.localStorage.getItem("blogViewedAt")||"0"))),r<30&&(!a||a0&&d.a.createElement("div",{className:"row footer__links"},d.a.createElement("div",{className:"col col--5 footer__col"},d.a.createElement("div",{className:"margin-bottom--md"},d.a.createElement(l.a,{className:"navbar__logo",src:p,alt:"Qovery",width:"150",height:"auto"})),d.a.createElement("div",{className:"margin-bottom--md"},d.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),d.a.createElement("div",null,d.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},d.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",d.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},d.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",d.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},d.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",d.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},d.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),o.map((function(e,u){return d.a.createElement("div",{key:u,className:"col footer__col"},null!=e.title?d.a.createElement("h4",{className:"footer__title"},e.title):null,null!=e.items&&Array.isArray(e.items)&&e.items.length>0?d.a.createElement("ul",{className:"footer__items"},e.items.map((function(e,u){return e.html?d.a.createElement("li",{key:u,className:"footer__item",dangerouslySetInnerHTML:{__html:e.html}}):d.a.createElement("li",{key:e.href||e.to,className:"footer__item"},d.a.createElement(L,e))}))):null)}))),(f||a)&&d.a.createElement("div",{className:"text--center"},f&&f.src&&d.a.createElement("div",{className:"margin-bottom--sm"},f.href?d.a.createElement("a",{href:f.href,target:"_blank",rel:"noopener noreferrer",className:R.a.footerLogoLink},d.a.createElement(F,{alt:f.alt,url:s})):d.a.createElement(F,{alt:f.alt,url:s})),d.a.createElement("small",null,a),d.a.createElement("br",null))))},D=t(462),U=t(463),z=t(3);t(138);u.a=function(e){var u=Object(m.a)().siteConfig,t=void 0===u?{}:u,n=t.favicon,c=(t.tagline,t.title),o=t.themeConfig.image,i=t.url,f=e.children,l=e.title,s=e.noFooter,p=e.description,h=e.image,v=e.keywords,b=(e.permalink,e.version),y=l?l+" | "+c:c,g=h||o,_=i+Object(I.a)(g),x=Object(I.a)(n),w=Object(z.h)(),E=w?"https://docs.qovery.com"+(w.pathname.endsWith("/")?w.pathname:w.pathname+"/"):null;return d.a.createElement(U.a,null,d.a.createElement(D.a,null,d.a.createElement(a.a,null,d.a.createElement("html",{lang:"en"}),d.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),y&&d.a.createElement("title",null,y),y&&d.a.createElement("meta",{property:"og:title",content:y}),n&&d.a.createElement("link",{rel:"shortcut icon",href:x}),p&&d.a.createElement("meta",{name:"description",content:p}),p&&d.a.createElement("meta",{property:"og:description",content:p}),b&&d.a.createElement("meta",{name:"docsearch:version",content:b}),v&&v.length&&d.a.createElement("meta",{name:"keywords",content:v.join(",")}),g&&d.a.createElement("meta",{property:"og:image",content:_}),g&&d.a.createElement("meta",{property:"twitter:image",content:_}),g&&d.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+y}),E&&d.a.createElement("meta",{property:"og:url",content:E}),d.a.createElement("meta",{name:"twitter:card",content:"summary"}),E&&d.a.createElement("link",{rel:"canonical",href:E})),d.a.createElement(r.a,null),d.a.createElement(P,null),d.a.createElement("div",{className:"main-wrapper"},f),!s&&d.a.createElement(B,null)))}},451:function(e,u,t){(function(e,n){var d;(function(){var r="Expected a function",a="__lodash_placeholder__",c=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],o="[object Arguments]",i="[object Array]",f="[object Boolean]",l="[object Date]",s="[object Error]",p="[object Function]",m="[object GeneratorFunction]",h="[object Map]",v="[object Number]",b="[object Object]",y="[object RegExp]",g="[object Set]",_="[object String]",x="[object Symbol]",w="[object WeakMap]",E="[object ArrayBuffer]",I="[object DataView]",S="[object Float32Array]",A="[object Float64Array]",k="[object Int8Array]",j="[object Int16Array]",O="[object Int32Array]",N="[object Uint8Array]",C="[object Uint16Array]",P="[object Uint32Array]",T=/\b__p \+= '';/g,M=/\b(__p \+=) '' \+/g,R=/(__e\(.*?\)|\b__t\)) \+\n'';/g,L=/&(?:amp|lt|gt|quot|#39);/g,F=/[&<>"']/g,B=RegExp(L.source),D=RegExp(F.source),U=/<%-([\s\S]+?)%>/g,z=/<%([\s\S]+?)%>/g,W=/<%=([\s\S]+?)%>/g,$=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,G=/^\w*$/,q=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,H=/[\\^$.*+?()[\]{}|]/g,K=RegExp(H.source),V=/^\s+|\s+$/g,J=/^\s+/,Z=/\s+$/,Q=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Y=/\{\n\/\* \[wrapped with (.+)\] \*/,X=/,? & /,ee=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,ue=/\\(\\)?/g,te=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,ne=/\w*$/,de=/^[-+]0x[0-9a-f]+$/i,re=/^0b[01]+$/i,ae=/^\[object .+?Constructor\]$/,ce=/^0o[0-7]+$/i,oe=/^(?:0|[1-9]\d*)$/,ie=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,fe=/($^)/,le=/['\n\r\u2028\u2029\\]/g,se="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",pe="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",me="[\\ud800-\\udfff]",he="["+pe+"]",ve="["+se+"]",be="\\d+",ye="[\\u2700-\\u27bf]",ge="[a-z\\xdf-\\xf6\\xf8-\\xff]",_e="[^\\ud800-\\udfff"+pe+be+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",xe="\\ud83c[\\udffb-\\udfff]",we="[^\\ud800-\\udfff]",Ee="(?:\\ud83c[\\udde6-\\uddff]){2}",Ie="[\\ud800-\\udbff][\\udc00-\\udfff]",Se="[A-Z\\xc0-\\xd6\\xd8-\\xde]",Ae="(?:"+ge+"|"+_e+")",ke="(?:"+Se+"|"+_e+")",je="(?:"+ve+"|"+xe+")"+"?",Oe="[\\ufe0e\\ufe0f]?"+je+("(?:\\u200d(?:"+[we,Ee,Ie].join("|")+")[\\ufe0e\\ufe0f]?"+je+")*"),Ne="(?:"+[ye,Ee,Ie].join("|")+")"+Oe,Ce="(?:"+[we+ve+"?",ve,Ee,Ie,me].join("|")+")",Pe=RegExp("['\u2019]","g"),Te=RegExp(ve,"g"),Me=RegExp(xe+"(?="+xe+")|"+Ce+Oe,"g"),Re=RegExp([Se+"?"+ge+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?="+[he,Se,"$"].join("|")+")",ke+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?="+[he,Se+Ae,"$"].join("|")+")",Se+"?"+Ae+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?",Se+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",be,Ne].join("|"),"g"),Le=RegExp("[\\u200d\\ud800-\\udfff"+se+"\\ufe0e\\ufe0f]"),Fe=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Be=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],De=-1,Ue={};Ue[S]=Ue[A]=Ue[k]=Ue[j]=Ue[O]=Ue[N]=Ue["[object Uint8ClampedArray]"]=Ue[C]=Ue[P]=!0,Ue[o]=Ue[i]=Ue[E]=Ue[f]=Ue[I]=Ue[l]=Ue[s]=Ue[p]=Ue[h]=Ue[v]=Ue[b]=Ue[y]=Ue[g]=Ue[_]=Ue[w]=!1;var ze={};ze[o]=ze[i]=ze[E]=ze[I]=ze[f]=ze[l]=ze[S]=ze[A]=ze[k]=ze[j]=ze[O]=ze[h]=ze[v]=ze[b]=ze[y]=ze[g]=ze[_]=ze[x]=ze[N]=ze["[object Uint8ClampedArray]"]=ze[C]=ze[P]=!0,ze[s]=ze[p]=ze[w]=!1;var We={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},$e=parseFloat,Ge=parseInt,qe="object"==typeof e&&e&&e.Object===Object&&e,He="object"==typeof self&&self&&self.Object===Object&&self,Ke=qe||He||Function("return this")(),Ve=u&&!u.nodeType&&u,Je=Ve&&"object"==typeof n&&n&&!n.nodeType&&n,Ze=Je&&Je.exports===Ve,Qe=Ze&&qe.process,Ye=function(){try{var e=Je&&Je.require&&Je.require("util").types;return e||Qe&&Qe.binding&&Qe.binding("util")}catch(u){}}(),Xe=Ye&&Ye.isArrayBuffer,eu=Ye&&Ye.isDate,uu=Ye&&Ye.isMap,tu=Ye&&Ye.isRegExp,nu=Ye&&Ye.isSet,du=Ye&&Ye.isTypedArray;function ru(e,u,t){switch(t.length){case 0:return e.call(u);case 1:return e.call(u,t[0]);case 2:return e.call(u,t[0],t[1]);case 3:return e.call(u,t[0],t[1],t[2])}return e.apply(u,t)}function au(e,u,t,n){for(var d=-1,r=null==e?0:e.length;++d-1}function su(e,u,t){for(var n=-1,d=null==e?0:e.length;++n-1;);return t}function Mu(e,u){for(var t=e.length;t--&&xu(u,e[t],0)>-1;);return t}function Ru(e,u){for(var t=e.length,n=0;t--;)e[t]===u&&++n;return n}var Lu=Au({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),Fu=Au({"&":"&","<":"<",">":">",'"':""","'":"'"});function Bu(e){return"\\"+We[e]}function Du(e){return Le.test(e)}function Uu(e){var u=-1,t=Array(e.size);return e.forEach((function(e,n){t[++u]=[n,e]})),t}function zu(e,u){return function(t){return e(u(t))}}function Wu(e,u){for(var t=-1,n=e.length,d=0,r=[];++t",""":'"',"'":"'"});var Vu=function e(u){var t,n=(u=null==u?Ke:Vu.defaults(Ke.Object(),u,Vu.pick(Ke,Be))).Array,d=u.Date,se=u.Error,pe=u.Function,me=u.Math,he=u.Object,ve=u.RegExp,be=u.String,ye=u.TypeError,ge=n.prototype,_e=pe.prototype,xe=he.prototype,we=u["__core-js_shared__"],Ee=_e.toString,Ie=xe.hasOwnProperty,Se=0,Ae=(t=/[^.]+$/.exec(we&&we.keys&&we.keys.IE_PROTO||""))?"Symbol(src)_1."+t:"",ke=xe.toString,je=Ee.call(he),Oe=Ke._,Ne=ve("^"+Ee.call(Ie).replace(H,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Ce=Ze?u.Buffer:void 0,Me=u.Symbol,Le=u.Uint8Array,We=Ce?Ce.allocUnsafe:void 0,qe=zu(he.getPrototypeOf,he),He=he.create,Ve=xe.propertyIsEnumerable,Je=ge.splice,Qe=Me?Me.isConcatSpreadable:void 0,Ye=Me?Me.iterator:void 0,yu=Me?Me.toStringTag:void 0,Au=function(){try{var e=Xd(he,"defineProperty");return e({},"",{}),e}catch(u){}}(),Ju=u.clearTimeout!==Ke.clearTimeout&&u.clearTimeout,Zu=d&&d.now!==Ke.Date.now&&d.now,Qu=u.setTimeout!==Ke.setTimeout&&u.setTimeout,Yu=me.ceil,Xu=me.floor,et=he.getOwnPropertySymbols,ut=Ce?Ce.isBuffer:void 0,tt=u.isFinite,nt=ge.join,dt=zu(he.keys,he),rt=me.max,at=me.min,ct=d.now,ot=u.parseInt,it=me.random,ft=ge.reverse,lt=Xd(u,"DataView"),st=Xd(u,"Map"),pt=Xd(u,"Promise"),mt=Xd(u,"Set"),ht=Xd(u,"WeakMap"),vt=Xd(he,"create"),bt=ht&&new ht,yt={},gt=Ar(lt),_t=Ar(st),xt=Ar(pt),wt=Ar(mt),Et=Ar(ht),It=Me?Me.prototype:void 0,St=It?It.valueOf:void 0,At=It?It.toString:void 0;function kt(e){if($a(e)&&!Pa(e)&&!(e instanceof Ct)){if(e instanceof Nt)return e;if(Ie.call(e,"__wrapped__"))return kr(e)}return new Nt(e)}var jt=function(){function e(){}return function(u){if(!Wa(u))return{};if(He)return He(u);e.prototype=u;var t=new e;return e.prototype=void 0,t}}();function Ot(){}function Nt(e,u){this.__wrapped__=e,this.__actions__=[],this.__chain__=!!u,this.__index__=0,this.__values__=void 0}function Ct(e){this.__wrapped__=e,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Pt(e){var u=-1,t=null==e?0:e.length;for(this.clear();++u=u?e:u)),e}function Jt(e,u,t,n,d,r){var a,c=1&u,i=2&u,s=4&u;if(t&&(a=d?t(e,n,d,r):t(e)),void 0!==a)return a;if(!Wa(e))return e;var w=Pa(e);if(w){if(a=function(e){var u=e.length,t=new e.constructor(u);u&&"string"==typeof e[0]&&Ie.call(e,"index")&&(t.index=e.index,t.input=e.input);return t}(e),!c)return bd(e,a)}else{var T=tr(e),M=T==p||T==m;if(La(e))return ld(e,c);if(T==b||T==o||M&&!d){if(a=i||M?{}:dr(e),!c)return i?function(e,u){return yd(e,ur(e),u)}(e,function(e,u){return e&&yd(u,_c(u),e)}(a,e)):function(e,u){return yd(e,er(e),u)}(e,qt(a,e))}else{if(!ze[T])return d?e:{};a=function(e,u,t){var n=e.constructor;switch(u){case E:return sd(e);case f:case l:return new n(+e);case I:return function(e,u){var t=u?sd(e.buffer):e.buffer;return new e.constructor(t,e.byteOffset,e.byteLength)}(e,t);case S:case A:case k:case j:case O:case N:case"[object Uint8ClampedArray]":case C:case P:return pd(e,t);case h:return new n;case v:case _:return new n(e);case y:return function(e){var u=new e.constructor(e.source,ne.exec(e));return u.lastIndex=e.lastIndex,u}(e);case g:return new n;case x:return d=e,St?he(St.call(d)):{}}var d}(e,T,c)}}r||(r=new Lt);var R=r.get(e);if(R)return R;r.set(e,a),Va(e)?e.forEach((function(n){a.add(Jt(n,u,t,n,e,r))})):Ga(e)&&e.forEach((function(n,d){a.set(d,Jt(n,u,t,d,e,r))}));var L=w?void 0:(s?i?Hd:qd:i?_c:gc)(e);return cu(L||e,(function(n,d){L&&(n=e[d=n]),Wt(a,d,Jt(n,u,t,d,e,r))})),a}function Zt(e,u,t){var n=t.length;if(null==e)return!n;for(e=he(e);n--;){var d=t[n],r=u[d],a=e[d];if(void 0===a&&!(d in e)||!r(a))return!1}return!0}function Qt(e,u,t){if("function"!=typeof e)throw new ye(r);return gr((function(){e.apply(void 0,t)}),u)}function Yt(e,u,t,n){var d=-1,r=lu,a=!0,c=e.length,o=[],i=u.length;if(!c)return o;t&&(u=pu(u,Nu(t))),n?(r=su,a=!1):u.length>=200&&(r=Pu,a=!1,u=new Rt(u));e:for(;++d-1},Tt.prototype.set=function(e,u){var t=this.__data__,n=$t(t,e);return n<0?(++this.size,t.push([e,u])):t[n][1]=u,this},Mt.prototype.clear=function(){this.size=0,this.__data__={hash:new Pt,map:new(st||Tt),string:new Pt}},Mt.prototype.delete=function(e){var u=Qd(this,e).delete(e);return this.size-=u?1:0,u},Mt.prototype.get=function(e){return Qd(this,e).get(e)},Mt.prototype.has=function(e){return Qd(this,e).has(e)},Mt.prototype.set=function(e,u){var t=Qd(this,e),n=t.size;return t.set(e,u),this.size+=t.size==n?0:1,this},Rt.prototype.add=Rt.prototype.push=function(e){return this.__data__.set(e,"__lodash_hash_undefined__"),this},Rt.prototype.has=function(e){return this.__data__.has(e)},Lt.prototype.clear=function(){this.__data__=new Tt,this.size=0},Lt.prototype.delete=function(e){var u=this.__data__,t=u.delete(e);return this.size=u.size,t},Lt.prototype.get=function(e){return this.__data__.get(e)},Lt.prototype.has=function(e){return this.__data__.has(e)},Lt.prototype.set=function(e,u){var t=this.__data__;if(t instanceof Tt){var n=t.__data__;if(!st||n.length<199)return n.push([e,u]),this.size=++t.size,this;t=this.__data__=new Mt(n)}return t.set(e,u),this.size=t.size,this};var Xt=xd(cn),en=xd(on,!0);function un(e,u){var t=!0;return Xt(e,(function(e,n,d){return t=!!u(e,n,d)})),t}function tn(e,u,t){for(var n=-1,d=e.length;++n0&&t(c)?u>1?dn(c,u-1,t,n,d):mu(d,c):n||(d[d.length]=c)}return d}var rn=wd(),an=wd(!0);function cn(e,u){return e&&rn(e,u,gc)}function on(e,u){return e&&an(e,u,gc)}function fn(e,u){return fu(u,(function(u){return Da(e[u])}))}function ln(e,u){for(var t=0,n=(u=cd(u,e)).length;null!=e&&tu}function hn(e,u){return null!=e&&Ie.call(e,u)}function vn(e,u){return null!=e&&u in he(e)}function bn(e,u,t){for(var d=t?su:lu,r=e[0].length,a=e.length,c=a,o=n(a),i=1/0,f=[];c--;){var l=e[c];c&&u&&(l=pu(l,Nu(u))),i=at(l.length,i),o[c]=!t&&(u||r>=120&&l.length>=120)?new Rt(c&&l):void 0}l=e[0];var s=-1,p=o[0];e:for(;++s=c)return o;var i=t[n];return o*("desc"==i?-1:1)}}return e.index-u.index}(e,u,t)}))}function Tn(e,u,t){for(var n=-1,d=u.length,r={};++n-1;)c!==e&&Je.call(c,o,1),Je.call(e,o,1);return e}function Rn(e,u){for(var t=e?u.length:0,n=t-1;t--;){var d=u[t];if(t==n||d!==r){var r=d;ar(d)?Je.call(e,d,1):Xn(e,d)}}return e}function Ln(e,u){return e+Xu(it()*(u-e+1))}function Fn(e,u){var t="";if(!e||u<1||u>9007199254740991)return t;do{u%2&&(t+=e),(u=Xu(u/2))&&(e+=e)}while(u);return t}function Bn(e,u){return _r(mr(e,u,qc),e+"")}function Dn(e){return Bt(jc(e))}function Un(e,u){var t=jc(e);return Er(t,Vt(u,0,t.length))}function zn(e,u,t,n){if(!Wa(e))return e;for(var d=-1,r=(u=cd(u,e)).length,a=r-1,c=e;null!=c&&++dr?0:r+u),(t=t>r?r:t)<0&&(t+=r),r=u>t?0:t-u>>>0,u>>>=0;for(var a=n(r);++d>>1,a=e[r];null!==a&&!Za(a)&&(t?a<=u:a=200){var i=u?null:Fd(e);if(i)return $u(i);a=!1,d=Pu,o=new Rt}else o=u?[]:c;e:for(;++n=n?e:qn(e,u,t)}var fd=Ju||function(e){return Ke.clearTimeout(e)};function ld(e,u){if(u)return e.slice();var t=e.length,n=We?We(t):new e.constructor(t);return e.copy(n),n}function sd(e){var u=new e.constructor(e.byteLength);return new Le(u).set(new Le(e)),u}function pd(e,u){var t=u?sd(e.buffer):e.buffer;return new e.constructor(t,e.byteOffset,e.length)}function md(e,u){if(e!==u){var t=void 0!==e,n=null===e,d=e==e,r=Za(e),a=void 0!==u,c=null===u,o=u==u,i=Za(u);if(!c&&!i&&!r&&e>u||r&&a&&o&&!c&&!i||n&&a&&o||!t&&o||!d)return 1;if(!n&&!r&&!i&&e1?t[d-1]:void 0,a=d>2?t[2]:void 0;for(r=e.length>3&&"function"==typeof r?(d--,r):void 0,a&&cr(t[0],t[1],a)&&(r=d<3?void 0:r,d=1),u=he(u);++n-1?d[r?u[a]:a]:void 0}}function kd(e){return Gd((function(u){var t=u.length,n=t,d=Nt.prototype.thru;for(e&&u.reverse();n--;){var a=u[n];if("function"!=typeof a)throw new ye(r);if(d&&!c&&"wrapper"==Vd(a))var c=new Nt([],!0)}for(n=c?n:t;++n1&&g.reverse(),l&&ic))return!1;var i=r.get(e);if(i&&r.get(u))return i==u;var f=-1,l=!0,s=2&t?new Rt:void 0;for(r.set(e,u),r.set(u,e);++f-1&&e%1==0&&e1?"& ":"")+u[n],u=u.join(t>2?", ":" "),e.replace(Q,"{\n/* [wrapped with "+u+"] */\n")}(n,function(e,u){return cu(c,(function(t){var n="_."+t[0];u&t[1]&&!lu(e,n)&&e.push(n)})),e.sort()}(function(e){var u=e.match(Y);return u?u[1].split(X):[]}(n),t)))}function wr(e){var u=0,t=0;return function(){var n=ct(),d=16-(n-t);if(t=n,d>0){if(++u>=800)return arguments[0]}else u=0;return e.apply(void 0,arguments)}}function Er(e,u){var t=-1,n=e.length,d=n-1;for(u=void 0===u?n:u;++t1?e[u-1]:void 0;return t="function"==typeof t?(e.pop(),t):void 0,Kr(e,t)}));function ea(e){var u=kt(e);return u.__chain__=!0,u}function ua(e,u){return u(e)}var ta=Gd((function(e){var u=e.length,t=u?e[0]:0,n=this.__wrapped__,d=function(u){return Kt(u,e)};return!(u>1||this.__actions__.length)&&n instanceof Ct&&ar(t)?((n=n.slice(t,+t+(u?1:0))).__actions__.push({func:ua,args:[d],thisArg:void 0}),new Nt(n,this.__chain__).thru((function(e){return u&&!e.length&&e.push(void 0),e}))):this.thru(d)}));var na=gd((function(e,u,t){Ie.call(e,t)?++e[t]:Ht(e,t,1)}));var da=Ad(Cr),ra=Ad(Pr);function aa(e,u){return(Pa(e)?cu:Xt)(e,Zd(u,3))}function ca(e,u){return(Pa(e)?ou:en)(e,Zd(u,3))}var oa=gd((function(e,u,t){Ie.call(e,t)?e[t].push(u):Ht(e,t,[u])}));var ia=Bn((function(e,u,t){var d=-1,r="function"==typeof u,a=Ma(e)?n(e.length):[];return Xt(e,(function(e){a[++d]=r?ru(u,e,t):yn(e,u,t)})),a})),fa=gd((function(e,u,t){Ht(e,t,u)}));function la(e,u){return(Pa(e)?pu:kn)(e,Zd(u,3))}var sa=gd((function(e,u,t){e[t?0:1].push(u)}),(function(){return[[],[]]}));var pa=Bn((function(e,u){if(null==e)return[];var t=u.length;return t>1&&cr(e,u[0],u[1])?u=[]:t>2&&cr(u[0],u[1],u[2])&&(u=[u[0]]),Pn(e,dn(u,1),[])})),ma=Zu||function(){return Ke.Date.now()};function ha(e,u,t){return u=t?void 0:u,Dd(e,128,void 0,void 0,void 0,void 0,u=e&&null==u?e.length:u)}function va(e,u){var t;if("function"!=typeof u)throw new ye(r);return e=tc(e),function(){return--e>0&&(t=u.apply(this,arguments)),e<=1&&(u=void 0),t}}var ba=Bn((function(e,u,t){var n=1;if(t.length){var d=Wu(t,Jd(ba));n|=32}return Dd(e,n,u,t,d)})),ya=Bn((function(e,u,t){var n=3;if(t.length){var d=Wu(t,Jd(ya));n|=32}return Dd(u,n,e,t,d)}));function ga(e,u,t){var n,d,a,c,o,i,f=0,l=!1,s=!1,p=!0;if("function"!=typeof e)throw new ye(r);function m(u){var t=n,r=d;return n=d=void 0,f=u,c=e.apply(r,t)}function h(e){return f=e,o=gr(b,u),l?m(e):c}function v(e){var t=e-i;return void 0===i||t>=u||t<0||s&&e-f>=a}function b(){var e=ma();if(v(e))return y(e);o=gr(b,function(e){var t=u-(e-i);return s?at(t,a-(e-f)):t}(e))}function y(e){return o=void 0,p&&n?m(e):(n=d=void 0,c)}function g(){var e=ma(),t=v(e);if(n=arguments,d=this,i=e,t){if(void 0===o)return h(i);if(s)return fd(o),o=gr(b,u),m(i)}return void 0===o&&(o=gr(b,u)),c}return u=dc(u)||0,Wa(t)&&(l=!!t.leading,a=(s="maxWait"in t)?rt(dc(t.maxWait)||0,u):a,p="trailing"in t?!!t.trailing:p),g.cancel=function(){void 0!==o&&fd(o),f=0,n=i=d=o=void 0},g.flush=function(){return void 0===o?c:y(ma())},g}var _a=Bn((function(e,u){return Qt(e,1,u)})),xa=Bn((function(e,u,t){return Qt(e,dc(u)||0,t)}));function wa(e,u){if("function"!=typeof e||null!=u&&"function"!=typeof u)throw new ye(r);var t=function(){var n=arguments,d=u?u.apply(this,n):n[0],r=t.cache;if(r.has(d))return r.get(d);var a=e.apply(this,n);return t.cache=r.set(d,a)||r,a};return t.cache=new(wa.Cache||Mt),t}function Ea(e){if("function"!=typeof e)throw new ye(r);return function(){var u=arguments;switch(u.length){case 0:return!e.call(this);case 1:return!e.call(this,u[0]);case 2:return!e.call(this,u[0],u[1]);case 3:return!e.call(this,u[0],u[1],u[2])}return!e.apply(this,u)}}wa.Cache=Mt;var Ia=od((function(e,u){var t=(u=1==u.length&&Pa(u[0])?pu(u[0],Nu(Zd())):pu(dn(u,1),Nu(Zd()))).length;return Bn((function(n){for(var d=-1,r=at(n.length,t);++d=u})),Ca=gn(function(){return arguments}())?gn:function(e){return $a(e)&&Ie.call(e,"callee")&&!Ve.call(e,"callee")},Pa=n.isArray,Ta=Xe?Nu(Xe):function(e){return $a(e)&&pn(e)==E};function Ma(e){return null!=e&&za(e.length)&&!Da(e)}function Ra(e){return $a(e)&&Ma(e)}var La=ut||ro,Fa=eu?Nu(eu):function(e){return $a(e)&&pn(e)==l};function Ba(e){if(!$a(e))return!1;var u=pn(e);return u==s||"[object DOMException]"==u||"string"==typeof e.message&&"string"==typeof e.name&&!Ha(e)}function Da(e){if(!Wa(e))return!1;var u=pn(e);return u==p||u==m||"[object AsyncFunction]"==u||"[object Proxy]"==u}function Ua(e){return"number"==typeof e&&e==tc(e)}function za(e){return"number"==typeof e&&e>-1&&e%1==0&&e<=9007199254740991}function Wa(e){var u=typeof e;return null!=e&&("object"==u||"function"==u)}function $a(e){return null!=e&&"object"==typeof e}var Ga=uu?Nu(uu):function(e){return $a(e)&&tr(e)==h};function qa(e){return"number"==typeof e||$a(e)&&pn(e)==v}function Ha(e){if(!$a(e)||pn(e)!=b)return!1;var u=qe(e);if(null===u)return!0;var t=Ie.call(u,"constructor")&&u.constructor;return"function"==typeof t&&t instanceof t&&Ee.call(t)==je}var Ka=tu?Nu(tu):function(e){return $a(e)&&pn(e)==y};var Va=nu?Nu(nu):function(e){return $a(e)&&tr(e)==g};function Ja(e){return"string"==typeof e||!Pa(e)&&$a(e)&&pn(e)==_}function Za(e){return"symbol"==typeof e||$a(e)&&pn(e)==x}var Qa=du?Nu(du):function(e){return $a(e)&&za(e.length)&&!!Ue[pn(e)]};var Ya=Md(An),Xa=Md((function(e,u){return e<=u}));function ec(e){if(!e)return[];if(Ma(e))return Ja(e)?Hu(e):bd(e);if(Ye&&e[Ye])return function(e){for(var u,t=[];!(u=e.next()).done;)t.push(u.value);return t}(e[Ye]());var u=tr(e);return(u==h?Uu:u==g?$u:jc)(e)}function uc(e){return e?(e=dc(e))===1/0||e===-1/0?17976931348623157e292*(e<0?-1:1):e==e?e:0:0===e?e:0}function tc(e){var u=uc(e),t=u%1;return u==u?t?u-t:u:0}function nc(e){return e?Vt(tc(e),0,4294967295):0}function dc(e){if("number"==typeof e)return e;if(Za(e))return NaN;if(Wa(e)){var u="function"==typeof e.valueOf?e.valueOf():e;e=Wa(u)?u+"":u}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(V,"");var t=re.test(e);return t||ce.test(e)?Ge(e.slice(2),t?2:8):de.test(e)?NaN:+e}function rc(e){return yd(e,_c(e))}function ac(e){return null==e?"":Qn(e)}var cc=_d((function(e,u){if(lr(u)||Ma(u))yd(u,gc(u),e);else for(var t in u)Ie.call(u,t)&&Wt(e,t,u[t])})),oc=_d((function(e,u){yd(u,_c(u),e)})),ic=_d((function(e,u,t,n){yd(u,_c(u),e,n)})),fc=_d((function(e,u,t,n){yd(u,gc(u),e,n)})),lc=Gd(Kt);var sc=Bn((function(e,u){e=he(e);var t=-1,n=u.length,d=n>2?u[2]:void 0;for(d&&cr(u[0],u[1],d)&&(n=1);++t1),u})),yd(e,Hd(e),t),n&&(t=Jt(t,7,Wd));for(var d=u.length;d--;)Xn(t,u[d]);return t}));var Ic=Gd((function(e,u){return null==e?{}:function(e,u){return Tn(e,u,(function(u,t){return hc(e,t)}))}(e,u)}));function Sc(e,u){if(null==e)return{};var t=pu(Hd(e),(function(e){return[e]}));return u=Zd(u),Tn(e,t,(function(e,t){return u(e,t[0])}))}var Ac=Bd(gc),kc=Bd(_c);function jc(e){return null==e?[]:Cu(e,gc(e))}var Oc=Id((function(e,u,t){return u=u.toLowerCase(),e+(t?Nc(u):u)}));function Nc(e){return Bc(ac(e).toLowerCase())}function Cc(e){return(e=ac(e))&&e.replace(ie,Lu).replace(Te,"")}var Pc=Id((function(e,u,t){return e+(t?"-":"")+u.toLowerCase()})),Tc=Id((function(e,u,t){return e+(t?" ":"")+u.toLowerCase()})),Mc=Ed("toLowerCase");var Rc=Id((function(e,u,t){return e+(t?"_":"")+u.toLowerCase()}));var Lc=Id((function(e,u,t){return e+(t?" ":"")+Bc(u)}));var Fc=Id((function(e,u,t){return e+(t?" ":"")+u.toUpperCase()})),Bc=Ed("toUpperCase");function Dc(e,u,t){return e=ac(e),void 0===(u=t?void 0:u)?function(e){return Fe.test(e)}(e)?function(e){return e.match(Re)||[]}(e):function(e){return e.match(ee)||[]}(e):e.match(u)||[]}var Uc=Bn((function(e,u){try{return ru(e,void 0,u)}catch(t){return Ba(t)?t:new se(t)}})),zc=Gd((function(e,u){return cu(u,(function(u){u=Sr(u),Ht(e,u,ba(e[u],e))})),e}));function Wc(e){return function(){return e}}var $c=kd(),Gc=kd(!0);function qc(e){return e}function Hc(e){return En("function"==typeof e?e:Jt(e,1))}var Kc=Bn((function(e,u){return function(t){return yn(t,e,u)}})),Vc=Bn((function(e,u){return function(t){return yn(e,t,u)}}));function Jc(e,u,t){var n=gc(u),d=fn(u,n);null!=t||Wa(u)&&(d.length||!n.length)||(t=u,u=e,e=this,d=fn(u,gc(u)));var r=!(Wa(t)&&"chain"in t&&!t.chain),a=Da(e);return cu(d,(function(t){var n=u[t];e[t]=n,a&&(e.prototype[t]=function(){var u=this.__chain__;if(r||u){var t=e(this.__wrapped__),d=t.__actions__=bd(this.__actions__);return d.push({func:n,args:arguments,thisArg:e}),t.__chain__=u,t}return n.apply(e,mu([this.value()],arguments))})})),e}function Zc(){}var Qc=Cd(pu),Yc=Cd(iu),Xc=Cd(bu);function eo(e){return or(e)?Su(Sr(e)):function(e){return function(u){return ln(u,e)}}(e)}var uo=Td(),to=Td(!0);function no(){return[]}function ro(){return!1}var ao=Nd((function(e,u){return e+u}),0),co=Ld("ceil"),oo=Nd((function(e,u){return e/u}),1),io=Ld("floor");var fo,lo=Nd((function(e,u){return e*u}),1),so=Ld("round"),po=Nd((function(e,u){return e-u}),0);return kt.after=function(e,u){if("function"!=typeof u)throw new ye(r);return e=tc(e),function(){if(--e<1)return u.apply(this,arguments)}},kt.ary=ha,kt.assign=cc,kt.assignIn=oc,kt.assignInWith=ic,kt.assignWith=fc,kt.at=lc,kt.before=va,kt.bind=ba,kt.bindAll=zc,kt.bindKey=ya,kt.castArray=function(){if(!arguments.length)return[];var e=arguments[0];return Pa(e)?e:[e]},kt.chain=ea,kt.chunk=function(e,u,t){u=(t?cr(e,u,t):void 0===u)?1:rt(tc(u),0);var d=null==e?0:e.length;if(!d||u<1)return[];for(var r=0,a=0,c=n(Yu(d/u));rd?0:d+t),(n=void 0===n||n>d?d:tc(n))<0&&(n+=d),n=t>n?0:nc(n);t>>0)?(e=ac(e))&&("string"==typeof u||null!=u&&!Ka(u))&&!(u=Qn(u))&&Du(e)?id(Hu(e),0,t):e.split(u,t):[]},kt.spread=function(e,u){if("function"!=typeof e)throw new ye(r);return u=null==u?0:rt(tc(u),0),Bn((function(t){var n=t[u],d=id(t,0,u);return n&&mu(d,n),ru(e,this,d)}))},kt.tail=function(e){var u=null==e?0:e.length;return u?qn(e,1,u):[]},kt.take=function(e,u,t){return e&&e.length?qn(e,0,(u=t||void 0===u?1:tc(u))<0?0:u):[]},kt.takeRight=function(e,u,t){var n=null==e?0:e.length;return n?qn(e,(u=n-(u=t||void 0===u?1:tc(u)))<0?0:u,n):[]},kt.takeRightWhile=function(e,u){return e&&e.length?ud(e,Zd(u,3),!1,!0):[]},kt.takeWhile=function(e,u){return e&&e.length?ud(e,Zd(u,3)):[]},kt.tap=function(e,u){return u(e),e},kt.throttle=function(e,u,t){var n=!0,d=!0;if("function"!=typeof e)throw new ye(r);return Wa(t)&&(n="leading"in t?!!t.leading:n,d="trailing"in t?!!t.trailing:d),ga(e,u,{leading:n,maxWait:u,trailing:d})},kt.thru=ua,kt.toArray=ec,kt.toPairs=Ac,kt.toPairsIn=kc,kt.toPath=function(e){return Pa(e)?pu(e,Sr):Za(e)?[e]:bd(Ir(ac(e)))},kt.toPlainObject=rc,kt.transform=function(e,u,t){var n=Pa(e),d=n||La(e)||Qa(e);if(u=Zd(u,4),null==t){var r=e&&e.constructor;t=d?n?new r:[]:Wa(e)&&Da(r)?jt(qe(e)):{}}return(d?cu:cn)(e,(function(e,n,d){return u(t,e,n,d)})),t},kt.unary=function(e){return ha(e,1)},kt.union=$r,kt.unionBy=Gr,kt.unionWith=qr,kt.uniq=function(e){return e&&e.length?Yn(e):[]},kt.uniqBy=function(e,u){return e&&e.length?Yn(e,Zd(u,2)):[]},kt.uniqWith=function(e,u){return u="function"==typeof u?u:void 0,e&&e.length?Yn(e,void 0,u):[]},kt.unset=function(e,u){return null==e||Xn(e,u)},kt.unzip=Hr,kt.unzipWith=Kr,kt.update=function(e,u,t){return null==e?e:ed(e,u,ad(t))},kt.updateWith=function(e,u,t,n){return n="function"==typeof n?n:void 0,null==e?e:ed(e,u,ad(t),n)},kt.values=jc,kt.valuesIn=function(e){return null==e?[]:Cu(e,_c(e))},kt.without=Vr,kt.words=Dc,kt.wrap=function(e,u){return Sa(ad(u),e)},kt.xor=Jr,kt.xorBy=Zr,kt.xorWith=Qr,kt.zip=Yr,kt.zipObject=function(e,u){return dd(e||[],u||[],Wt)},kt.zipObjectDeep=function(e,u){return dd(e||[],u||[],zn)},kt.zipWith=Xr,kt.entries=Ac,kt.entriesIn=kc,kt.extend=oc,kt.extendWith=ic,Jc(kt,kt),kt.add=ao,kt.attempt=Uc,kt.camelCase=Oc,kt.capitalize=Nc,kt.ceil=co,kt.clamp=function(e,u,t){return void 0===t&&(t=u,u=void 0),void 0!==t&&(t=(t=dc(t))==t?t:0),void 0!==u&&(u=(u=dc(u))==u?u:0),Vt(dc(e),u,t)},kt.clone=function(e){return Jt(e,4)},kt.cloneDeep=function(e){return Jt(e,5)},kt.cloneDeepWith=function(e,u){return Jt(e,5,u="function"==typeof u?u:void 0)},kt.cloneWith=function(e,u){return Jt(e,4,u="function"==typeof u?u:void 0)},kt.conformsTo=function(e,u){return null==u||Zt(e,u,gc(u))},kt.deburr=Cc,kt.defaultTo=function(e,u){return null==e||e!=e?u:e},kt.divide=oo,kt.endsWith=function(e,u,t){e=ac(e),u=Qn(u);var n=e.length,d=t=void 0===t?n:Vt(tc(t),0,n);return(t-=u.length)>=0&&e.slice(t,d)==u},kt.eq=ja,kt.escape=function(e){return(e=ac(e))&&D.test(e)?e.replace(F,Fu):e},kt.escapeRegExp=function(e){return(e=ac(e))&&K.test(e)?e.replace(H,"\\$&"):e},kt.every=function(e,u,t){var n=Pa(e)?iu:un;return t&&cr(e,u,t)&&(u=void 0),n(e,Zd(u,3))},kt.find=da,kt.findIndex=Cr,kt.findKey=function(e,u){return gu(e,Zd(u,3),cn)},kt.findLast=ra,kt.findLastIndex=Pr,kt.findLastKey=function(e,u){return gu(e,Zd(u,3),on)},kt.floor=io,kt.forEach=aa,kt.forEachRight=ca,kt.forIn=function(e,u){return null==e?e:rn(e,Zd(u,3),_c)},kt.forInRight=function(e,u){return null==e?e:an(e,Zd(u,3),_c)},kt.forOwn=function(e,u){return e&&cn(e,Zd(u,3))},kt.forOwnRight=function(e,u){return e&&on(e,Zd(u,3))},kt.get=mc,kt.gt=Oa,kt.gte=Na,kt.has=function(e,u){return null!=e&&nr(e,u,hn)},kt.hasIn=hc,kt.head=Mr,kt.identity=qc,kt.includes=function(e,u,t,n){e=Ma(e)?e:jc(e),t=t&&!n?tc(t):0;var d=e.length;return t<0&&(t=rt(d+t,0)),Ja(e)?t<=d&&e.indexOf(u,t)>-1:!!d&&xu(e,u,t)>-1},kt.indexOf=function(e,u,t){var n=null==e?0:e.length;if(!n)return-1;var d=null==t?0:tc(t);return d<0&&(d=rt(n+d,0)),xu(e,u,d)},kt.inRange=function(e,u,t){return u=uc(u),void 0===t?(t=u,u=0):t=uc(t),function(e,u,t){return e>=at(u,t)&&e=-9007199254740991&&e<=9007199254740991},kt.isSet=Va,kt.isString=Ja,kt.isSymbol=Za,kt.isTypedArray=Qa,kt.isUndefined=function(e){return void 0===e},kt.isWeakMap=function(e){return $a(e)&&tr(e)==w},kt.isWeakSet=function(e){return $a(e)&&"[object WeakSet]"==pn(e)},kt.join=function(e,u){return null==e?"":nt.call(e,u)},kt.kebabCase=Pc,kt.last=Br,kt.lastIndexOf=function(e,u,t){var n=null==e?0:e.length;if(!n)return-1;var d=n;return void 0!==t&&(d=(d=tc(t))<0?rt(n+d,0):at(d,n-1)),u==u?function(e,u,t){for(var n=t+1;n--;)if(e[n]===u)return n;return n}(e,u,d):_u(e,Eu,d,!0)},kt.lowerCase=Tc,kt.lowerFirst=Mc,kt.lt=Ya,kt.lte=Xa,kt.max=function(e){return e&&e.length?tn(e,qc,mn):void 0},kt.maxBy=function(e,u){return e&&e.length?tn(e,Zd(u,2),mn):void 0},kt.mean=function(e){return Iu(e,qc)},kt.meanBy=function(e,u){return Iu(e,Zd(u,2))},kt.min=function(e){return e&&e.length?tn(e,qc,An):void 0},kt.minBy=function(e,u){return e&&e.length?tn(e,Zd(u,2),An):void 0},kt.stubArray=no,kt.stubFalse=ro,kt.stubObject=function(){return{}},kt.stubString=function(){return""},kt.stubTrue=function(){return!0},kt.multiply=lo,kt.nth=function(e,u){return e&&e.length?Cn(e,tc(u)):void 0},kt.noConflict=function(){return Ke._===this&&(Ke._=Oe),this},kt.noop=Zc,kt.now=ma,kt.pad=function(e,u,t){e=ac(e);var n=(u=tc(u))?qu(e):0;if(!u||n>=u)return e;var d=(u-n)/2;return Pd(Xu(d),t)+e+Pd(Yu(d),t)},kt.padEnd=function(e,u,t){e=ac(e);var n=(u=tc(u))?qu(e):0;return u&&nu){var n=e;e=u,u=n}if(t||e%1||u%1){var d=it();return at(e+d*(u-e+$e("1e-"+((d+"").length-1))),u)}return Ln(e,u)},kt.reduce=function(e,u,t){var n=Pa(e)?hu:ku,d=arguments.length<3;return n(e,Zd(u,4),t,d,Xt)},kt.reduceRight=function(e,u,t){var n=Pa(e)?vu:ku,d=arguments.length<3;return n(e,Zd(u,4),t,d,en)},kt.repeat=function(e,u,t){return u=(t?cr(e,u,t):void 0===u)?1:tc(u),Fn(ac(e),u)},kt.replace=function(){var e=arguments,u=ac(e[0]);return e.length<3?u:u.replace(e[1],e[2])},kt.result=function(e,u,t){var n=-1,d=(u=cd(u,e)).length;for(d||(d=1,e=void 0);++n9007199254740991)return[];var t=4294967295,n=at(e,4294967295);e-=4294967295;for(var d=Ou(n,u=Zd(u));++t=r)return e;var c=t-qu(n);if(c<1)return n;var o=a?id(a,0,c).join(""):e.slice(0,c);if(void 0===d)return o+n;if(a&&(c+=o.length-c),Ka(d)){if(e.slice(c).search(d)){var i,f=o;for(d.global||(d=ve(d.source,ac(ne.exec(d))+"g")),d.lastIndex=0;i=d.exec(f);)var l=i.index;o=o.slice(0,void 0===l?c:l)}}else if(e.indexOf(Qn(d),c)!=c){var s=o.lastIndexOf(d);s>-1&&(o=o.slice(0,s))}return o+n},kt.unescape=function(e){return(e=ac(e))&&B.test(e)?e.replace(L,Ku):e},kt.uniqueId=function(e){var u=++Se;return ac(e)+u},kt.upperCase=Fc,kt.upperFirst=Bc,kt.each=aa,kt.eachRight=ca,kt.first=Mr,Jc(kt,(fo={},cn(kt,(function(e,u){Ie.call(kt.prototype,u)||(fo[u]=e)})),fo),{chain:!1}),kt.VERSION="4.17.15",cu(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(e){kt[e].placeholder=kt})),cu(["drop","take"],(function(e,u){Ct.prototype[e]=function(t){t=void 0===t?1:rt(tc(t),0);var n=this.__filtered__&&!u?new Ct(this):this.clone();return n.__filtered__?n.__takeCount__=at(t,n.__takeCount__):n.__views__.push({size:at(t,4294967295),type:e+(n.__dir__<0?"Right":"")}),n},Ct.prototype[e+"Right"]=function(u){return this.reverse()[e](u).reverse()}})),cu(["filter","map","takeWhile"],(function(e,u){var t=u+1,n=1==t||3==t;Ct.prototype[e]=function(e){var u=this.clone();return u.__iteratees__.push({iteratee:Zd(e,3),type:t}),u.__filtered__=u.__filtered__||n,u}})),cu(["head","last"],(function(e,u){var t="take"+(u?"Right":"");Ct.prototype[e]=function(){return this[t](1).value()[0]}})),cu(["initial","tail"],(function(e,u){var t="drop"+(u?"":"Right");Ct.prototype[e]=function(){return this.__filtered__?new Ct(this):this[t](1)}})),Ct.prototype.compact=function(){return this.filter(qc)},Ct.prototype.find=function(e){return this.filter(e).head()},Ct.prototype.findLast=function(e){return this.reverse().find(e)},Ct.prototype.invokeMap=Bn((function(e,u){return"function"==typeof e?new Ct(this):this.map((function(t){return yn(t,e,u)}))})),Ct.prototype.reject=function(e){return this.filter(Ea(Zd(e)))},Ct.prototype.slice=function(e,u){e=tc(e);var t=this;return t.__filtered__&&(e>0||u<0)?new Ct(t):(e<0?t=t.takeRight(-e):e&&(t=t.drop(e)),void 0!==u&&(t=(u=tc(u))<0?t.dropRight(-u):t.take(u-e)),t)},Ct.prototype.takeRightWhile=function(e){return this.reverse().takeWhile(e).reverse()},Ct.prototype.toArray=function(){return this.take(4294967295)},cn(Ct.prototype,(function(e,u){var t=/^(?:filter|find|map|reject)|While$/.test(u),n=/^(?:head|last)$/.test(u),d=kt[n?"take"+("last"==u?"Right":""):u],r=n||/^find/.test(u);d&&(kt.prototype[u]=function(){var u=this.__wrapped__,a=n?[1]:arguments,c=u instanceof Ct,o=a[0],i=c||Pa(u),f=function(e){var u=d.apply(kt,mu([e],a));return n&&l?u[0]:u};i&&t&&"function"==typeof o&&1!=o.length&&(c=i=!1);var l=this.__chain__,s=!!this.__actions__.length,p=r&&!l,m=c&&!s;if(!r&&i){u=m?u:new Ct(this);var h=e.apply(u,a);return h.__actions__.push({func:ua,args:[f],thisArg:void 0}),new Nt(h,l)}return p&&m?e.apply(this,a):(h=this.thru(f),p?n?h.value()[0]:h.value():h)})})),cu(["pop","push","shift","sort","splice","unshift"],(function(e){var u=ge[e],t=/^(?:push|sort|unshift)$/.test(e)?"tap":"thru",n=/^(?:pop|shift)$/.test(e);kt.prototype[e]=function(){var e=arguments;if(n&&!this.__chain__){var d=this.value();return u.apply(Pa(d)?d:[],e)}return this[t]((function(t){return u.apply(Pa(t)?t:[],e)}))}})),cn(Ct.prototype,(function(e,u){var t=kt[u];if(t){var n=t.name+"";Ie.call(yt,n)||(yt[n]=[]),yt[n].push({name:u,func:t})}})),yt[jd(void 0,2).name]=[{name:"wrapper",func:void 0}],Ct.prototype.clone=function(){var e=new Ct(this.__wrapped__);return e.__actions__=bd(this.__actions__),e.__dir__=this.__dir__,e.__filtered__=this.__filtered__,e.__iteratees__=bd(this.__iteratees__),e.__takeCount__=this.__takeCount__,e.__views__=bd(this.__views__),e},Ct.prototype.reverse=function(){if(this.__filtered__){var e=new Ct(this);e.__dir__=-1,e.__filtered__=!0}else(e=this.clone()).__dir__*=-1;return e},Ct.prototype.value=function(){var e=this.__wrapped__.value(),u=this.__dir__,t=Pa(e),n=u<0,d=t?e.length:0,r=function(e,u,t){var n=-1,d=t.length;for(;++n=this.__values__.length;return{done:e,value:e?void 0:this.__values__[this.__index__++]}},kt.prototype.plant=function(e){for(var u,t=this;t instanceof Ot;){var n=kr(t);n.__index__=0,n.__values__=void 0,u?d.__wrapped__=n:u=n;var d=n;t=t.__wrapped__}return d.__wrapped__=e,u},kt.prototype.reverse=function(){var e=this.__wrapped__;if(e instanceof Ct){var u=e;return this.__actions__.length&&(u=new Ct(this)),(u=u.reverse()).__actions__.push({func:ua,args:[Wr],thisArg:void 0}),new Nt(u,this.__chain__)}return this.thru(Wr)},kt.prototype.toJSON=kt.prototype.valueOf=kt.prototype.value=function(){return td(this.__wrapped__,this.__actions__)},kt.prototype.first=kt.prototype.head,Ye&&(kt.prototype[Ye]=function(){return this}),kt}();Ke._=Vu,void 0===(d=function(){return Vu}.call(u,t,u,n))||(n.exports=d)}).call(this)}).call(this,t(76),t(456)(e))},454:function(e,u,t){"use strict";var n=t(0),d=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});u.a=d},456:function(e,u){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),e.webpackPolyfill=1),e}},469:function(e,u,t){"use strict";var n=SyntaxError,d=Function,r=TypeError,a=function(e){try{return d('"use strict"; return ('+e+").constructor;")()}catch(u){}},c=Object.getOwnPropertyDescriptor;if(c)try{c({},"")}catch(k){c=null}var o=function(){throw new r},i=c?function(){try{return o}catch(e){try{return c(arguments,"callee").get}catch(u){return o}}}():o,f=t(507)(),l=Object.getPrototypeOf||function(e){return e.__proto__},s={},p="undefined"==typeof Uint8Array?void 0:l(Uint8Array),m={"%AggregateError%":"undefined"==typeof AggregateError?void 0:AggregateError,"%Array%":Array,"%ArrayBuffer%":"undefined"==typeof ArrayBuffer?void 0:ArrayBuffer,"%ArrayIteratorPrototype%":f?l([][Symbol.iterator]()):void 0,"%AsyncFromSyncIteratorPrototype%":void 0,"%AsyncFunction%":s,"%AsyncGenerator%":s,"%AsyncGeneratorFunction%":s,"%AsyncIteratorPrototype%":s,"%Atomics%":"undefined"==typeof Atomics?void 0:Atomics,"%BigInt%":"undefined"==typeof BigInt?void 0:BigInt,"%Boolean%":Boolean,"%DataView%":"undefined"==typeof DataView?void 0:DataView,"%Date%":Date,"%decodeURI%":decodeURI,"%decodeURIComponent%":decodeURIComponent,"%encodeURI%":encodeURI,"%encodeURIComponent%":encodeURIComponent,"%Error%":Error,"%eval%":eval,"%EvalError%":EvalError,"%Float32Array%":"undefined"==typeof Float32Array?void 0:Float32Array,"%Float64Array%":"undefined"==typeof Float64Array?void 0:Float64Array,"%FinalizationRegistry%":"undefined"==typeof FinalizationRegistry?void 0:FinalizationRegistry,"%Function%":d,"%GeneratorFunction%":s,"%Int8Array%":"undefined"==typeof Int8Array?void 0:Int8Array,"%Int16Array%":"undefined"==typeof Int16Array?void 0:Int16Array,"%Int32Array%":"undefined"==typeof Int32Array?void 0:Int32Array,"%isFinite%":isFinite,"%isNaN%":isNaN,"%IteratorPrototype%":f?l(l([][Symbol.iterator]())):void 0,"%JSON%":"object"==typeof JSON?JSON:void 0,"%Map%":"undefined"==typeof Map?void 0:Map,"%MapIteratorPrototype%":"undefined"!=typeof Map&&f?l((new Map)[Symbol.iterator]()):void 0,"%Math%":Math,"%Number%":Number,"%Object%":Object,"%parseFloat%":parseFloat,"%parseInt%":parseInt,"%Promise%":"undefined"==typeof Promise?void 0:Promise,"%Proxy%":"undefined"==typeof Proxy?void 0:Proxy,"%RangeError%":RangeError,"%ReferenceError%":ReferenceError,"%Reflect%":"undefined"==typeof Reflect?void 0:Reflect,"%RegExp%":RegExp,"%Set%":"undefined"==typeof Set?void 0:Set,"%SetIteratorPrototype%":"undefined"!=typeof Set&&f?l((new Set)[Symbol.iterator]()):void 0,"%SharedArrayBuffer%":"undefined"==typeof SharedArrayBuffer?void 0:SharedArrayBuffer,"%String%":String,"%StringIteratorPrototype%":f?l(""[Symbol.iterator]()):void 0,"%Symbol%":f?Symbol:void 0,"%SyntaxError%":n,"%ThrowTypeError%":i,"%TypedArray%":p,"%TypeError%":r,"%Uint8Array%":"undefined"==typeof Uint8Array?void 0:Uint8Array,"%Uint8ClampedArray%":"undefined"==typeof Uint8ClampedArray?void 0:Uint8ClampedArray,"%Uint16Array%":"undefined"==typeof Uint16Array?void 0:Uint16Array,"%Uint32Array%":"undefined"==typeof Uint32Array?void 0:Uint32Array,"%URIError%":URIError,"%WeakMap%":"undefined"==typeof WeakMap?void 0:WeakMap,"%WeakRef%":"undefined"==typeof WeakRef?void 0:WeakRef,"%WeakSet%":"undefined"==typeof WeakSet?void 0:WeakSet},h={"%ArrayBufferPrototype%":["ArrayBuffer","prototype"],"%ArrayPrototype%":["Array","prototype"],"%ArrayProto_entries%":["Array","prototype","entries"],"%ArrayProto_forEach%":["Array","prototype","forEach"],"%ArrayProto_keys%":["Array","prototype","keys"],"%ArrayProto_values%":["Array","prototype","values"],"%AsyncFunctionPrototype%":["AsyncFunction","prototype"],"%AsyncGenerator%":["AsyncGeneratorFunction","prototype"],"%AsyncGeneratorPrototype%":["AsyncGeneratorFunction","prototype","prototype"],"%BooleanPrototype%":["Boolean","prototype"],"%DataViewPrototype%":["DataView","prototype"],"%DatePrototype%":["Date","prototype"],"%ErrorPrototype%":["Error","prototype"],"%EvalErrorPrototype%":["EvalError","prototype"],"%Float32ArrayPrototype%":["Float32Array","prototype"],"%Float64ArrayPrototype%":["Float64Array","prototype"],"%FunctionPrototype%":["Function","prototype"],"%Generator%":["GeneratorFunction","prototype"],"%GeneratorPrototype%":["GeneratorFunction","prototype","prototype"],"%Int8ArrayPrototype%":["Int8Array","prototype"],"%Int16ArrayPrototype%":["Int16Array","prototype"],"%Int32ArrayPrototype%":["Int32Array","prototype"],"%JSONParse%":["JSON","parse"],"%JSONStringify%":["JSON","stringify"],"%MapPrototype%":["Map","prototype"],"%NumberPrototype%":["Number","prototype"],"%ObjectPrototype%":["Object","prototype"],"%ObjProto_toString%":["Object","prototype","toString"],"%ObjProto_valueOf%":["Object","prototype","valueOf"],"%PromisePrototype%":["Promise","prototype"],"%PromiseProto_then%":["Promise","prototype","then"],"%Promise_all%":["Promise","all"],"%Promise_reject%":["Promise","reject"],"%Promise_resolve%":["Promise","resolve"],"%RangeErrorPrototype%":["RangeError","prototype"],"%ReferenceErrorPrototype%":["ReferenceError","prototype"],"%RegExpPrototype%":["RegExp","prototype"],"%SetPrototype%":["Set","prototype"],"%SharedArrayBufferPrototype%":["SharedArrayBuffer","prototype"],"%StringPrototype%":["String","prototype"],"%SymbolPrototype%":["Symbol","prototype"],"%SyntaxErrorPrototype%":["SyntaxError","prototype"],"%TypedArrayPrototype%":["TypedArray","prototype"],"%TypeErrorPrototype%":["TypeError","prototype"],"%Uint8ArrayPrototype%":["Uint8Array","prototype"],"%Uint8ClampedArrayPrototype%":["Uint8ClampedArray","prototype"],"%Uint16ArrayPrototype%":["Uint16Array","prototype"],"%Uint32ArrayPrototype%":["Uint32Array","prototype"],"%URIErrorPrototype%":["URIError","prototype"],"%WeakMapPrototype%":["WeakMap","prototype"],"%WeakSetPrototype%":["WeakSet","prototype"]},v=t(470),b=t(510),y=v.call(Function.call,Array.prototype.concat),g=v.call(Function.apply,Array.prototype.splice),_=v.call(Function.call,String.prototype.replace),x=v.call(Function.call,String.prototype.slice),w=v.call(Function.call,RegExp.prototype.exec),E=/[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g,I=/\\(\\)?/g,S=function(e){var u=x(e,0,1),t=x(e,-1);if("%"===u&&"%"!==t)throw new n("invalid intrinsic syntax, expected closing `%`");if("%"===t&&"%"!==u)throw new n("invalid intrinsic syntax, expected opening `%`");var d=[];return _(e,E,(function(e,u,t,n){d[d.length]=t?_(n,I,"$1"):u||e})),d},A=function(e,u){var t,d=e;if(b(h,d)&&(d="%"+(t=h[d])[0]+"%"),b(m,d)){var c=m[d];if(c===s&&(c=function e(u){var t;if("%AsyncFunction%"===u)t=a("async function () {}");else if("%GeneratorFunction%"===u)t=a("function* () {}");else if("%AsyncGeneratorFunction%"===u)t=a("async function* () {}");else if("%AsyncGenerator%"===u){var n=e("%AsyncGeneratorFunction%");n&&(t=n.prototype)}else if("%AsyncIteratorPrototype%"===u){var d=e("%AsyncGenerator%");d&&(t=l(d.prototype))}return m[u]=t,t}(d)),void 0===c&&!u)throw new r("intrinsic "+e+" exists, but is not available. Please file an issue!");return{alias:t,name:d,value:c}}throw new n("intrinsic "+e+" does not exist!")};e.exports=function(e,u){if("string"!=typeof e||0===e.length)throw new r("intrinsic name must be a non-empty string");if(arguments.length>1&&"boolean"!=typeof u)throw new r('"allowMissing" argument must be a boolean');if(null===w(/^%?[^%]*%?$/,e))throw new n("`%` may not be present anywhere but at the beginning and end of the intrinsic name");var t=S(e),d=t.length>0?t[0]:"",a=A("%"+d+"%",u),o=a.name,i=a.value,f=!1,l=a.alias;l&&(d=l[0],g(t,y([0,1],l)));for(var s=1,p=!0;s=t.length){var E=c(i,h);i=(p=!!E)&&"get"in E&&!("originalValue"in E.get)?E.get:i[h]}else p=b(i,h),i=i[h];p&&!f&&(m[o]=i)}}return i}},470:function(e,u,t){"use strict";var n=t(509);e.exports=Function.prototype.bind||n},471:function(e,u,t){"use strict";var n=String.prototype.replace,d=/%20/g,r="RFC1738",a="RFC3986";e.exports={default:a,formatters:{RFC1738:function(e){return n.call(e,d,"+")},RFC3986:function(e){return String(e)}},RFC1738:r,RFC3986:a}},478:function(e,u,t){"use strict";var n=t(471),d=Object.prototype.hasOwnProperty,r=Array.isArray,a=function(){for(var e=[],u=0;u<256;++u)e.push("%"+((u<16?"0":"")+u.toString(16)).toUpperCase());return e}(),c=function(e,u){for(var t=u&&u.plainObjects?Object.create(null):{},n=0;n1;){var u=e.pop(),t=u.obj[u.prop];if(r(t)){for(var n=[],d=0;d=48&&f<=57||f>=65&&f<=90||f>=97&&f<=122||r===n.RFC1738&&(40===f||41===f)?o+=c.charAt(i):f<128?o+=a[f]:f<2048?o+=a[192|f>>6]+a[128|63&f]:f<55296||f>=57344?o+=a[224|f>>12]+a[128|f>>6&63]+a[128|63&f]:(i+=1,f=65536+((1023&f)<<10|1023&c.charCodeAt(i)),o+=a[240|f>>18]+a[128|f>>12&63]+a[128|f>>6&63]+a[128|63&f])}return o},isBuffer:function(e){return!(!e||"object"!=typeof e)&&!!(e.constructor&&e.constructor.isBuffer&&e.constructor.isBuffer(e))},isRegExp:function(e){return"[object RegExp]"===Object.prototype.toString.call(e)},maybeMap:function(e,u){if(r(e)){for(var t=[],n=0;n{if("string"!=typeof e)throw new TypeError("Expected a string");return e=(e=(e=n(e)).toLowerCase().replace(/[_-]+/g," ").replace(/\s{2,}/g," ").trim()).charAt(0).toUpperCase()+e.slice(1)};e.exports=d,e.exports.default=d},486:function(e,u){e.exports=Object.is||function(e,u){return e===u?0!==e||1/e==1/u:e!=e&&u!=u}},489:function(e,u,t){"use strict";var n=t(30),d=t(12),r=t(27),a=t(91),c=t(92),o=t(26),i=t(545),f=t(93);d(d.S+d.F*!t(83)((function(e){Array.from(e)})),"Array",{from:function(e){var u,t,d,l,s=r(e),p="function"==typeof this?this:Array,m=arguments.length,h=m>1?arguments[1]:void 0,v=void 0!==h,b=0,y=f(s);if(v&&(h=n(h,m>2?arguments[2]:void 0,2)),null==y||p==Array&&c(y))for(t=new p(u=o(s.length));u>b;b++)i(t,b,v?h(s[b],b):s[b]);else for(l=y.call(s),t=new p;!(d=l.next()).done;b++)i(t,b,v?a(l,h,[d.value,b],!0):d.value);return t.length=b,t}})},490:function(e,u,t){"use strict";var n=t(546),d=t(492);e.exports=t(547)("Set",(function(e){return function(){return e(this,arguments.length>0?arguments[0]:void 0)}}),{add:function(e){return n.def(d(this,"Set"),e=0===e?0:e,e)}},n)},491:function(e,u,t){var n=t(40)("meta"),d=t(13),r=t(31),a=t(28).f,c=0,o=Object.isExtensible||function(){return!0},i=!t(14)((function(){return o(Object.preventExtensions({}))})),f=function(e){a(e,n,{value:{i:"O"+ ++c,w:{}}})},l=e.exports={KEY:n,NEED:!1,fastKey:function(e,u){if(!d(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!r(e,n)){if(!o(e))return"F";if(!u)return"E";f(e)}return e[n].i},getWeak:function(e,u){if(!r(e,n)){if(!o(e))return!0;if(!u)return!1;f(e)}return e[n].w},onFreeze:function(e){return i&&l.NEED&&o(e)&&!r(e,n)&&f(e),e}}},492:function(e,u,t){var n=t(13);e.exports=function(e,u){if(!n(e)||e._t!==u)throw TypeError("Incompatible receiver, "+u+" required!");return e}},493:function(e,u,t){"use strict";const n=t(494);e.exports=(e,u)=>{if("string"!=typeof e)throw new TypeError("Expected a string");u=void 0===u?"_":u;const t=n("([\\p{Ll}\\d])(\\p{Lu})","g"),d=n("(\\p{Lu}+)(\\p{Lu}[\\p{Ll}\\d]+)","g");return e.replace(t,`$1${u}$2`).replace(d,`$1${u}$2`).toLowerCase()}},494:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0});var n=l(t(495)),d=l(t(496)),r=l(t(497)),a=l(t(498)),c=l(t(499)),o=l(t(500)),i=l(t(501)),f=l(t(502));function l(e){return e&&e.__esModule?e:{default:e}}(0,d.default)(n.default),(0,r.default)(n.default),(0,a.default)(n.default),(0,c.default)(n.default),(0,o.default)(n.default),(0,i.default)(n.default),(0,f.default)(n.default),u.default=n.default,e.exports=u.default},495:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0});var n={astral:!1},d={exec:RegExp.prototype.exec,test:RegExp.prototype.test,match:String.prototype.match,replace:String.prototype.replace,split:String.prototype.split},r={},a={},c={},o=[],i={default:/\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|\(\?(?:[:=!]|<[=!])|[?*+]\?|{\d+(?:,\d*)?}\??|[\s\S]/,class:/\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|[\s\S]/},f=/\$(?:{([\w$]+)}|<([\w$]+)>|(\d\d?|[\s\S]))/g,l=void 0===d.exec.call(/()??/,"")[1],s=void 0!==/x/.flags,p={}.toString;function m(e){var u=!0;try{new RegExp("",e)}catch(t){u=!1}return u}var h=m("u"),v=m("y"),b={g:!0,i:!0,m:!0,u:h,y:v};function y(e,u,t,n,d){var r=void 0;if(e.xregexp={captureNames:u},d)return e;if(e.__proto__)e.__proto__=C.prototype;else for(r in C.prototype)e[r]=C.prototype[r];return e.xregexp.source=t,e.xregexp.flags=n?n.split("").sort().join(""):n,e}function g(e){return d.replace.call(e,/([\s\S])(?=[\s\S]*\1)/g,"")}function _(e,u){if(!C.isRegExp(e))throw new TypeError("Type RegExp expected");var t=e.xregexp||{},n=function(e){return s?e.flags:d.exec.call(/\/([a-z]*)$/i,RegExp.prototype.toString.call(e))[1]}(e),r="",a="",c=null,o=null;return(u=u||{}).removeG&&(a+="g"),u.removeY&&(a+="y"),a&&(n=d.replace.call(n,new RegExp("["+a+"]+","g"),"")),u.addG&&(r+="g"),u.addY&&(r+="y"),r&&(n=g(n+r)),u.isInternalOnly||(void 0!==t.source&&(c=t.source),null!=t.flags&&(o=r?g(t.flags+r):t.flags)),e=y(new RegExp(u.source||e.source,n),function(e){return!(!e.xregexp||!e.xregexp.captureNames)}(e)?t.captureNames.slice(0):null,c,o,u.isInternalOnly)}function x(e){return parseInt(e,16)}function w(e,u,t){return"("===e.input[e.index-1]||")"===e.input[e.index+e[0].length]||function(e,u,t){return d.test.call(-1!==t.indexOf("x")?/^(?:\s|#[^#\n]*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/:/^(?:\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/,e.slice(u))}(e.input,e.index+e[0].length,t)?"":"(?:)"}function E(e){return parseInt(e,10).toString(16)}function I(e,u){return p.call(e)==="[object "+u+"]"}function S(e){for(;e.length<4;)e="0"+e;return e}function A(e){var u={};return I(e,"String")?(C.forEach(e,/[^\s,]+/,(function(e){u[e]=!0})),u):e}function k(e){if(!/^[\w$]$/.test(e))throw new Error("Flag must be a single character A-Za-z0-9_$");b[e]=!0}function j(e,u,t,n,d){for(var r=o.length,a=e[t],c=null,i=void 0,f=void 0;r--;)if(!((f=o[r]).leadChar&&f.leadChar!==a||f.scope!==n&&"all"!==f.scope||f.flag&&-1===u.indexOf(f.flag))&&(i=C.exec(e,f.regex,t,"sticky"))){c={matchLength:i[0].length,output:f.handler.call(d,i,n,u),reparse:f.reparse};break}return c}function O(e){n.astral=e}function N(e){if(null==e)throw new TypeError("Cannot convert null or undefined to object");return e}function C(e,u){if(C.isRegExp(e)){if(void 0!==u)throw new TypeError("Cannot supply flags when copying a RegExp");return _(e)}if(e=void 0===e?"":String(e),u=void 0===u?"":String(u),C.isInstalled("astral")&&-1===u.indexOf("A")&&(u+="A"),c[e]||(c[e]={}),!c[e][u]){for(var t={hasNamedCapture:!1,captureNames:[]},n="default",r="",a=0,o=void 0,f=function(e,u){var t=void 0;if(g(u)!==u)throw new SyntaxError("Invalid duplicate regex flag "+u);for(e=d.replace.call(e,/^\(\?([\w$]+)\)/,(function(e,t){if(d.test.call(/[gy]/,t))throw new SyntaxError("Cannot use flag g or y in mode modifier "+e);return u=g(u+t),""})),t=0;t"}else if(t)return"\\"+(+t+a);return e}if(!I(e,"Array")||!e.length)throw new TypeError("Must provide a nonempty array of patterns to merge");for(var i=/(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*\]/g,f=[],l=void 0,s=0;s1&&-1!==t.indexOf("")){var n=_(this,{removeG:!0,isInternalOnly:!0});d.replace.call(String(e).slice(t.index),n,(function(){for(var e=arguments.length,u=Array(e),n=0;nt.index&&(this.lastIndex=t.index)}return this.global||(this.lastIndex=u),t},r.test=function(e){return!!r.exec.call(this,e)},r.match=function(e){if(C.isRegExp(e)){if(e.global){var u=d.match.apply(this,arguments);return e.lastIndex=0,u}}else e=new RegExp(e);return r.exec.call(e,N(this))},r.replace=function(e,u){var t=C.isRegExp(e),n=void 0,r=void 0,a=void 0;return t?(e.xregexp&&(r=e.xregexp.captureNames),n=e.lastIndex):e+="",a=I(u,"Function")?d.replace.call(String(this),e,(function(){for(var n=arguments.length,d=Array(n),a=0;at.length-3)throw new SyntaxError("Backreference to undefined group "+e);return t[d]||""}throw new SyntaxError("Invalid token "+e)}})),t&&(e.global?e.lastIndex=0:e.lastIndex=n),a},r.split=function(e,u){if(!C.isRegExp(e))return d.split.apply(this,arguments);var t=String(this),n=[],r=e.lastIndex,a=0,c=void 0;return u=(void 0===u?-1:u)>>>0,C.forEach(t,e,(function(e){e.index+e[0].length>a&&(n.push(t.slice(a,e.index)),e.length>1&&e.indexu?n.slice(0,u):n},C.addToken(/\\([ABCE-RTUVXYZaeg-mopqyz]|c(?![A-Za-z])|u(?![\dA-Fa-f]{4}|{[\dA-Fa-f]+})|x(?![\dA-Fa-f]{2}))/,(function(e,u){if("B"===e[1]&&"default"===u)return e[0];throw new SyntaxError("Invalid escape "+e[0])}),{scope:"all",leadChar:"\\"}),C.addToken(/\\u{([\dA-Fa-f]+)}/,(function(e,u,t){var n=x(e[1]);if(n>1114111)throw new SyntaxError("Invalid Unicode code point "+e[0]);if(n<=65535)return"\\u"+S(E(n));if(h&&-1!==t.indexOf("u"))return e[0];throw new SyntaxError("Cannot use Unicode code point above \\u{FFFF} without flag u")}),{scope:"all",leadChar:"\\"}),C.addToken(/\[(\^?)\]/,(function(e){return e[1]?"[\\s\\S]":"\\b\\B"}),{leadChar:"["}),C.addToken(/\(\?#[^)]*\)/,w,{leadChar:"("}),C.addToken(/\s+|#[^\n]*\n?/,w,{flag:"x"}),C.addToken(/\./,(function(){return"[\\s\\S]"}),{flag:"s",leadChar:"."}),C.addToken(/\\k<([\w$]+)>/,(function(e){var u=isNaN(e[1])?this.captureNames.indexOf(e[1])+1:+e[1],t=e.index+e[0].length;if(!u||u>this.captureNames.length)throw new SyntaxError("Backreference to undefined group "+e[0]);return"\\"+u+(t===e.input.length||isNaN(e.input[t])?"":"(?:)")}),{leadChar:"\\"}),C.addToken(/\\(\d+)/,(function(e,u){if(!("default"===u&&/^[1-9]/.test(e[1])&&+e[1]<=this.captureNames.length)&&"0"!==e[1])throw new SyntaxError("Cannot use octal escape or backreference to undefined group "+e[0]);return e[0]}),{scope:"all",leadChar:"\\"}),C.addToken(/\(\?P?<([\w$]+)>/,(function(e){if(!isNaN(e[1]))throw new SyntaxError("Cannot use integer as capture name "+e[0]);if("length"===e[1]||"__proto__"===e[1])throw new SyntaxError("Cannot use reserved word as capture name "+e[0]);if(-1!==this.captureNames.indexOf(e[1]))throw new SyntaxError("Cannot use same name for multiple groups "+e[0]);return this.captureNames.push(e[1]),this.hasNamedCapture=!0,"("}),{leadChar:"("}),C.addToken(/\((?!\?)/,(function(e,u,t){return-1!==t.indexOf("n")?"(?:":(this.captureNames.push(null),"(")}),{optionalFlags:"n",leadChar:"("}),u.default=C,e.exports=u.default},496:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0}),u.default=function(e){var u=/(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*\]/g,t=e.union([/\({{([\w$]+)}}\)|{{([\w$]+)}}/,u],"g",{conjunction:"or"});function n(e){var u=/^(?:\(\?:\))*\^/,t=/\$(?:\(\?:\))*$/;return u.test(e)&&t.test(e)&&t.test(e.replace(/\\[\s\S]/g,""))?e.replace(u,"").replace(t,""):e}function d(u,t){var n=t?"x":"";return e.isRegExp(u)?u.xregexp&&u.xregexp.captureNames?u:e(u.source,n):e(u,n)}function r(u){return u instanceof RegExp?u:e.escape(u)}function a(e,u,t){return e["subpattern"+t]=u,e}function c(e,u,t){return e+(u1?n-1:0),o=1;o"):o="(?:",h=m,""+o+f[a].pattern.replace(u,(function(e,u,t){if(u){if(c=f[a].names[m-h],++m,c)return"(?<"+c+">"}else if(t)return i=+t-1,f[a].names[i]?"\\k<"+f[a].names[i]+">":"\\"+(+t+h);return e}))+")"}if(d){if(c=y[v],b[++v]=++m,c)return"(?<"+c+">"}else if(r)return y[i=+r-1]?"\\k<"+y[i]+">":"\\"+b[+r];return e}));return e(g,c)}},e.exports=u.default},497:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0}),u.default=function(e){function u(e,u,t,n){return{name:e,value:u,start:t,end:n}}e.matchRecursive=function(t,n,d,r,a){a=a||{};var c=-1!==(r=r||"").indexOf("g"),o=-1!==r.indexOf("y"),i=r.replace(/y/g,""),f=a.escapeChar,l=a.valueNames,s=[],p=0,m=0,h=0,v=0,b=void 0,y=void 0,g=void 0,_=void 0,x=void 0;if(n=e(n,i),d=e(d,i),f){if(f.length>1)throw new Error("Cannot use more than one escape character");f=e.escape(f),x=new RegExp("(?:"+f+"[\\S\\s]|(?:(?!"+e.union([n,d],"",{conjunction:"or"}).source+")[^"+f+"])+)+",r.replace(/[^imu]+/g,""))}for(;;){if(f&&(h+=(e.exec(t,x,h,"sticky")||[""])[0].length),g=e.exec(t,n,h),_=e.exec(t,d,h),g&&_&&(g.index<=_.index?_=null:g=null),g||_)h=(m=(g||_).index)+(g||_)[0].length;else if(!p)break;if(o&&!p&&m>v)break;if(g)p||(b=m,y=h),++p;else{if(!_||!p)throw new Error("Unbalanced delimiter found in string");if(!--p&&(l?(l[0]&&b>v&&s.push(u(l[0],t.slice(v,b),v,b)),l[1]&&s.push(u(l[1],t.slice(b,y),b,y)),l[2]&&s.push(u(l[2],t.slice(y,m),y,m)),l[3]&&s.push(u(l[3],t.slice(m,h),m,h))):s.push(t.slice(y,m)),v=h,!c))break}m===h&&++h}return c&&!o&&l&&l[0]&&t.length>v&&s.push(u(l[0],t.slice(v),v,t.length)),s}},e.exports=u.default},498:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0}),u.default=function(e){var u={},t=e._dec,n=e._hex,d=e._pad4;function r(e){return e.replace(/[- _]+/g,"").toLowerCase()}function a(e){var u=/^\\[xu](.+)/.exec(e);return u?t(u[1]):e.charCodeAt("\\"===e[0]?1:0)}function c(t){var r,c,o;return u[t]["b!"]||(u[t]["b!"]=(r=u[t].bmp,c="",o=-1,e.forEach(r,/(\\x..|\\u....|\\?[\s\S])(?:-(\\x..|\\u....|\\?[\s\S]))?/,(function(e){var u=a(e[1]);u>o+1&&(c+="\\u"+d(n(o+1)),u>o+2&&(c+="-\\u"+d(n(u-1)))),o=a(e[2]||e[1])})),o<65535&&(c+="\\u"+d(n(o+1)),o<65534&&(c+="-\\uFFFF")),c))}function o(e,t){var n=t?"a!":"a=";return u[e][n]||(u[e][n]=function(e,t){var n=u[e],d="";return n.bmp&&!n.isBmpLast&&(d="["+n.bmp+"]"+(n.astral?"|":"")),n.astral&&(d+=n.astral),n.isBmpLast&&n.bmp&&(d+=(n.astral?"|":"")+"["+n.bmp+"]"),t?"(?:(?!"+d+")(?:[\ud800-\udbff][\udc00-\udfff]|[\0-\uffff]))":"(?:"+d+")"}(e,t))}e.addToken(/\\([pP])(?:{(\^?)([^}]*)}|([A-Za-z]))/,(function(e,t,n){var d="P"===e[1]||!!e[2],a=-1!==n.indexOf("A"),i=r(e[4]||e[3]),f=u[i];if("P"===e[1]&&e[2])throw new SyntaxError("Invalid double negation "+e[0]);if(!u.hasOwnProperty(i))throw new SyntaxError("Unknown Unicode token "+e[0]);if(f.inverseOf){if(i=r(f.inverseOf),!u.hasOwnProperty(i))throw new ReferenceError("Unicode token missing data "+e[0]+" -> "+f.inverseOf);f=u[i],d=!d}if(!f.bmp&&!a)throw new SyntaxError("Astral mode required for Unicode token "+e[0]);if(a){if("class"===t)throw new SyntaxError("Astral mode does not support Unicode tokens within character classes");return o(i,d)}return"class"===t?d?c(i):f.bmp:(d?"[^":"[")+f.bmp+"]"}),{scope:"all",optionalFlags:"A",leadChar:"\\"}),e.addUnicodeData=function(t){for(var n=void 0,d=0;d\\x5E`\\x7C~\xa2-\xa6\xa8\xa9\xac\xae-\xb1\xb4\xb8\xd7\xf7\u02c2-\u02c5\u02d2-\u02df\u02e5-\u02eb\u02ed\u02ef-\u02ff\u0375\u0384\u0385\u03f6\u0482\u058d-\u058f\u0606-\u0608\u060b\u060e\u060f\u06de\u06e9\u06fd\u06fe\u07f6\u09f2\u09f3\u09fa\u09fb\u0af1\u0b70\u0bf3-\u0bfa\u0c7f\u0d4f\u0d79\u0e3f\u0f01-\u0f03\u0f13\u0f15-\u0f17\u0f1a-\u0f1f\u0f34\u0f36\u0f38\u0fbe-\u0fc5\u0fc7-\u0fcc\u0fce\u0fcf\u0fd5-\u0fd8\u109e\u109f\u1390-\u1399\u17db\u1940\u19de-\u19ff\u1b61-\u1b6a\u1b74-\u1b7c\u1fbd\u1fbf-\u1fc1\u1fcd-\u1fcf\u1fdd-\u1fdf\u1fed-\u1fef\u1ffd\u1ffe\u2044\u2052\u207a-\u207c\u208a-\u208c\u20a0-\u20be\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116-\u2118\u211e-\u2123\u2125\u2127\u2129\u212e\u213a\u213b\u2140-\u2144\u214a-\u214d\u214f\u218a\u218b\u2190-\u2307\u230c-\u2328\u232b-\u23fe\u2400-\u2426\u2440-\u244a\u249c-\u24e9\u2500-\u2767\u2794-\u27c4\u27c7-\u27e5\u27f0-\u2982\u2999-\u29d7\u29dc-\u29fb\u29fe-\u2b73\u2b76-\u2b95\u2b98-\u2bb9\u2bbd-\u2bc8\u2bca-\u2bd1\u2bec-\u2bef\u2ce5-\u2cea\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u2ff0-\u2ffb\u3004\u3012\u3013\u3020\u3036\u3037\u303e\u303f\u309b\u309c\u3190\u3191\u3196-\u319f\u31c0-\u31e3\u3200-\u321e\u322a-\u3247\u3250\u3260-\u327f\u328a-\u32b0\u32c0-\u32fe\u3300-\u33ff\u4dc0-\u4dff\ua490-\ua4c6\ua700-\ua716\ua720\ua721\ua789\ua78a\ua828-\ua82b\ua836-\ua839\uaa77-\uaa79\uab5b\ufb29\ufbb2-\ufbc1\ufdfc\ufdfd\ufe62\ufe64-\ufe66\ufe69\uff04\uff0b\uff1c-\uff1e\uff3e\uff40\uff5c\uff5e\uffe0-\uffe6\uffe8-\uffee\ufffc\ufffd",astral:"\ud800[\udd37-\udd3f\udd79-\udd89\udd8c-\udd8e\udd90-\udd9b\udda0\uddd0-\uddfc]|\ud802[\udc77\udc78\udec8]|\ud805\udf3f|\ud81a[\udf3c-\udf3f\udf45]|\ud82f\udc9c|\ud834[\udc00-\udcf5\udd00-\udd26\udd29-\udd64\udd6a-\udd6c\udd83\udd84\udd8c-\udda9\uddae-\udde8\ude00-\ude41\ude45\udf00-\udf56]|\ud835[\udec1\udedb\udefb\udf15\udf35\udf4f\udf6f\udf89\udfa9\udfc3]|\ud836[\udc00-\uddff\ude37-\ude3a\ude6d-\ude74\ude76-\ude83\ude85\ude86]|\ud83b[\udef0\udef1]|\ud83c[\udc00-\udc2b\udc30-\udc93\udca0-\udcae\udcb1-\udcbf\udcc1-\udccf\udcd1-\udcf5\udd10-\udd2e\udd30-\udd6b\udd70-\uddac\udde6-\ude02\ude10-\ude3b\ude40-\ude48\ude50\ude51\udf00-\udfff]|\ud83d[\udc00-\uded2\udee0-\udeec\udef0-\udef6\udf00-\udf73\udf80-\udfd4]|\ud83e[\udc00-\udc0b\udc10-\udc47\udc50-\udc59\udc60-\udc87\udc90-\udcad\udd10-\udd1e\udd20-\udd27\udd30\udd33-\udd3e\udd40-\udd4b\udd50-\udd5e\udd80-\udd91\uddc0]"},{name:"Sc",alias:"Currency_Symbol",bmp:"\\x24\xa2-\xa5\u058f\u060b\u09f2\u09f3\u09fb\u0af1\u0bf9\u0e3f\u17db\u20a0-\u20be\ua838\ufdfc\ufe69\uff04\uffe0\uffe1\uffe5\uffe6"},{name:"Sk",alias:"Modifier_Symbol",bmp:"\\x5E`\xa8\xaf\xb4\xb8\u02c2-\u02c5\u02d2-\u02df\u02e5-\u02eb\u02ed\u02ef-\u02ff\u0375\u0384\u0385\u1fbd\u1fbf-\u1fc1\u1fcd-\u1fcf\u1fdd-\u1fdf\u1fed-\u1fef\u1ffd\u1ffe\u309b\u309c\ua700-\ua716\ua720\ua721\ua789\ua78a\uab5b\ufbb2-\ufbc1\uff3e\uff40\uffe3",astral:"\ud83c[\udffb-\udfff]"},{name:"Sm",alias:"Math_Symbol",bmp:"\\x2B<->\\x7C~\xac\xb1\xd7\xf7\u03f6\u0606-\u0608\u2044\u2052\u207a-\u207c\u208a-\u208c\u2118\u2140-\u2144\u214b\u2190-\u2194\u219a\u219b\u21a0\u21a3\u21a6\u21ae\u21ce\u21cf\u21d2\u21d4\u21f4-\u22ff\u2320\u2321\u237c\u239b-\u23b3\u23dc-\u23e1\u25b7\u25c1\u25f8-\u25ff\u266f\u27c0-\u27c4\u27c7-\u27e5\u27f0-\u27ff\u2900-\u2982\u2999-\u29d7\u29dc-\u29fb\u29fe-\u2aff\u2b30-\u2b44\u2b47-\u2b4c\ufb29\ufe62\ufe64-\ufe66\uff0b\uff1c-\uff1e\uff5c\uff5e\uffe2\uffe9-\uffec",astral:"\ud835[\udec1\udedb\udefb\udf15\udf35\udf4f\udf6f\udf89\udfa9\udfc3]|\ud83b[\udef0\udef1]"},{name:"So",alias:"Other_Symbol",bmp:"\xa6\xa9\xae\xb0\u0482\u058d\u058e\u060e\u060f\u06de\u06e9\u06fd\u06fe\u07f6\u09fa\u0b70\u0bf3-\u0bf8\u0bfa\u0c7f\u0d4f\u0d79\u0f01-\u0f03\u0f13\u0f15-\u0f17\u0f1a-\u0f1f\u0f34\u0f36\u0f38\u0fbe-\u0fc5\u0fc7-\u0fcc\u0fce\u0fcf\u0fd5-\u0fd8\u109e\u109f\u1390-\u1399\u1940\u19de-\u19ff\u1b61-\u1b6a\u1b74-\u1b7c\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116\u2117\u211e-\u2123\u2125\u2127\u2129\u212e\u213a\u213b\u214a\u214c\u214d\u214f\u218a\u218b\u2195-\u2199\u219c-\u219f\u21a1\u21a2\u21a4\u21a5\u21a7-\u21ad\u21af-\u21cd\u21d0\u21d1\u21d3\u21d5-\u21f3\u2300-\u2307\u230c-\u231f\u2322-\u2328\u232b-\u237b\u237d-\u239a\u23b4-\u23db\u23e2-\u23fe\u2400-\u2426\u2440-\u244a\u249c-\u24e9\u2500-\u25b6\u25b8-\u25c0\u25c2-\u25f7\u2600-\u266e\u2670-\u2767\u2794-\u27bf\u2800-\u28ff\u2b00-\u2b2f\u2b45\u2b46\u2b4d-\u2b73\u2b76-\u2b95\u2b98-\u2bb9\u2bbd-\u2bc8\u2bca-\u2bd1\u2bec-\u2bef\u2ce5-\u2cea\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u2ff0-\u2ffb\u3004\u3012\u3013\u3020\u3036\u3037\u303e\u303f\u3190\u3191\u3196-\u319f\u31c0-\u31e3\u3200-\u321e\u322a-\u3247\u3250\u3260-\u327f\u328a-\u32b0\u32c0-\u32fe\u3300-\u33ff\u4dc0-\u4dff\ua490-\ua4c6\ua828-\ua82b\ua836\ua837\ua839\uaa77-\uaa79\ufdfd\uffe4\uffe8\uffed\uffee\ufffc\ufffd",astral:"\ud800[\udd37-\udd3f\udd79-\udd89\udd8c-\udd8e\udd90-\udd9b\udda0\uddd0-\uddfc]|\ud802[\udc77\udc78\udec8]|\ud805\udf3f|\ud81a[\udf3c-\udf3f\udf45]|\ud82f\udc9c|\ud834[\udc00-\udcf5\udd00-\udd26\udd29-\udd64\udd6a-\udd6c\udd83\udd84\udd8c-\udda9\uddae-\udde8\ude00-\ude41\ude45\udf00-\udf56]|\ud836[\udc00-\uddff\ude37-\ude3a\ude6d-\ude74\ude76-\ude83\ude85\ude86]|\ud83c[\udc00-\udc2b\udc30-\udc93\udca0-\udcae\udcb1-\udcbf\udcc1-\udccf\udcd1-\udcf5\udd10-\udd2e\udd30-\udd6b\udd70-\uddac\udde6-\ude02\ude10-\ude3b\ude40-\ude48\ude50\ude51\udf00-\udffa]|\ud83d[\udc00-\uded2\udee0-\udeec\udef0-\udef6\udf00-\udf73\udf80-\udfd4]|\ud83e[\udc00-\udc0b\udc10-\udc47\udc50-\udc59\udc60-\udc87\udc90-\udcad\udd10-\udd1e\udd20-\udd27\udd30\udd33-\udd3e\udd40-\udd4b\udd50-\udd5e\udd80-\udd91\uddc0]"},{name:"Z",alias:"Separator",bmp:" \xa0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000"},{name:"Zl",alias:"Line_Separator",bmp:"\u2028"},{name:"Zp",alias:"Paragraph_Separator",bmp:"\u2029"},{name:"Zs",alias:"Space_Separator",bmp:" \xa0\u1680\u2000-\u200a\u202f\u205f\u3000"}])},e.exports=u.default},501:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0}),u.default=function(e){if(!e.addUnicodeData)throw new ReferenceError("Unicode Base must be loaded before Unicode Properties");var u=[{name:"ASCII",bmp:"\0-\x7f"},{name:"Alphabetic",bmp:"A-Za-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0345\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0561-\u0587\u05b0-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0657\u0659-\u065f\u066e-\u06d3\u06d5-\u06dc\u06e1-\u06e8\u06ed-\u06ef\u06fa-\u06fc\u06ff\u0710-\u073f\u074d-\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0817\u081a-\u082c\u0840-\u0858\u08a0-\u08b4\u08b6-\u08bd\u08d4-\u08df\u08e3-\u08e9\u08f0-\u093b\u093d-\u094c\u094e-\u0950\u0955-\u0963\u0971-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd-\u09c4\u09c7\u09c8\u09cb\u09cc\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09f0\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3e-\u0a42\u0a47\u0a48\u0a4b\u0a4c\u0a51\u0a59-\u0a5c\u0a5e\u0a70-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd-\u0ac5\u0ac7-\u0ac9\u0acb\u0acc\u0ad0\u0ae0-\u0ae3\u0af9\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d-\u0b44\u0b47\u0b48\u0b4b\u0b4c\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcc\u0bd0\u0bd7\u0c00-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4c\u0c55\u0c56\u0c58-\u0c5a\u0c60-\u0c63\u0c80-\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccc\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0cf1\u0cf2\u0d01-\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4c\u0d4e\u0d54-\u0d57\u0d5f-\u0d63\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e46\u0e4d\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ecd\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f71-\u0f81\u0f88-\u0f97\u0f99-\u0fbc\u1000-\u1036\u1038\u103b-\u103f\u1050-\u1062\u1065-\u1068\u106e-\u1086\u108e\u109c\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135f\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1713\u1720-\u1733\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17b3\u17b6-\u17c8\u17d7\u17dc\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191e\u1920-\u192b\u1930-\u1938\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a1b\u1a20-\u1a5e\u1a61-\u1a74\u1aa7\u1b00-\u1b33\u1b35-\u1b43\u1b45-\u1b4b\u1b80-\u1ba9\u1bac-\u1baf\u1bba-\u1be5\u1be7-\u1bf1\u1c00-\u1c35\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1d00-\u1dbf\u1de7-\u1df4\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u24b6-\u24e9\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fd5\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua674-\ua67b\ua67f-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7ae\ua7b0-\ua7b7\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua827\ua840-\ua873\ua880-\ua8c3\ua8c5\ua8f2-\ua8f7\ua8fb\ua8fd\ua90a-\ua92a\ua930-\ua952\ua960-\ua97c\ua980-\ua9b2\ua9b4-\ua9bf\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa36\uaa40-\uaa4d\uaa60-\uaa76\uaa7a\uaa7e-\uaabe\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf5\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab65\uab70-\uabea\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc",astral:"\ud800[\udc00-\udc0b\udc0d-\udc26\udc28-\udc3a\udc3c\udc3d\udc3f-\udc4d\udc50-\udc5d\udc80-\udcfa\udd40-\udd74\ude80-\ude9c\udea0-\uded0\udf00-\udf1f\udf30-\udf4a\udf50-\udf7a\udf80-\udf9d\udfa0-\udfc3\udfc8-\udfcf\udfd1-\udfd5]|\ud801[\udc00-\udc9d\udcb0-\udcd3\udcd8-\udcfb\udd00-\udd27\udd30-\udd63\ude00-\udf36\udf40-\udf55\udf60-\udf67]|\ud802[\udc00-\udc05\udc08\udc0a-\udc35\udc37\udc38\udc3c\udc3f-\udc55\udc60-\udc76\udc80-\udc9e\udce0-\udcf2\udcf4\udcf5\udd00-\udd15\udd20-\udd39\udd80-\uddb7\uddbe\uddbf\ude00-\ude03\ude05\ude06\ude0c-\ude13\ude15-\ude17\ude19-\ude33\ude60-\ude7c\ude80-\ude9c\udec0-\udec7\udec9-\udee4\udf00-\udf35\udf40-\udf55\udf60-\udf72\udf80-\udf91]|\ud803[\udc00-\udc48\udc80-\udcb2\udcc0-\udcf2]|\ud804[\udc00-\udc45\udc82-\udcb8\udcd0-\udce8\udd00-\udd32\udd50-\udd72\udd76\udd80-\uddbf\uddc1-\uddc4\uddda\udddc\ude00-\ude11\ude13-\ude34\ude37\ude3e\ude80-\ude86\ude88\ude8a-\ude8d\ude8f-\ude9d\ude9f-\udea8\udeb0-\udee8\udf00-\udf03\udf05-\udf0c\udf0f\udf10\udf13-\udf28\udf2a-\udf30\udf32\udf33\udf35-\udf39\udf3d-\udf44\udf47\udf48\udf4b\udf4c\udf50\udf57\udf5d-\udf63]|\ud805[\udc00-\udc41\udc43-\udc45\udc47-\udc4a\udc80-\udcc1\udcc4\udcc5\udcc7\udd80-\uddb5\uddb8-\uddbe\uddd8-\udddd\ude00-\ude3e\ude40\ude44\ude80-\udeb5\udf00-\udf19\udf1d-\udf2a]|\ud806[\udca0-\udcdf\udcff\udec0-\udef8]|\ud807[\udc00-\udc08\udc0a-\udc36\udc38-\udc3e\udc40\udc72-\udc8f\udc92-\udca7\udca9-\udcb6]|\ud808[\udc00-\udf99]|\ud809[\udc00-\udc6e\udc80-\udd43]|[\ud80c\ud81c-\ud820\ud840-\ud868\ud86a-\ud86c\ud86f-\ud872][\udc00-\udfff]|\ud80d[\udc00-\udc2e]|\ud811[\udc00-\ude46]|\ud81a[\udc00-\ude38\ude40-\ude5e\uded0-\udeed\udf00-\udf36\udf40-\udf43\udf63-\udf77\udf7d-\udf8f]|\ud81b[\udf00-\udf44\udf50-\udf7e\udf93-\udf9f\udfe0]|\ud821[\udc00-\udfec]|\ud822[\udc00-\udef2]|\ud82c[\udc00\udc01]|\ud82f[\udc00-\udc6a\udc70-\udc7c\udc80-\udc88\udc90-\udc99\udc9e]|\ud835[\udc00-\udc54\udc56-\udc9c\udc9e\udc9f\udca2\udca5\udca6\udca9-\udcac\udcae-\udcb9\udcbb\udcbd-\udcc3\udcc5-\udd05\udd07-\udd0a\udd0d-\udd14\udd16-\udd1c\udd1e-\udd39\udd3b-\udd3e\udd40-\udd44\udd46\udd4a-\udd50\udd52-\udea5\udea8-\udec0\udec2-\udeda\udedc-\udefa\udefc-\udf14\udf16-\udf34\udf36-\udf4e\udf50-\udf6e\udf70-\udf88\udf8a-\udfa8\udfaa-\udfc2\udfc4-\udfcb]|\ud838[\udc00-\udc06\udc08-\udc18\udc1b-\udc21\udc23\udc24\udc26-\udc2a]|\ud83a[\udc00-\udcc4\udd00-\udd43\udd47]|\ud83b[\ude00-\ude03\ude05-\ude1f\ude21\ude22\ude24\ude27\ude29-\ude32\ude34-\ude37\ude39\ude3b\ude42\ude47\ude49\ude4b\ude4d-\ude4f\ude51\ude52\ude54\ude57\ude59\ude5b\ude5d\ude5f\ude61\ude62\ude64\ude67-\ude6a\ude6c-\ude72\ude74-\ude77\ude79-\ude7c\ude7e\ude80-\ude89\ude8b-\ude9b\udea1-\udea3\udea5-\udea9\udeab-\udebb]|\ud83c[\udd30-\udd49\udd50-\udd69\udd70-\udd89]|\ud869[\udc00-\uded6\udf00-\udfff]|\ud86d[\udc00-\udf34\udf40-\udfff]|\ud86e[\udc00-\udc1d\udc20-\udfff]|\ud873[\udc00-\udea1]|\ud87e[\udc00-\ude1d]"},{name:"Any",isBmpLast:!0,bmp:"\0-\uffff",astral:"[\ud800-\udbff][\udc00-\udfff]"},{name:"Default_Ignorable_Code_Point",bmp:"\xad\u034f\u061c\u115f\u1160\u17b4\u17b5\u180b-\u180e\u200b-\u200f\u202a-\u202e\u2060-\u206f\u3164\ufe00-\ufe0f\ufeff\uffa0\ufff0-\ufff8",astral:"\ud82f[\udca0-\udca3]|\ud834[\udd73-\udd7a]|[\udb40-\udb43][\udc00-\udfff]"},{name:"Lowercase",bmp:"a-z\xaa\xb5\xba\xdf-\xf6\xf8-\xff\u0101\u0103\u0105\u0107\u0109\u010b\u010d\u010f\u0111\u0113\u0115\u0117\u0119\u011b\u011d\u011f\u0121\u0123\u0125\u0127\u0129\u012b\u012d\u012f\u0131\u0133\u0135\u0137\u0138\u013a\u013c\u013e\u0140\u0142\u0144\u0146\u0148\u0149\u014b\u014d\u014f\u0151\u0153\u0155\u0157\u0159\u015b\u015d\u015f\u0161\u0163\u0165\u0167\u0169\u016b\u016d\u016f\u0171\u0173\u0175\u0177\u017a\u017c\u017e-\u0180\u0183\u0185\u0188\u018c\u018d\u0192\u0195\u0199-\u019b\u019e\u01a1\u01a3\u01a5\u01a8\u01aa\u01ab\u01ad\u01b0\u01b4\u01b6\u01b9\u01ba\u01bd-\u01bf\u01c6\u01c9\u01cc\u01ce\u01d0\u01d2\u01d4\u01d6\u01d8\u01da\u01dc\u01dd\u01df\u01e1\u01e3\u01e5\u01e7\u01e9\u01eb\u01ed\u01ef\u01f0\u01f3\u01f5\u01f9\u01fb\u01fd\u01ff\u0201\u0203\u0205\u0207\u0209\u020b\u020d\u020f\u0211\u0213\u0215\u0217\u0219\u021b\u021d\u021f\u0221\u0223\u0225\u0227\u0229\u022b\u022d\u022f\u0231\u0233-\u0239\u023c\u023f\u0240\u0242\u0247\u0249\u024b\u024d\u024f-\u0293\u0295-\u02b8\u02c0\u02c1\u02e0-\u02e4\u0345\u0371\u0373\u0377\u037a-\u037d\u0390\u03ac-\u03ce\u03d0\u03d1\u03d5-\u03d7\u03d9\u03db\u03dd\u03df\u03e1\u03e3\u03e5\u03e7\u03e9\u03eb\u03ed\u03ef-\u03f3\u03f5\u03f8\u03fb\u03fc\u0430-\u045f\u0461\u0463\u0465\u0467\u0469\u046b\u046d\u046f\u0471\u0473\u0475\u0477\u0479\u047b\u047d\u047f\u0481\u048b\u048d\u048f\u0491\u0493\u0495\u0497\u0499\u049b\u049d\u049f\u04a1\u04a3\u04a5\u04a7\u04a9\u04ab\u04ad\u04af\u04b1\u04b3\u04b5\u04b7\u04b9\u04bb\u04bd\u04bf\u04c2\u04c4\u04c6\u04c8\u04ca\u04cc\u04ce\u04cf\u04d1\u04d3\u04d5\u04d7\u04d9\u04db\u04dd\u04df\u04e1\u04e3\u04e5\u04e7\u04e9\u04eb\u04ed\u04ef\u04f1\u04f3\u04f5\u04f7\u04f9\u04fb\u04fd\u04ff\u0501\u0503\u0505\u0507\u0509\u050b\u050d\u050f\u0511\u0513\u0515\u0517\u0519\u051b\u051d\u051f\u0521\u0523\u0525\u0527\u0529\u052b\u052d\u052f\u0561-\u0587\u13f8-\u13fd\u1c80-\u1c88\u1d00-\u1dbf\u1e01\u1e03\u1e05\u1e07\u1e09\u1e0b\u1e0d\u1e0f\u1e11\u1e13\u1e15\u1e17\u1e19\u1e1b\u1e1d\u1e1f\u1e21\u1e23\u1e25\u1e27\u1e29\u1e2b\u1e2d\u1e2f\u1e31\u1e33\u1e35\u1e37\u1e39\u1e3b\u1e3d\u1e3f\u1e41\u1e43\u1e45\u1e47\u1e49\u1e4b\u1e4d\u1e4f\u1e51\u1e53\u1e55\u1e57\u1e59\u1e5b\u1e5d\u1e5f\u1e61\u1e63\u1e65\u1e67\u1e69\u1e6b\u1e6d\u1e6f\u1e71\u1e73\u1e75\u1e77\u1e79\u1e7b\u1e7d\u1e7f\u1e81\u1e83\u1e85\u1e87\u1e89\u1e8b\u1e8d\u1e8f\u1e91\u1e93\u1e95-\u1e9d\u1e9f\u1ea1\u1ea3\u1ea5\u1ea7\u1ea9\u1eab\u1ead\u1eaf\u1eb1\u1eb3\u1eb5\u1eb7\u1eb9\u1ebb\u1ebd\u1ebf\u1ec1\u1ec3\u1ec5\u1ec7\u1ec9\u1ecb\u1ecd\u1ecf\u1ed1\u1ed3\u1ed5\u1ed7\u1ed9\u1edb\u1edd\u1edf\u1ee1\u1ee3\u1ee5\u1ee7\u1ee9\u1eeb\u1eed\u1eef\u1ef1\u1ef3\u1ef5\u1ef7\u1ef9\u1efb\u1efd\u1eff-\u1f07\u1f10-\u1f15\u1f20-\u1f27\u1f30-\u1f37\u1f40-\u1f45\u1f50-\u1f57\u1f60-\u1f67\u1f70-\u1f7d\u1f80-\u1f87\u1f90-\u1f97\u1fa0-\u1fa7\u1fb0-\u1fb4\u1fb6\u1fb7\u1fbe\u1fc2-\u1fc4\u1fc6\u1fc7\u1fd0-\u1fd3\u1fd6\u1fd7\u1fe0-\u1fe7\u1ff2-\u1ff4\u1ff6\u1ff7\u2071\u207f\u2090-\u209c\u210a\u210e\u210f\u2113\u212f\u2134\u2139\u213c\u213d\u2146-\u2149\u214e\u2170-\u217f\u2184\u24d0-\u24e9\u2c30-\u2c5e\u2c61\u2c65\u2c66\u2c68\u2c6a\u2c6c\u2c71\u2c73\u2c74\u2c76-\u2c7d\u2c81\u2c83\u2c85\u2c87\u2c89\u2c8b\u2c8d\u2c8f\u2c91\u2c93\u2c95\u2c97\u2c99\u2c9b\u2c9d\u2c9f\u2ca1\u2ca3\u2ca5\u2ca7\u2ca9\u2cab\u2cad\u2caf\u2cb1\u2cb3\u2cb5\u2cb7\u2cb9\u2cbb\u2cbd\u2cbf\u2cc1\u2cc3\u2cc5\u2cc7\u2cc9\u2ccb\u2ccd\u2ccf\u2cd1\u2cd3\u2cd5\u2cd7\u2cd9\u2cdb\u2cdd\u2cdf\u2ce1\u2ce3\u2ce4\u2cec\u2cee\u2cf3\u2d00-\u2d25\u2d27\u2d2d\ua641\ua643\ua645\ua647\ua649\ua64b\ua64d\ua64f\ua651\ua653\ua655\ua657\ua659\ua65b\ua65d\ua65f\ua661\ua663\ua665\ua667\ua669\ua66b\ua66d\ua681\ua683\ua685\ua687\ua689\ua68b\ua68d\ua68f\ua691\ua693\ua695\ua697\ua699\ua69b-\ua69d\ua723\ua725\ua727\ua729\ua72b\ua72d\ua72f-\ua731\ua733\ua735\ua737\ua739\ua73b\ua73d\ua73f\ua741\ua743\ua745\ua747\ua749\ua74b\ua74d\ua74f\ua751\ua753\ua755\ua757\ua759\ua75b\ua75d\ua75f\ua761\ua763\ua765\ua767\ua769\ua76b\ua76d\ua76f-\ua778\ua77a\ua77c\ua77f\ua781\ua783\ua785\ua787\ua78c\ua78e\ua791\ua793-\ua795\ua797\ua799\ua79b\ua79d\ua79f\ua7a1\ua7a3\ua7a5\ua7a7\ua7a9\ua7b5\ua7b7\ua7f8-\ua7fa\uab30-\uab5a\uab5c-\uab65\uab70-\uabbf\ufb00-\ufb06\ufb13-\ufb17\uff41-\uff5a",astral:"\ud801[\udc28-\udc4f\udcd8-\udcfb]|\ud803[\udcc0-\udcf2]|\ud806[\udcc0-\udcdf]|\ud835[\udc1a-\udc33\udc4e-\udc54\udc56-\udc67\udc82-\udc9b\udcb6-\udcb9\udcbb\udcbd-\udcc3\udcc5-\udccf\udcea-\udd03\udd1e-\udd37\udd52-\udd6b\udd86-\udd9f\uddba-\uddd3\uddee-\ude07\ude22-\ude3b\ude56-\ude6f\ude8a-\udea5\udec2-\udeda\udedc-\udee1\udefc-\udf14\udf16-\udf1b\udf36-\udf4e\udf50-\udf55\udf70-\udf88\udf8a-\udf8f\udfaa-\udfc2\udfc4-\udfc9\udfcb]|\ud83a[\udd22-\udd43]"},{name:"Noncharacter_Code_Point",bmp:"\ufdd0-\ufdef\ufffe\uffff",astral:"[\ud83f\ud87f\ud8bf\ud8ff\ud93f\ud97f\ud9bf\ud9ff\uda3f\uda7f\udabf\udaff\udb3f\udb7f\udbbf\udbff][\udffe\udfff]"},{name:"Uppercase",bmp:"A-Z\xc0-\xd6\xd8-\xde\u0100\u0102\u0104\u0106\u0108\u010a\u010c\u010e\u0110\u0112\u0114\u0116\u0118\u011a\u011c\u011e\u0120\u0122\u0124\u0126\u0128\u012a\u012c\u012e\u0130\u0132\u0134\u0136\u0139\u013b\u013d\u013f\u0141\u0143\u0145\u0147\u014a\u014c\u014e\u0150\u0152\u0154\u0156\u0158\u015a\u015c\u015e\u0160\u0162\u0164\u0166\u0168\u016a\u016c\u016e\u0170\u0172\u0174\u0176\u0178\u0179\u017b\u017d\u0181\u0182\u0184\u0186\u0187\u0189-\u018b\u018e-\u0191\u0193\u0194\u0196-\u0198\u019c\u019d\u019f\u01a0\u01a2\u01a4\u01a6\u01a7\u01a9\u01ac\u01ae\u01af\u01b1-\u01b3\u01b5\u01b7\u01b8\u01bc\u01c4\u01c7\u01ca\u01cd\u01cf\u01d1\u01d3\u01d5\u01d7\u01d9\u01db\u01de\u01e0\u01e2\u01e4\u01e6\u01e8\u01ea\u01ec\u01ee\u01f1\u01f4\u01f6-\u01f8\u01fa\u01fc\u01fe\u0200\u0202\u0204\u0206\u0208\u020a\u020c\u020e\u0210\u0212\u0214\u0216\u0218\u021a\u021c\u021e\u0220\u0222\u0224\u0226\u0228\u022a\u022c\u022e\u0230\u0232\u023a\u023b\u023d\u023e\u0241\u0243-\u0246\u0248\u024a\u024c\u024e\u0370\u0372\u0376\u037f\u0386\u0388-\u038a\u038c\u038e\u038f\u0391-\u03a1\u03a3-\u03ab\u03cf\u03d2-\u03d4\u03d8\u03da\u03dc\u03de\u03e0\u03e2\u03e4\u03e6\u03e8\u03ea\u03ec\u03ee\u03f4\u03f7\u03f9\u03fa\u03fd-\u042f\u0460\u0462\u0464\u0466\u0468\u046a\u046c\u046e\u0470\u0472\u0474\u0476\u0478\u047a\u047c\u047e\u0480\u048a\u048c\u048e\u0490\u0492\u0494\u0496\u0498\u049a\u049c\u049e\u04a0\u04a2\u04a4\u04a6\u04a8\u04aa\u04ac\u04ae\u04b0\u04b2\u04b4\u04b6\u04b8\u04ba\u04bc\u04be\u04c0\u04c1\u04c3\u04c5\u04c7\u04c9\u04cb\u04cd\u04d0\u04d2\u04d4\u04d6\u04d8\u04da\u04dc\u04de\u04e0\u04e2\u04e4\u04e6\u04e8\u04ea\u04ec\u04ee\u04f0\u04f2\u04f4\u04f6\u04f8\u04fa\u04fc\u04fe\u0500\u0502\u0504\u0506\u0508\u050a\u050c\u050e\u0510\u0512\u0514\u0516\u0518\u051a\u051c\u051e\u0520\u0522\u0524\u0526\u0528\u052a\u052c\u052e\u0531-\u0556\u10a0-\u10c5\u10c7\u10cd\u13a0-\u13f5\u1e00\u1e02\u1e04\u1e06\u1e08\u1e0a\u1e0c\u1e0e\u1e10\u1e12\u1e14\u1e16\u1e18\u1e1a\u1e1c\u1e1e\u1e20\u1e22\u1e24\u1e26\u1e28\u1e2a\u1e2c\u1e2e\u1e30\u1e32\u1e34\u1e36\u1e38\u1e3a\u1e3c\u1e3e\u1e40\u1e42\u1e44\u1e46\u1e48\u1e4a\u1e4c\u1e4e\u1e50\u1e52\u1e54\u1e56\u1e58\u1e5a\u1e5c\u1e5e\u1e60\u1e62\u1e64\u1e66\u1e68\u1e6a\u1e6c\u1e6e\u1e70\u1e72\u1e74\u1e76\u1e78\u1e7a\u1e7c\u1e7e\u1e80\u1e82\u1e84\u1e86\u1e88\u1e8a\u1e8c\u1e8e\u1e90\u1e92\u1e94\u1e9e\u1ea0\u1ea2\u1ea4\u1ea6\u1ea8\u1eaa\u1eac\u1eae\u1eb0\u1eb2\u1eb4\u1eb6\u1eb8\u1eba\u1ebc\u1ebe\u1ec0\u1ec2\u1ec4\u1ec6\u1ec8\u1eca\u1ecc\u1ece\u1ed0\u1ed2\u1ed4\u1ed6\u1ed8\u1eda\u1edc\u1ede\u1ee0\u1ee2\u1ee4\u1ee6\u1ee8\u1eea\u1eec\u1eee\u1ef0\u1ef2\u1ef4\u1ef6\u1ef8\u1efa\u1efc\u1efe\u1f08-\u1f0f\u1f18-\u1f1d\u1f28-\u1f2f\u1f38-\u1f3f\u1f48-\u1f4d\u1f59\u1f5b\u1f5d\u1f5f\u1f68-\u1f6f\u1fb8-\u1fbb\u1fc8-\u1fcb\u1fd8-\u1fdb\u1fe8-\u1fec\u1ff8-\u1ffb\u2102\u2107\u210b-\u210d\u2110-\u2112\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u2130-\u2133\u213e\u213f\u2145\u2160-\u216f\u2183\u24b6-\u24cf\u2c00-\u2c2e\u2c60\u2c62-\u2c64\u2c67\u2c69\u2c6b\u2c6d-\u2c70\u2c72\u2c75\u2c7e-\u2c80\u2c82\u2c84\u2c86\u2c88\u2c8a\u2c8c\u2c8e\u2c90\u2c92\u2c94\u2c96\u2c98\u2c9a\u2c9c\u2c9e\u2ca0\u2ca2\u2ca4\u2ca6\u2ca8\u2caa\u2cac\u2cae\u2cb0\u2cb2\u2cb4\u2cb6\u2cb8\u2cba\u2cbc\u2cbe\u2cc0\u2cc2\u2cc4\u2cc6\u2cc8\u2cca\u2ccc\u2cce\u2cd0\u2cd2\u2cd4\u2cd6\u2cd8\u2cda\u2cdc\u2cde\u2ce0\u2ce2\u2ceb\u2ced\u2cf2\ua640\ua642\ua644\ua646\ua648\ua64a\ua64c\ua64e\ua650\ua652\ua654\ua656\ua658\ua65a\ua65c\ua65e\ua660\ua662\ua664\ua666\ua668\ua66a\ua66c\ua680\ua682\ua684\ua686\ua688\ua68a\ua68c\ua68e\ua690\ua692\ua694\ua696\ua698\ua69a\ua722\ua724\ua726\ua728\ua72a\ua72c\ua72e\ua732\ua734\ua736\ua738\ua73a\ua73c\ua73e\ua740\ua742\ua744\ua746\ua748\ua74a\ua74c\ua74e\ua750\ua752\ua754\ua756\ua758\ua75a\ua75c\ua75e\ua760\ua762\ua764\ua766\ua768\ua76a\ua76c\ua76e\ua779\ua77b\ua77d\ua77e\ua780\ua782\ua784\ua786\ua78b\ua78d\ua790\ua792\ua796\ua798\ua79a\ua79c\ua79e\ua7a0\ua7a2\ua7a4\ua7a6\ua7a8\ua7aa-\ua7ae\ua7b0-\ua7b4\ua7b6\uff21-\uff3a",astral:"\ud801[\udc00-\udc27\udcb0-\udcd3]|\ud803[\udc80-\udcb2]|\ud806[\udca0-\udcbf]|\ud835[\udc00-\udc19\udc34-\udc4d\udc68-\udc81\udc9c\udc9e\udc9f\udca2\udca5\udca6\udca9-\udcac\udcae-\udcb5\udcd0-\udce9\udd04\udd05\udd07-\udd0a\udd0d-\udd14\udd16-\udd1c\udd38\udd39\udd3b-\udd3e\udd40-\udd44\udd46\udd4a-\udd50\udd6c-\udd85\udda0-\uddb9\uddd4-\udded\ude08-\ude21\ude3c-\ude55\ude70-\ude89\udea8-\udec0\udee2-\udefa\udf1c-\udf34\udf56-\udf6e\udf90-\udfa8\udfca]|\ud83a[\udd00-\udd21]|\ud83c[\udd30-\udd49\udd50-\udd69\udd70-\udd89]"},{name:"White_Space",bmp:"\t-\r \x85\xa0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000"}];u.push({name:"Assigned",inverseOf:"Cn"}),e.addUnicodeData(u)},e.exports=u.default},502:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0}),u.default=function(e){if(!e.addUnicodeData)throw new ReferenceError("Unicode Base must be loaded before Unicode Scripts");e.addUnicodeData([{name:"Adlam",astral:"\ud83a[\udd00-\udd4a\udd50-\udd59\udd5e\udd5f]"},{name:"Ahom",astral:"\ud805[\udf00-\udf19\udf1d-\udf2b\udf30-\udf3f]"},{name:"Anatolian_Hieroglyphs",astral:"\ud811[\udc00-\ude46]"},{name:"Arabic",bmp:"\u0600-\u0604\u0606-\u060b\u060d-\u061a\u061e\u0620-\u063f\u0641-\u064a\u0656-\u066f\u0671-\u06dc\u06de-\u06ff\u0750-\u077f\u08a0-\u08b4\u08b6-\u08bd\u08d4-\u08e1\u08e3-\u08ff\ufb50-\ufbc1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfd\ufe70-\ufe74\ufe76-\ufefc",astral:"\ud803[\ude60-\ude7e]|\ud83b[\ude00-\ude03\ude05-\ude1f\ude21\ude22\ude24\ude27\ude29-\ude32\ude34-\ude37\ude39\ude3b\ude42\ude47\ude49\ude4b\ude4d-\ude4f\ude51\ude52\ude54\ude57\ude59\ude5b\ude5d\ude5f\ude61\ude62\ude64\ude67-\ude6a\ude6c-\ude72\ude74-\ude77\ude79-\ude7c\ude7e\ude80-\ude89\ude8b-\ude9b\udea1-\udea3\udea5-\udea9\udeab-\udebb\udef0\udef1]"},{name:"Armenian",bmp:"\u0531-\u0556\u0559-\u055f\u0561-\u0587\u058a\u058d-\u058f\ufb13-\ufb17"},{name:"Avestan",astral:"\ud802[\udf00-\udf35\udf39-\udf3f]"},{name:"Balinese",bmp:"\u1b00-\u1b4b\u1b50-\u1b7c"},{name:"Bamum",bmp:"\ua6a0-\ua6f7",astral:"\ud81a[\udc00-\ude38]"},{name:"Bassa_Vah",astral:"\ud81a[\uded0-\udeed\udef0-\udef5]"},{name:"Batak",bmp:"\u1bc0-\u1bf3\u1bfc-\u1bff"},{name:"Bengali",bmp:"\u0980-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09fb"},{name:"Bhaiksuki",astral:"\ud807[\udc00-\udc08\udc0a-\udc36\udc38-\udc45\udc50-\udc6c]"},{name:"Bopomofo",bmp:"\u02ea\u02eb\u3105-\u312d\u31a0-\u31ba"},{name:"Brahmi",astral:"\ud804[\udc00-\udc4d\udc52-\udc6f\udc7f]"},{name:"Braille",bmp:"\u2800-\u28ff"},{name:"Buginese",bmp:"\u1a00-\u1a1b\u1a1e\u1a1f"},{name:"Buhid",bmp:"\u1740-\u1753"},{name:"Canadian_Aboriginal",bmp:"\u1400-\u167f\u18b0-\u18f5"},{name:"Carian",astral:"\ud800[\udea0-\uded0]"},{name:"Caucasian_Albanian",astral:"\ud801[\udd30-\udd63\udd6f]"},{name:"Chakma",astral:"\ud804[\udd00-\udd34\udd36-\udd43]"},{name:"Cham",bmp:"\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa5c-\uaa5f"},{name:"Cherokee",bmp:"\u13a0-\u13f5\u13f8-\u13fd\uab70-\uabbf"},{name:"Common",bmp:"\0-@\\x5B-`\\x7B-\xa9\xab-\xb9\xbb-\xbf\xd7\xf7\u02b9-\u02df\u02e5-\u02e9\u02ec-\u02ff\u0374\u037e\u0385\u0387\u0589\u0605\u060c\u061b\u061c\u061f\u0640\u06dd\u08e2\u0964\u0965\u0e3f\u0fd5-\u0fd8\u10fb\u16eb-\u16ed\u1735\u1736\u1802\u1803\u1805\u1cd3\u1ce1\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u2000-\u200b\u200e-\u2064\u2066-\u2070\u2074-\u207e\u2080-\u208e\u20a0-\u20be\u2100-\u2125\u2127-\u2129\u212c-\u2131\u2133-\u214d\u214f-\u215f\u2189-\u218b\u2190-\u23fe\u2400-\u2426\u2440-\u244a\u2460-\u27ff\u2900-\u2b73\u2b76-\u2b95\u2b98-\u2bb9\u2bbd-\u2bc8\u2bca-\u2bd1\u2bec-\u2bef\u2e00-\u2e44\u2ff0-\u2ffb\u3000-\u3004\u3006\u3008-\u3020\u3030-\u3037\u303c-\u303f\u309b\u309c\u30a0\u30fb\u30fc\u3190-\u319f\u31c0-\u31e3\u3220-\u325f\u327f-\u32cf\u3358-\u33ff\u4dc0-\u4dff\ua700-\ua721\ua788-\ua78a\ua830-\ua839\ua92e\ua9cf\uab5b\ufd3e\ufd3f\ufe10-\ufe19\ufe30-\ufe52\ufe54-\ufe66\ufe68-\ufe6b\ufeff\uff01-\uff20\uff3b-\uff40\uff5b-\uff65\uff70\uff9e\uff9f\uffe0-\uffe6\uffe8-\uffee\ufff9-\ufffd",astral:"\ud800[\udd00-\udd02\udd07-\udd33\udd37-\udd3f\udd90-\udd9b\uddd0-\uddfc\udee1-\udefb]|\ud82f[\udca0-\udca3]|\ud834[\udc00-\udcf5\udd00-\udd26\udd29-\udd66\udd6a-\udd7a\udd83\udd84\udd8c-\udda9\uddae-\udde8\udf00-\udf56\udf60-\udf71]|\ud835[\udc00-\udc54\udc56-\udc9c\udc9e\udc9f\udca2\udca5\udca6\udca9-\udcac\udcae-\udcb9\udcbb\udcbd-\udcc3\udcc5-\udd05\udd07-\udd0a\udd0d-\udd14\udd16-\udd1c\udd1e-\udd39\udd3b-\udd3e\udd40-\udd44\udd46\udd4a-\udd50\udd52-\udea5\udea8-\udfcb\udfce-\udfff]|\ud83c[\udc00-\udc2b\udc30-\udc93\udca0-\udcae\udcb1-\udcbf\udcc1-\udccf\udcd1-\udcf5\udd00-\udd0c\udd10-\udd2e\udd30-\udd6b\udd70-\uddac\udde6-\uddff\ude01\ude02\ude10-\ude3b\ude40-\ude48\ude50\ude51\udf00-\udfff]|\ud83d[\udc00-\uded2\udee0-\udeec\udef0-\udef6\udf00-\udf73\udf80-\udfd4]|\ud83e[\udc00-\udc0b\udc10-\udc47\udc50-\udc59\udc60-\udc87\udc90-\udcad\udd10-\udd1e\udd20-\udd27\udd30\udd33-\udd3e\udd40-\udd4b\udd50-\udd5e\udd80-\udd91\uddc0]|\udb40[\udc01\udc20-\udc7f]"},{name:"Coptic",bmp:"\u03e2-\u03ef\u2c80-\u2cf3\u2cf9-\u2cff"},{name:"Cuneiform",astral:"\ud808[\udc00-\udf99]|\ud809[\udc00-\udc6e\udc70-\udc74\udc80-\udd43]"},{name:"Cypriot",astral:"\ud802[\udc00-\udc05\udc08\udc0a-\udc35\udc37\udc38\udc3c\udc3f]"},{name:"Cyrillic",bmp:"\u0400-\u0484\u0487-\u052f\u1c80-\u1c88\u1d2b\u1d78\u2de0-\u2dff\ua640-\ua69f\ufe2e\ufe2f"},{name:"Deseret",astral:"\ud801[\udc00-\udc4f]"},{name:"Devanagari",bmp:"\u0900-\u0950\u0953-\u0963\u0966-\u097f\ua8e0-\ua8fd"},{name:"Duployan",astral:"\ud82f[\udc00-\udc6a\udc70-\udc7c\udc80-\udc88\udc90-\udc99\udc9c-\udc9f]"},{name:"Egyptian_Hieroglyphs",astral:"\ud80c[\udc00-\udfff]|\ud80d[\udc00-\udc2e]"},{name:"Elbasan",astral:"\ud801[\udd00-\udd27]"},{name:"Ethiopic",bmp:"\u1200-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u137c\u1380-\u1399\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e"},{name:"Georgian",bmp:"\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u10ff\u2d00-\u2d25\u2d27\u2d2d"},{name:"Glagolitic",bmp:"\u2c00-\u2c2e\u2c30-\u2c5e",astral:"\ud838[\udc00-\udc06\udc08-\udc18\udc1b-\udc21\udc23\udc24\udc26-\udc2a]"},{name:"Gothic",astral:"\ud800[\udf30-\udf4a]"},{name:"Grantha",astral:"\ud804[\udf00-\udf03\udf05-\udf0c\udf0f\udf10\udf13-\udf28\udf2a-\udf30\udf32\udf33\udf35-\udf39\udf3c-\udf44\udf47\udf48\udf4b-\udf4d\udf50\udf57\udf5d-\udf63\udf66-\udf6c\udf70-\udf74]"},{name:"Greek",bmp:"\u0370-\u0373\u0375-\u0377\u037a-\u037d\u037f\u0384\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03e1\u03f0-\u03ff\u1d26-\u1d2a\u1d5d-\u1d61\u1d66-\u1d6a\u1dbf\u1f00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fc4\u1fc6-\u1fd3\u1fd6-\u1fdb\u1fdd-\u1fef\u1ff2-\u1ff4\u1ff6-\u1ffe\u2126\uab65",astral:"\ud800[\udd40-\udd8e\udda0]|\ud834[\ude00-\ude45]"},{name:"Gujarati",bmp:"\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0af1\u0af9"},{name:"Gurmukhi",bmp:"\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75"},{name:"Han",bmp:"\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u3005\u3007\u3021-\u3029\u3038-\u303b\u3400-\u4db5\u4e00-\u9fd5\uf900-\ufa6d\ufa70-\ufad9",astral:"[\ud840-\ud868\ud86a-\ud86c\ud86f-\ud872][\udc00-\udfff]|\ud869[\udc00-\uded6\udf00-\udfff]|\ud86d[\udc00-\udf34\udf40-\udfff]|\ud86e[\udc00-\udc1d\udc20-\udfff]|\ud873[\udc00-\udea1]|\ud87e[\udc00-\ude1d]"},{name:"Hangul",bmp:"\u1100-\u11ff\u302e\u302f\u3131-\u318e\u3200-\u321e\u3260-\u327e\ua960-\ua97c\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uffa0-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc"},{name:"Hanunoo",bmp:"\u1720-\u1734"},{name:"Hatran",astral:"\ud802[\udce0-\udcf2\udcf4\udcf5\udcfb-\udcff]"},{name:"Hebrew",bmp:"\u0591-\u05c7\u05d0-\u05ea\u05f0-\u05f4\ufb1d-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufb4f"},{name:"Hiragana",bmp:"\u3041-\u3096\u309d-\u309f",astral:"\ud82c\udc01|\ud83c\ude00"},{name:"Imperial_Aramaic",astral:"\ud802[\udc40-\udc55\udc57-\udc5f]"},{name:"Inherited",bmp:"\u0300-\u036f\u0485\u0486\u064b-\u0655\u0670\u0951\u0952\u1ab0-\u1abe\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1cf4\u1cf8\u1cf9\u1dc0-\u1df5\u1dfb-\u1dff\u200c\u200d\u20d0-\u20f0\u302a-\u302d\u3099\u309a\ufe00-\ufe0f\ufe20-\ufe2d",astral:"\ud800[\uddfd\udee0]|\ud834[\udd67-\udd69\udd7b-\udd82\udd85-\udd8b\uddaa-\uddad]|\udb40[\udd00-\uddef]"},{name:"Inscriptional_Pahlavi",astral:"\ud802[\udf60-\udf72\udf78-\udf7f]"},{name:"Inscriptional_Parthian",astral:"\ud802[\udf40-\udf55\udf58-\udf5f]"},{name:"Javanese",bmp:"\ua980-\ua9cd\ua9d0-\ua9d9\ua9de\ua9df"},{name:"Kaithi",astral:"\ud804[\udc80-\udcc1]"},{name:"Kannada",bmp:"\u0c80-\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2"},{name:"Katakana",bmp:"\u30a1-\u30fa\u30fd-\u30ff\u31f0-\u31ff\u32d0-\u32fe\u3300-\u3357\uff66-\uff6f\uff71-\uff9d",astral:"\ud82c\udc00"},{name:"Kayah_Li",bmp:"\ua900-\ua92d\ua92f"},{name:"Kharoshthi",astral:"\ud802[\ude00-\ude03\ude05\ude06\ude0c-\ude13\ude15-\ude17\ude19-\ude33\ude38-\ude3a\ude3f-\ude47\ude50-\ude58]"},{name:"Khmer",bmp:"\u1780-\u17dd\u17e0-\u17e9\u17f0-\u17f9\u19e0-\u19ff"},{name:"Khojki",astral:"\ud804[\ude00-\ude11\ude13-\ude3e]"},{name:"Khudawadi",astral:"\ud804[\udeb0-\udeea\udef0-\udef9]"},{name:"Lao",bmp:"\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf"},{name:"Latin",bmp:"A-Za-z\xaa\xba\xc0-\xd6\xd8-\xf6\xf8-\u02b8\u02e0-\u02e4\u1d00-\u1d25\u1d2c-\u1d5c\u1d62-\u1d65\u1d6b-\u1d77\u1d79-\u1dbe\u1e00-\u1eff\u2071\u207f\u2090-\u209c\u212a\u212b\u2132\u214e\u2160-\u2188\u2c60-\u2c7f\ua722-\ua787\ua78b-\ua7ae\ua7b0-\ua7b7\ua7f7-\ua7ff\uab30-\uab5a\uab5c-\uab64\ufb00-\ufb06\uff21-\uff3a\uff41-\uff5a"},{name:"Lepcha",bmp:"\u1c00-\u1c37\u1c3b-\u1c49\u1c4d-\u1c4f"},{name:"Limbu",bmp:"\u1900-\u191e\u1920-\u192b\u1930-\u193b\u1940\u1944-\u194f"},{name:"Linear_A",astral:"\ud801[\ude00-\udf36\udf40-\udf55\udf60-\udf67]"},{name:"Linear_B",astral:"\ud800[\udc00-\udc0b\udc0d-\udc26\udc28-\udc3a\udc3c\udc3d\udc3f-\udc4d\udc50-\udc5d\udc80-\udcfa]"},{name:"Lisu",bmp:"\ua4d0-\ua4ff"},{name:"Lycian",astral:"\ud800[\ude80-\ude9c]"},{name:"Lydian",astral:"\ud802[\udd20-\udd39\udd3f]"},{name:"Mahajani",astral:"\ud804[\udd50-\udd76]"},{name:"Malayalam",bmp:"\u0d01-\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4f\u0d54-\u0d63\u0d66-\u0d7f"},{name:"Mandaic",bmp:"\u0840-\u085b\u085e"},{name:"Manichaean",astral:"\ud802[\udec0-\udee6\udeeb-\udef6]"},{name:"Marchen",astral:"\ud807[\udc70-\udc8f\udc92-\udca7\udca9-\udcb6]"},{name:"Meetei_Mayek",bmp:"\uaae0-\uaaf6\uabc0-\uabed\uabf0-\uabf9"},{name:"Mende_Kikakui",astral:"\ud83a[\udc00-\udcc4\udcc7-\udcd6]"},{name:"Meroitic_Cursive",astral:"\ud802[\udda0-\uddb7\uddbc-\uddcf\uddd2-\uddff]"},{name:"Meroitic_Hieroglyphs",astral:"\ud802[\udd80-\udd9f]"},{name:"Miao",astral:"\ud81b[\udf00-\udf44\udf50-\udf7e\udf8f-\udf9f]"},{name:"Modi",astral:"\ud805[\ude00-\ude44\ude50-\ude59]"},{name:"Mongolian",bmp:"\u1800\u1801\u1804\u1806-\u180e\u1810-\u1819\u1820-\u1877\u1880-\u18aa",astral:"\ud805[\ude60-\ude6c]"},{name:"Mro",astral:"\ud81a[\ude40-\ude5e\ude60-\ude69\ude6e\ude6f]"},{name:"Multani",astral:"\ud804[\ude80-\ude86\ude88\ude8a-\ude8d\ude8f-\ude9d\ude9f-\udea9]"},{name:"Myanmar",bmp:"\u1000-\u109f\ua9e0-\ua9fe\uaa60-\uaa7f"},{name:"Nabataean",astral:"\ud802[\udc80-\udc9e\udca7-\udcaf]"},{name:"New_Tai_Lue",bmp:"\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19da\u19de\u19df"},{name:"Newa",astral:"\ud805[\udc00-\udc59\udc5b\udc5d]"},{name:"Nko",bmp:"\u07c0-\u07fa"},{name:"Ogham",bmp:"\u1680-\u169c"},{name:"Ol_Chiki",bmp:"\u1c50-\u1c7f"},{name:"Old_Hungarian",astral:"\ud803[\udc80-\udcb2\udcc0-\udcf2\udcfa-\udcff]"},{name:"Old_Italic",astral:"\ud800[\udf00-\udf23]"},{name:"Old_North_Arabian",astral:"\ud802[\ude80-\ude9f]"},{name:"Old_Permic",astral:"\ud800[\udf50-\udf7a]"},{name:"Old_Persian",astral:"\ud800[\udfa0-\udfc3\udfc8-\udfd5]"},{name:"Old_South_Arabian",astral:"\ud802[\ude60-\ude7f]"},{name:"Old_Turkic",astral:"\ud803[\udc00-\udc48]"},{name:"Oriya",bmp:"\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b77"},{name:"Osage",astral:"\ud801[\udcb0-\udcd3\udcd8-\udcfb]"},{name:"Osmanya",astral:"\ud801[\udc80-\udc9d\udca0-\udca9]"},{name:"Pahawh_Hmong",astral:"\ud81a[\udf00-\udf45\udf50-\udf59\udf5b-\udf61\udf63-\udf77\udf7d-\udf8f]"},{name:"Palmyrene",astral:"\ud802[\udc60-\udc7f]"},{name:"Pau_Cin_Hau",astral:"\ud806[\udec0-\udef8]"},{name:"Phags_Pa",bmp:"\ua840-\ua877"},{name:"Phoenician",astral:"\ud802[\udd00-\udd1b\udd1f]"},{name:"Psalter_Pahlavi",astral:"\ud802[\udf80-\udf91\udf99-\udf9c\udfa9-\udfaf]"},{name:"Rejang",bmp:"\ua930-\ua953\ua95f"},{name:"Runic",bmp:"\u16a0-\u16ea\u16ee-\u16f8"},{name:"Samaritan",bmp:"\u0800-\u082d\u0830-\u083e"},{name:"Saurashtra",bmp:"\ua880-\ua8c5\ua8ce-\ua8d9"},{name:"Sharada",astral:"\ud804[\udd80-\uddcd\uddd0-\udddf]"},{name:"Shavian",astral:"\ud801[\udc50-\udc7f]"},{name:"Siddham",astral:"\ud805[\udd80-\uddb5\uddb8-\udddd]"},{name:"SignWriting",astral:"\ud836[\udc00-\ude8b\ude9b-\ude9f\udea1-\udeaf]"},{name:"Sinhala",bmp:"\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2-\u0df4",astral:"\ud804[\udde1-\uddf4]"},{name:"Sora_Sompeng",astral:"\ud804[\udcd0-\udce8\udcf0-\udcf9]"},{name:"Sundanese",bmp:"\u1b80-\u1bbf\u1cc0-\u1cc7"},{name:"Syloti_Nagri",bmp:"\ua800-\ua82b"},{name:"Syriac",bmp:"\u0700-\u070d\u070f-\u074a\u074d-\u074f"},{name:"Tagalog",bmp:"\u1700-\u170c\u170e-\u1714"},{name:"Tagbanwa",bmp:"\u1760-\u176c\u176e-\u1770\u1772\u1773"},{name:"Tai_Le",bmp:"\u1950-\u196d\u1970-\u1974"},{name:"Tai_Tham",bmp:"\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa0-\u1aad"},{name:"Tai_Viet",bmp:"\uaa80-\uaac2\uaadb-\uaadf"},{name:"Takri",astral:"\ud805[\ude80-\udeb7\udec0-\udec9]"},{name:"Tamil",bmp:"\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bfa"},{name:"Tangut",astral:"\ud81b\udfe0|[\ud81c-\ud820][\udc00-\udfff]|\ud821[\udc00-\udfec]|\ud822[\udc00-\udef2]"},{name:"Telugu",bmp:"\u0c00-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58-\u0c5a\u0c60-\u0c63\u0c66-\u0c6f\u0c78-\u0c7f"},{name:"Thaana",bmp:"\u0780-\u07b1"},{name:"Thai",bmp:"\u0e01-\u0e3a\u0e40-\u0e5b"},{name:"Tibetan",bmp:"\u0f00-\u0f47\u0f49-\u0f6c\u0f71-\u0f97\u0f99-\u0fbc\u0fbe-\u0fcc\u0fce-\u0fd4\u0fd9\u0fda"},{name:"Tifinagh",bmp:"\u2d30-\u2d67\u2d6f\u2d70\u2d7f"},{name:"Tirhuta",astral:"\ud805[\udc80-\udcc7\udcd0-\udcd9]"},{name:"Ugaritic",astral:"\ud800[\udf80-\udf9d\udf9f]"},{name:"Vai",bmp:"\ua500-\ua62b"},{name:"Warang_Citi",astral:"\ud806[\udca0-\udcf2\udcff]"},{name:"Yi",bmp:"\ua000-\ua48c\ua490-\ua4c6"}])},e.exports=u.default},503:function(e,u,t){"use strict";var n=t(0),d=t.n(n);u.a=function(e){var u=e.text;return d.a.createElement("section",{className:"empty"},d.a.createElement("div",{className:"icon"},d.a.createElement("img",{src:"/img/logo-square.svg",alt:"The Qovery Logo"})),d.a.createElement("div",{className:"text"},u))}},504:function(e,u,t){"use strict";var n=t(505),d=t(515),r=t(471);e.exports={formats:r,parse:d,stringify:n}},505:function(e,u,t){"use strict";var n=t(506),d=t(478),r=t(471),a=Object.prototype.hasOwnProperty,c={brackets:function(e){return e+"[]"},comma:"comma",indices:function(e,u){return e+"["+u+"]"},repeat:function(e){return e}},o=Array.isArray,i=String.prototype.split,f=Array.prototype.push,l=function(e,u){f.apply(e,o(u)?u:[u])},s=Date.prototype.toISOString,p=r.default,m={addQueryPrefix:!1,allowDots:!1,charset:"utf-8",charsetSentinel:!1,delimiter:"&",encode:!0,encoder:d.encode,encodeValuesOnly:!1,format:p,formatter:r.formatters[p],indices:!1,serializeDate:function(e){return s.call(e)},skipNulls:!1,strictNullHandling:!1},h={},v=function e(u,t,r,a,c,f,s,p,v,b,y,g,_,x,w,E){for(var I,S=u,A=E,k=0,j=!1;void 0!==(A=A.get(h))&&!j;){var O=A.get(u);if(k+=1,void 0!==O){if(O===k)throw new RangeError("Cyclic object value");j=!0}void 0===A.get(h)&&(k=0)}if("function"==typeof p?S=p(t,S):S instanceof Date?S=y(S):"comma"===r&&o(S)&&(S=d.maybeMap(S,(function(e){return e instanceof Date?y(e):e}))),null===S){if(c)return s&&!x?s(t,m.encoder,w,"key",g):t;S=""}if("string"==typeof(I=S)||"number"==typeof I||"boolean"==typeof I||"symbol"==typeof I||"bigint"==typeof I||d.isBuffer(S)){if(s){var N=x?t:s(t,m.encoder,w,"key",g);if("comma"===r&&x){for(var C=i.call(String(S),","),P="",T=0;T0?S.join(",")||null:void 0}];else if(o(p))M=p;else{var L=Object.keys(S);M=v?L.sort(v):L}for(var F=a&&o(S)&&1===S.length?t+"[]":t,B=0;B0?x+_:""}},506:function(e,u,t){"use strict";var n=t(469),d=t(511),r=t(513),a=n("%TypeError%"),c=n("%WeakMap%",!0),o=n("%Map%",!0),i=d("WeakMap.prototype.get",!0),f=d("WeakMap.prototype.set",!0),l=d("WeakMap.prototype.has",!0),s=d("Map.prototype.get",!0),p=d("Map.prototype.set",!0),m=d("Map.prototype.has",!0),h=function(e,u){for(var t,n=e;null!==(t=n.next);n=t)if(t.key===u)return n.next=t.next,t.next=e.next,e.next=t,t};e.exports=function(){var e,u,t,n={assert:function(e){if(!n.has(e))throw new a("Side channel does not contain "+r(e))},get:function(n){if(c&&n&&("object"==typeof n||"function"==typeof n)){if(e)return i(e,n)}else if(o){if(u)return s(u,n)}else if(t)return function(e,u){var t=h(e,u);return t&&t.value}(t,n)},has:function(n){if(c&&n&&("object"==typeof n||"function"==typeof n)){if(e)return l(e,n)}else if(o){if(u)return m(u,n)}else if(t)return function(e,u){return!!h(e,u)}(t,n);return!1},set:function(n,d){c&&n&&("object"==typeof n||"function"==typeof n)?(e||(e=new c),f(e,n,d)):o?(u||(u=new o),p(u,n,d)):(t||(t={key:{},next:null}),function(e,u,t){var n=h(e,u);n?n.value=t:e.next={key:u,next:e.next,value:t}}(t,n,d))}};return n}},507:function(e,u,t){"use strict";var n="undefined"!=typeof Symbol&&Symbol,d=t(508);e.exports=function(){return"function"==typeof n&&("function"==typeof Symbol&&("symbol"==typeof n("foo")&&("symbol"==typeof Symbol("bar")&&d())))}},508:function(e,u,t){"use strict";e.exports=function(){if("function"!=typeof Symbol||"function"!=typeof Object.getOwnPropertySymbols)return!1;if("symbol"==typeof Symbol.iterator)return!0;var e={},u=Symbol("test"),t=Object(u);if("string"==typeof u)return!1;if("[object Symbol]"!==Object.prototype.toString.call(u))return!1;if("[object Symbol]"!==Object.prototype.toString.call(t))return!1;for(u in e[u]=42,e)return!1;if("function"==typeof Object.keys&&0!==Object.keys(e).length)return!1;if("function"==typeof Object.getOwnPropertyNames&&0!==Object.getOwnPropertyNames(e).length)return!1;var n=Object.getOwnPropertySymbols(e);if(1!==n.length||n[0]!==u)return!1;if(!Object.prototype.propertyIsEnumerable.call(e,u))return!1;if("function"==typeof Object.getOwnPropertyDescriptor){var d=Object.getOwnPropertyDescriptor(e,u);if(42!==d.value||!0!==d.enumerable)return!1}return!0}},509:function(e,u,t){"use strict";var n="Function.prototype.bind called on incompatible ",d=Array.prototype.slice,r=Object.prototype.toString;e.exports=function(e){var u=this;if("function"!=typeof u||"[object Function]"!==r.call(u))throw new TypeError(n+u);for(var t,a=d.call(arguments,1),c=function(){if(this instanceof t){var n=u.apply(this,a.concat(d.call(arguments)));return Object(n)===n?n:this}return u.apply(e,a.concat(d.call(arguments)))},o=Math.max(0,u.length-a.length),i=[],f=0;f-1?d(t):t}},512:function(e,u,t){"use strict";var n=t(470),d=t(469),r=d("%Function.prototype.apply%"),a=d("%Function.prototype.call%"),c=d("%Reflect.apply%",!0)||n.call(a,r),o=d("%Object.getOwnPropertyDescriptor%",!0),i=d("%Object.defineProperty%",!0),f=d("%Math.max%");if(i)try{i({},"a",{value:1})}catch(s){i=null}e.exports=function(e){var u=c(n,a,arguments);if(o&&i){var t=o(u,"length");t.configurable&&i(u,"length",{value:1+f(0,e.length-(arguments.length-1))})}return u};var l=function(){return c(n,r,arguments)};i?i(e.exports,"apply",{value:l}):e.exports.apply=l},513:function(e,u,t){var n="function"==typeof Map&&Map.prototype,d=Object.getOwnPropertyDescriptor&&n?Object.getOwnPropertyDescriptor(Map.prototype,"size"):null,r=n&&d&&"function"==typeof d.get?d.get:null,a=n&&Map.prototype.forEach,c="function"==typeof Set&&Set.prototype,o=Object.getOwnPropertyDescriptor&&c?Object.getOwnPropertyDescriptor(Set.prototype,"size"):null,i=c&&o&&"function"==typeof o.get?o.get:null,f=c&&Set.prototype.forEach,l="function"==typeof WeakMap&&WeakMap.prototype?WeakMap.prototype.has:null,s="function"==typeof WeakSet&&WeakSet.prototype?WeakSet.prototype.has:null,p="function"==typeof WeakRef&&WeakRef.prototype?WeakRef.prototype.deref:null,m=Boolean.prototype.valueOf,h=Object.prototype.toString,v=Function.prototype.toString,b=String.prototype.match,y=String.prototype.slice,g=String.prototype.replace,_=String.prototype.toUpperCase,x=String.prototype.toLowerCase,w=RegExp.prototype.test,E=Array.prototype.concat,I=Array.prototype.join,S=Array.prototype.slice,A=Math.floor,k="function"==typeof BigInt?BigInt.prototype.valueOf:null,j=Object.getOwnPropertySymbols,O="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?Symbol.prototype.toString:null,N="function"==typeof Symbol&&"object"==typeof Symbol.iterator,C="function"==typeof Symbol&&Symbol.toStringTag&&(typeof Symbol.toStringTag===N||"symbol")?Symbol.toStringTag:null,P=Object.prototype.propertyIsEnumerable,T=("function"==typeof Reflect?Reflect.getPrototypeOf:Object.getPrototypeOf)||([].__proto__===Array.prototype?function(e){return e.__proto__}:null);function M(e,u){if(e===1/0||e===-1/0||e!=e||e&&e>-1e3&&e<1e3||w.call(/e/,u))return u;var t=/[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;if("number"==typeof e){var n=e<0?-A(-e):A(e);if(n!==e){var d=String(n),r=y.call(u,d.length+1);return g.call(d,t,"$&_")+"."+g.call(g.call(r,/([0-9]{3})/g,"$&_"),/_$/,"")}}return g.call(u,t,"$&_")}var R=t(514),L=R.custom,F=W(L)?L:null;function B(e,u,t){var n="double"===(t.quoteStyle||u)?'"':"'";return n+e+n}function D(e){return g.call(String(e),/"/g,""")}function U(e){return!("[object Array]"!==q(e)||C&&"object"==typeof e&&C in e)}function z(e){return!("[object RegExp]"!==q(e)||C&&"object"==typeof e&&C in e)}function W(e){if(N)return e&&"object"==typeof e&&e instanceof Symbol;if("symbol"==typeof e)return!0;if(!e||"object"!=typeof e||!O)return!1;try{return O.call(e),!0}catch(u){}return!1}e.exports=function e(u,t,n,d){var c=t||{};if(G(c,"quoteStyle")&&"single"!==c.quoteStyle&&"double"!==c.quoteStyle)throw new TypeError('option "quoteStyle" must be "single" or "double"');if(G(c,"maxStringLength")&&("number"==typeof c.maxStringLength?c.maxStringLength<0&&c.maxStringLength!==1/0:null!==c.maxStringLength))throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`');var o=!G(c,"customInspect")||c.customInspect;if("boolean"!=typeof o&&"symbol"!==o)throw new TypeError("option \"customInspect\", if provided, must be `true`, `false`, or `'symbol'`");if(G(c,"indent")&&null!==c.indent&&"\t"!==c.indent&&!(parseInt(c.indent,10)===c.indent&&c.indent>0))throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`');if(G(c,"numericSeparator")&&"boolean"!=typeof c.numericSeparator)throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`');var h=c.numericSeparator;if(void 0===u)return"undefined";if(null===u)return"null";if("boolean"==typeof u)return u?"true":"false";if("string"==typeof u)return function e(u,t){if(u.length>t.maxStringLength){var n=u.length-t.maxStringLength,d="... "+n+" more character"+(n>1?"s":"");return e(y.call(u,0,t.maxStringLength),t)+d}return B(g.call(g.call(u,/(['\\])/g,"\\$1"),/[\x00-\x1f]/g,K),"single",t)}(u,c);if("number"==typeof u){if(0===u)return 1/0/u>0?"0":"-0";var _=String(u);return h?M(u,_):_}if("bigint"==typeof u){var w=String(u)+"n";return h?M(u,w):w}var A=void 0===c.depth?5:c.depth;if(void 0===n&&(n=0),n>=A&&A>0&&"object"==typeof u)return U(u)?"[Array]":"[Object]";var j=function(e,u){var t;if("\t"===e.indent)t="\t";else{if(!("number"==typeof e.indent&&e.indent>0))return null;t=I.call(Array(e.indent+1)," ")}return{base:t,prev:I.call(Array(u+1),t)}}(c,n);if(void 0===d)d=[];else if(H(d,u)>=0)return"[Circular]";function L(u,t,r){if(t&&(d=S.call(d)).push(t),r){var a={depth:c.depth};return G(c,"quoteStyle")&&(a.quoteStyle=c.quoteStyle),e(u,a,n+1,d)}return e(u,c,n+1,d)}if("function"==typeof u&&!z(u)){var $=function(e){if(e.name)return e.name;var u=b.call(v.call(e),/^function\s*([\w$]+)/);if(u)return u[1];return null}(u),X=Y(u,L);return"[Function"+($?": "+$:" (anonymous)")+"]"+(X.length>0?" { "+I.call(X,", ")+" }":"")}if(W(u)){var ee=N?g.call(String(u),/^(Symbol\(.*\))_[^)]*$/,"$1"):O.call(u);return"object"!=typeof u||N?ee:V(ee)}if(function(e){if(!e||"object"!=typeof e)return!1;if("undefined"!=typeof HTMLElement&&e instanceof HTMLElement)return!0;return"string"==typeof e.nodeName&&"function"==typeof e.getAttribute}(u)){for(var ue="<"+x.call(String(u.nodeName)),te=u.attributes||[],ne=0;ne"}if(U(u)){if(0===u.length)return"[]";var de=Y(u,L);return j&&!function(e){for(var u=0;u=0)return!1;return!0}(de)?"["+Q(de,j)+"]":"[ "+I.call(de,", ")+" ]"}if(function(e){return!("[object Error]"!==q(e)||C&&"object"==typeof e&&C in e)}(u)){var re=Y(u,L);return"cause"in Error.prototype||!("cause"in u)||P.call(u,"cause")?0===re.length?"["+String(u)+"]":"{ ["+String(u)+"] "+I.call(re,", ")+" }":"{ ["+String(u)+"] "+I.call(E.call("[cause]: "+L(u.cause),re),", ")+" }"}if("object"==typeof u&&o){if(F&&"function"==typeof u[F]&&R)return R(u,{depth:A-n});if("symbol"!==o&&"function"==typeof u.inspect)return u.inspect()}if(function(e){if(!r||!e||"object"!=typeof e)return!1;try{r.call(e);try{i.call(e)}catch(ue){return!0}return e instanceof Map}catch(u){}return!1}(u)){var ae=[];return a.call(u,(function(e,t){ae.push(L(t,u,!0)+" => "+L(e,u))})),Z("Map",r.call(u),ae,j)}if(function(e){if(!i||!e||"object"!=typeof e)return!1;try{i.call(e);try{r.call(e)}catch(u){return!0}return e instanceof Set}catch(t){}return!1}(u)){var ce=[];return f.call(u,(function(e){ce.push(L(e,u))})),Z("Set",i.call(u),ce,j)}if(function(e){if(!l||!e||"object"!=typeof e)return!1;try{l.call(e,l);try{s.call(e,s)}catch(ue){return!0}return e instanceof WeakMap}catch(u){}return!1}(u))return J("WeakMap");if(function(e){if(!s||!e||"object"!=typeof e)return!1;try{s.call(e,s);try{l.call(e,l)}catch(ue){return!0}return e instanceof WeakSet}catch(u){}return!1}(u))return J("WeakSet");if(function(e){if(!p||!e||"object"!=typeof e)return!1;try{return p.call(e),!0}catch(u){}return!1}(u))return J("WeakRef");if(function(e){return!("[object Number]"!==q(e)||C&&"object"==typeof e&&C in e)}(u))return V(L(Number(u)));if(function(e){if(!e||"object"!=typeof e||!k)return!1;try{return k.call(e),!0}catch(u){}return!1}(u))return V(L(k.call(u)));if(function(e){return!("[object Boolean]"!==q(e)||C&&"object"==typeof e&&C in e)}(u))return V(m.call(u));if(function(e){return!("[object String]"!==q(e)||C&&"object"==typeof e&&C in e)}(u))return V(L(String(u)));if(!function(e){return!("[object Date]"!==q(e)||C&&"object"==typeof e&&C in e)}(u)&&!z(u)){var oe=Y(u,L),ie=T?T(u)===Object.prototype:u instanceof Object||u.constructor===Object,fe=u instanceof Object?"":"null prototype",le=!ie&&C&&Object(u)===u&&C in u?y.call(q(u),8,-1):fe?"Object":"",se=(ie||"function"!=typeof u.constructor?"":u.constructor.name?u.constructor.name+" ":"")+(le||fe?"["+I.call(E.call([],le||[],fe||[]),": ")+"] ":"");return 0===oe.length?se+"{}":j?se+"{"+Q(oe,j)+"}":se+"{ "+I.call(oe,", ")+" }"}return String(u)};var $=Object.prototype.hasOwnProperty||function(e){return e in this};function G(e,u){return $.call(e,u)}function q(e){return h.call(e)}function H(e,u){if(e.indexOf)return e.indexOf(u);for(var t=0,n=e.length;t-1?e.split(","):e},i=function(e,u,t,n){if(e){var r=t.allowDots?e.replace(/\.([^.[]+)/g,"[$1]"):e,a=/(\[[^[\]]*])/g,c=t.depth>0&&/(\[[^[\]]*])/.exec(r),i=c?r.slice(0,c.index):r,f=[];if(i){if(!t.plainObjects&&d.call(Object.prototype,i)&&!t.allowPrototypes)return;f.push(i)}for(var l=0;t.depth>0&&null!==(c=a.exec(r))&&l=0;--r){var a,c=e[r];if("[]"===c&&t.parseArrays)a=[].concat(d);else{a=t.plainObjects?Object.create(null):{};var i="["===c.charAt(0)&&"]"===c.charAt(c.length-1)?c.slice(1,-1):c,f=parseInt(i,10);t.parseArrays||""!==i?!isNaN(f)&&c!==i&&String(f)===i&&f>=0&&t.parseArrays&&f<=t.arrayLimit?(a=[])[f]=d:"__proto__"!==i&&(a[i]=d):a={0:d}}d=a}return d}(f,u,t,n)}};e.exports=function(e,u){var t=function(e){if(!e)return a;if(null!==e.decoder&&void 0!==e.decoder&&"function"!=typeof e.decoder)throw new TypeError("Decoder has to be a function.");if(void 0!==e.charset&&"utf-8"!==e.charset&&"iso-8859-1"!==e.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var u=void 0===e.charset?a.charset:e.charset;return{allowDots:void 0===e.allowDots?a.allowDots:!!e.allowDots,allowPrototypes:"boolean"==typeof e.allowPrototypes?e.allowPrototypes:a.allowPrototypes,allowSparse:"boolean"==typeof e.allowSparse?e.allowSparse:a.allowSparse,arrayLimit:"number"==typeof e.arrayLimit?e.arrayLimit:a.arrayLimit,charset:u,charsetSentinel:"boolean"==typeof e.charsetSentinel?e.charsetSentinel:a.charsetSentinel,comma:"boolean"==typeof e.comma?e.comma:a.comma,decoder:"function"==typeof e.decoder?e.decoder:a.decoder,delimiter:"string"==typeof e.delimiter||n.isRegExp(e.delimiter)?e.delimiter:a.delimiter,depth:"number"==typeof e.depth||!1===e.depth?+e.depth:a.depth,ignoreQueryPrefix:!0===e.ignoreQueryPrefix,interpretNumericEntities:"boolean"==typeof e.interpretNumericEntities?e.interpretNumericEntities:a.interpretNumericEntities,parameterLimit:"number"==typeof e.parameterLimit?e.parameterLimit:a.parameterLimit,parseArrays:!1!==e.parseArrays,plainObjects:"boolean"==typeof e.plainObjects?e.plainObjects:a.plainObjects,strictNullHandling:"boolean"==typeof e.strictNullHandling?e.strictNullHandling:a.strictNullHandling}}(u);if(""===e||null==e)return t.plainObjects?Object.create(null):{};for(var f="string"==typeof e?function(e,u){var t,i={},f=u.ignoreQueryPrefix?e.replace(/^\?/,""):e,l=u.parameterLimit===1/0?void 0:u.parameterLimit,s=f.split(u.delimiter,l),p=-1,m=u.charset;if(u.charsetSentinel)for(t=0;t-1&&(v=r(v)?[v]:v),d.call(i,h)?i[h]=n.combine(i[h],v):i[h]=v}return i}(e,t):e,l=t.plainObjects?Object.create(null):{},s=Object.keys(f),p=0;p1?arguments[1]:void 0,3);t=t?t.n:this._f;)for(n(t.v,t.k,this);t&&t.r;)t=t.p},has:function(e){return!!v(m(this,u),e)}}),s&&n(f.prototype,"size",{get:function(){return m(this,u)[h]}}),f},def:function(e,u,t){var n,d,r=v(e,u);return r?r.v=t:(e._l=r={i:d=p(u,!0),k:u,v:t,p:n=e._l,n:void 0,r:!1},e._f||(e._f=r),n&&(n.n=r),e[h]++,"F"!==d&&(e._i[d]=r)),e},getEntry:v,setStrong:function(e,u,t){i(e,u,(function(e,t){this._t=m(e,u),this._k=t,this._l=void 0}),(function(){for(var e=this._k,u=this._l;u&&u.r;)u=u.p;return this._t&&(this._l=u=u?u.n:this._t._f)?f(0,"keys"==e?u.k:"values"==e?u.v:[u.k,u.v]):(this._t=void 0,f(1))}),t?"entries":"values",!t,!0),l(u)}}},547:function(e,u,t){"use strict";var n=t(5),d=t(12),r=t(16),a=t(82),c=t(491),o=t(81),i=t(80),f=t(13),l=t(14),s=t(83),p=t(41),m=t(548);e.exports=function(e,u,t,h,v,b){var y=n[e],g=y,_=v?"set":"add",x=g&&g.prototype,w={},E=function(e){var u=x[e];r(x,e,"delete"==e||"has"==e?function(e){return!(b&&!f(e))&&u.call(this,0===e?0:e)}:"get"==e?function(e){return b&&!f(e)?void 0:u.call(this,0===e?0:e)}:"add"==e?function(e){return u.call(this,0===e?0:e),this}:function(e,t){return u.call(this,0===e?0:e,t),this})};if("function"==typeof g&&(b||x.forEach&&!l((function(){(new g).entries().next()})))){var I=new g,S=I[_](b?{}:-0,1)!=I,A=l((function(){I.has(1)})),k=s((function(e){new g(e)})),j=!b&&l((function(){for(var e=new g,u=5;u--;)e[_](u,u);return!e.has(-0)}));k||((g=u((function(u,t){i(u,g,e);var n=m(new y,u,g);return null!=t&&o(t,v,n[_],n),n}))).prototype=x,x.constructor=g),(A||j)&&(E("delete"),E("has"),v&&E("get")),(j||S)&&E(_),b&&x.clear&&delete x.clear}else g=h.getConstructor(u,e,v,_),a(g.prototype,t),c.NEED=!0;return p(g,e),w[e]=g,d(d.G+d.W+d.F*(g!=y),w),b||h.setStrong(g,e,v),g}},548:function(e,u,t){var n=t(13),d=t(549).set;e.exports=function(e,u,t){var r,a=u.constructor;return a!==t&&"function"==typeof a&&(r=a.prototype)!==t.prototype&&n(r)&&d&&d(e,r),e}},549:function(e,u,t){var n=t(13),d=t(8),r=function(e,u){if(d(e),!n(u)&&null!==u)throw TypeError(u+": can't set as prototype!")};e.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(e,u,n){try{(n=t(30)(Function.call,t(550).f(Object.prototype,"__proto__").set,2))(e,[]),u=!(e instanceof Array)}catch(d){u=!0}return function(e,t){return r(e,t),u?e.__proto__=t:n(e,t),e}}({},!1):void 0),check:r}},550:function(e,u,t){var n=t(62),d=t(57),r=t(33),a=t(87),c=t(31),o=t(86),i=Object.getOwnPropertyDescriptor;u.f=t(10)?i:function(e,u){if(e=r(e),u=a(u,!0),o)try{return i(e,u)}catch(t){}if(c(e,u))return d(!n.f.call(e,u),e[u])}},551:function(e,u,t){"use strict";var n=t(12),d=t(32),r=t(27),a=t(14),c=[].sort,o=[1,2,3];n(n.P+n.F*(a((function(){o.sort(void 0)}))||!a((function(){o.sort(null)}))||!t(552)(c)),"Array",{sort:function(e){return void 0===e?c.call(r(this)):c.call(r(this),d(e))}})},552:function(e,u,t){"use strict";var n=t(14);e.exports=function(e,u){return!!e&&n((function(){u?e.call(null,(function(){}),1):e.call(null)}))}},561:function(e,u,t){"use strict";t(489),t(79),t(490),t(551),t(29),t(22),t(21),t(85),t(442);var n=t(1),d=(t(446),t(447),t(77),t(428),t(0)),r=t.n(d),a=t(481),c=t.n(a);t(150);var o=function(e){var u=e.humanize,t=e.icon,n=e.values,d=e.currentState,a=e.setState;if(0==n.size)return null;var o=Array.from(n);return r.a.createElement(r.a.Fragment,null,o.map((function(e,n){var o="string"==typeof e&&u?c()(e):e;return r.a.createElement("label",{key:n},r.a.createElement("input",{type:"checkbox",onChange:function(u){var t=new Set(d);u.currentTarget.checked?t.add(e):t.delete(e),a(t)},checked:d.has(e)}),o&&r.a.createElement(r.a.Fragment,null,t?r.a.createElement("i",{className:"feather icon-"+t}):""," ",o))})))},i=t(503),f=t(431),l=t(430),s=(t(440),t(451)),p=t.n(s),m=t(423),h=t.n(m),v=t(504),b=t.n(v),y=t(436);t(151);function g(e){var u=e.delivery_guarantee,t=e.description,n=e.event_types,d=e.function_category,a=(e.logo_path,e.name),c=e.pathTemplate,o=e.status,i=e.title,f=e.type,s=c;s||("source"==f&&(s="/docs/reference/sources//"),"transform"==f&&(s="/docs/reference/transforms//"),"sink"==f&&(s="/docs/reference/sinks//"));var p=s.replace("",a);return r.a.createElement(l.a,{to:p,className:"qovery-component",title:t},r.a.createElement("div",{className:"qovery-component--header"},r.a.createElement("div",{className:"qovery-component--name"},i)),r.a.createElement("div",{className:"qovery-component--badges"},"beta"==o?r.a.createElement("span",{className:"badge badge--warning",title:"This component is in beta and is not recommended for production environments"},r.a.createElement("i",{className:"feather icon-alert-triangle"})):r.a.createElement("span",{className:"badge badge--primary",title:"This component has passed reliability standards that make it production ready"},r.a.createElement("i",{className:"feather icon-award"})),"best_effort"==u?r.a.createElement("span",{className:"badge badge--warning",title:"This component makes a best-effort delivery guarantee, and in rare cases can lose data"},r.a.createElement("i",{className:"feather icon-shield-off"})):r.a.createElement("span",{className:"badge badge--primary",title:"This component offers an at-least-once delivery guarantee"},r.a.createElement("i",{className:"feather icon-shield"})),n.includes("log")?r.a.createElement("span",{className:"badge badge--primary",title:"This component works with log event types"},"log"):"",n.includes("metric")?r.a.createElement("span",{className:"badge badge--primary",title:"This component works with metric event types"},"metric"):"",r.a.createElement("span",{className:"badge badge--primary"},d)))}function _(e){var u=e.components,t=e.headingLevel,d=e.pathTemplate,a=e.titles,c=u.filter((function(e){return"source"==e.type})),o=u.filter((function(e){return"transform"==e.type})),l=u.filter((function(e){return"sink"==e.type})),s="h"+(t||3);return u.length>0?r.a.createElement(r.a.Fragment,null,c.length>0?r.a.createElement(r.a.Fragment,null,a&&r.a.createElement(s,null,c.length," Sources"),r.a.createElement("div",{className:"qovery-components--grid"},c.map((function(e,u){return r.a.createElement(g,Object(n.a)({key:u,pathTemplate:d},e))})))):"",o.length>0?r.a.createElement(r.a.Fragment,null,a&&r.a.createElement(s,null,o.length," Transforms"),r.a.createElement("div",{className:"qovery-components--grid"},o.map((function(e,u){return r.a.createElement(g,Object(n.a)({key:u,pathTemplate:d},e))})))):"",l.length>0?r.a.createElement(r.a.Fragment,null,a&&r.a.createElement(s,null,l.length," Sinks"),r.a.createElement("div",{className:"qovery-components--grid"},l.map((function(e,u){return r.a.createElement(g,Object(n.a)({key:u,pathTemplate:d},e))})))):"",r.a.createElement("hr",null),r.a.createElement(f.a,{to:"https://github.com/qovery/documentation/issues/new?labels=type%3A+new+feature",target:"_blank",rightIcon:"plus-circle"},"Request a new component")):r.a.createElement(i.a,{text:"no components found"})}u.a=function(e){var u=Object(y.a)().siteConfig.customFields.metadata,t=u.sources,n=u.transforms,a=u.sinks,c=e.titles||null==e.titles,i=1==e.filterColumn,f=e.pathTemplate,s=e.location?b.a.parse(e.location.search,{ignoreQueryPrefix:!0}):{},m=[];(e.sources||null==e.sources)&&(m=m.concat(Object.values(t))),(e.transforms||null==e.transforms)&&(m=m.concat(Object.values(n))),(e.sinks||null==e.sinks)&&(m=m.concat(Object.values(a))),m=m.sort((function(e,u){return e.name>u.name?1:-1}));var v=Object(d.useState)("true"==s["at-least-once"]),g=v[0],x=v[1],w=Object(d.useState)(new Set(s["event-types"]||e.eventTypes)),E=w[0],I=w[1],S=Object(d.useState)(new Set(s.functions)),A=S[0],k=S[1],j=Object(d.useState)(new Set(s["operating-systems"])),O=j[0],N=j[1],C=Object(d.useState)("true"==s["prod-ready"]),P=C[0],T=C[1],M=Object(d.useState)(new Set(s.providers)),R=M[0],L=M[1],F=Object(d.useState)(s.search),B=F[0],D=F[1];B&&(m=m.filter((function(e){return(e.name.toLowerCase()+" "+e.type.toLowerCase()).includes(B.toLowerCase())}))),g&&(m=m.filter((function(e){return"at_least_once"==e.delivery_guarantee}))),E.size>0&&(m=m.filter((function(e){return Array.from(E).some((function(u){return e.event_types.includes(u)}))}))),A.size>0&&(m=m.filter((function(e){return A.has(e.function_category)}))),O.size>0&&(m=m.filter((function(e){return Array.from(O).every((function(u){return e.operating_systems.includes(u)}))}))),P&&(m=m.filter((function(e){return"prod-ready"==e.status}))),R.size>0&&(m=m.filter((function(e){return Array.from(R).every((function(u){return e.service_providers&&e.service_providers.includes(u)}))}))),e.exceptNames&&e.exceptNames.length>0&&(m=m.filter((function(u){return!e.exceptNames.includes(u.name)}))),e.exceptFunctions&&e.exceptFunctions.length>0&&(m=m.filter((function(u){return!e.exceptFunctions.includes(u.function_category)})));var U=E.size>0?E:new Set(p()(m).map((function(e){return e.event_types})).flatten().uniq().compact().sort().value()),z=new Set(p()(m).map((function(e){return e.operating_systems})).flatten().uniq().compact().sort().value()),W=new Set(p()(m).map((function(e){return e.service_providers})).flatten().uniq().compact().sort().value()),$=new Set(p()(m).filter((function(e){return"source"==e.type})).map((function(e){return e.function_category})).uniq().compact().sort().value()),G=new Set(p()(m).filter((function(e){return"transform"==e.type})).map((function(e){return e.function_category})).uniq().compact().sort().value()),q=new Set(p()(m).filter((function(e){return"sink"==e.type})).map((function(e){return e.function_category})).uniq().compact().sort().value());return r.a.createElement("div",{className:h()("qovery-components",{"qovery-components--cols":i})},r.a.createElement("div",{className:"filters"},r.a.createElement("div",{className:"search"},r.a.createElement("input",{className:"input--text input--lg",type:"text",onChange:function(e){return D(e.currentTarget.value)},placeholder:"\ud83d\udd0d Search..."})),r.a.createElement("div",{className:"filter"},r.a.createElement("div",{className:"filter--label"},r.a.createElement(l.a,{to:"/docs/getting-started/data-model/",title:"Learn more about Qovery's event types"},"Event types ",r.a.createElement("i",{className:"feather icon-info"}))),r.a.createElement("div",{className:"filter--choices"},r.a.createElement(o,{label:"Event Types",icon:"database",values:U,humanize:!0,currentState:E,setState:I}))),r.a.createElement("div",{className:"filter"},r.a.createElement("div",{className:"filter--label"},r.a.createElement(l.a,{to:"/docs/getting-started/whats-next/",title:"Learn more about Qovery's guarantees"},"Guarantees ",r.a.createElement("i",{className:"feather icon-info"}))),r.a.createElement("div",{className:"filter--choices"},r.a.createElement("label",{title:"Show only components that offer an at-least-once delivery guarantee."},r.a.createElement("input",{type:"checkbox",onChange:function(e){return x(e.currentTarget.checked)},checked:g}),r.a.createElement("i",{className:"feather icon-shield"})," At-least-once"),r.a.createElement("label",{title:"Show only production ready components."},r.a.createElement("input",{type:"checkbox",onChange:function(e){return T(e.currentTarget.checked)},checked:P}),r.a.createElement("i",{className:"feather icon-award"})," Prod-ready"))),$.size>0&&r.a.createElement("div",{className:"filter"},r.a.createElement("div",{className:"filter--label"},"Source Functions"),r.a.createElement("div",{className:"filter--choices"},r.a.createElement(o,{label:"Functions",icon:"settings",values:$,humanize:!0,currentState:A,setState:k}))),G.size>0&&r.a.createElement("div",{className:"filter"},r.a.createElement("div",{className:"filter--label"},"Transform Functions"),r.a.createElement("div",{className:"filter--choices"},r.a.createElement(o,{label:"Functions",icon:"settings",values:G,humanize:!0,currentState:A,setState:k}))),q.size>0&&r.a.createElement("div",{className:"filter"},r.a.createElement("div",{className:"filter--label"},"Sink Functions"),r.a.createElement("div",{className:"filter--choices"},r.a.createElement(o,{label:"Functions",icon:"settings",values:q,humanize:!0,currentState:A,setState:k}))),W.size>0&&r.a.createElement("div",{className:"filter"},r.a.createElement("div",{className:"filter--label"},"Providers"),r.a.createElement("div",{className:"filter--choices"},r.a.createElement(o,{label:"Providers",icon:"cloud",values:W,currentState:R,setState:L}))),z.size>0&&r.a.createElement("div",{className:"filter"},r.a.createElement("div",{className:"filter--label"},r.a.createElement(l.a,{to:"/docs/setup/installation/operating-systems/",title:"Learn more about Qovery's operating systems"},"Operating Systems")),r.a.createElement("div",{className:"filter--choices"},r.a.createElement(o,{label:"Operating Systems",icon:"cpu",values:z,currentState:O,setState:N})))),r.a.createElement("div",{className:"qovery-components--results"},r.a.createElement(_,{components:m,headingLevel:e.headingLevel,pathTemplate:f,titles:c})))}}}]); \ No newline at end of file diff --git a/54e7632e.66383920.js.LICENSE.txt b/54e7632e.c06ee927.js.LICENSE.txt similarity index 100% rename from 54e7632e.66383920.js.LICENSE.txt rename to 54e7632e.c06ee927.js.LICENSE.txt diff --git a/e06f2af5.90c333c9.js b/55af4c9e.01a5e97b.js similarity index 93% rename from e06f2af5.90c333c9.js rename to 55af4c9e.01a5e97b.js index 35e81b44bc..398d5e0082 100644 --- a/e06f2af5.90c333c9.js +++ b/55af4c9e.01a5e97b.js @@ -1,2 +1,2 @@ -/*! For license information please see e06f2af5.90c333c9.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[236],{388:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),i=(n(0),n(422)),a=n(431),c={last_modified_on:"2021-09-06",$schema:"/.meta/.schemas/guides.json",title:"How to use Github Organizations with Qovery",description:"How to configure Github and Qovery to use your Github Organization repositories with Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},u={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to use Github Organizations with Qovery",description:"How to configure Github and Qovery to use your Github Organization repositories with Qovery",permalink:"/guides/tutorial/github-organization-repository-access",readingTime:"1 min read",source:"@site/guides/tutorial/github-organization-repository-access.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to use Github Organizations with Qovery",truncated:!1,prevItem:{title:"How to use CloudFront with a React frontend application on Qovery",permalink:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery"},nextItem:{title:"How To Use Lifecycle Job To Deploy Any Kind Of Resources",permalink:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources"}},s=[],l={rightToc:s};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"When you create a new application, you need to connect it to a Git repository.\nIf your code is stored in a Github Organization, Qovery needs privileges to access your Organization's repositories\nin order to run deployments."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/github-org-access-1.png",alt:"Github Organization"})),Object(i.b)("p",null,"If Organization repositories are missing in the repository selector, you will need to grant Qovery access to your organization."),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/settings/connections/applications/f54d3da8bad40800b3bf"}),"Qovery Github Application"))),Object(i.b)("li",null,Object(i.b)("p",null,"Make sure Qovery has access to the organization you want to use (grant permissions if necessary)"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/github-org-access-2.png",alt:"Github Organization"}))))),Object(i.b)("p",null,"After following the steps from above, you should be able to select your organization repositories in Qovery Console while creating an application."))}p.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,a=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(n),b=r,y=p["".concat(a,".").concat(b)]||p[b]||f[b]||i;return n?o.a.createElement(y,c({ref:t},s,{components:n})):o.a.createElement(y,c({ref:t},s))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=b;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,a[1]=c;for(var s=2;s=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,a=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(n),b=r,y=p["".concat(a,".").concat(b)]||p[b]||f[b]||i;return n?o.a.createElement(y,c({ref:t},s,{components:n})):o.a.createElement(y,c({ref:t},s))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=b;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,a[1]=c;for(var s=2;s=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,a=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(n),b=r,y=p["".concat(a,".").concat(b)]||p[b]||f[b]||i;return n?o.a.createElement(y,c({ref:t},s,{components:n})):o.a.createElement(y,c({ref:t},s))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=b;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,a[1]=c;for(var s=2;s=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),p=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},u=function(e){var t=p(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(i.forwardRef)((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,o=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),u=p(n),m=i,b=u["".concat(o,".").concat(m)]||u[m]||d[m]||r;return n?a.a.createElement(b,l({ref:t},s,{components:n})):a.a.createElement(b,l({ref:t},s))}));function b(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:i,o[1]=l;for(var s=2;s1?arguments[1]:void 0,n),c=o>2?arguments[2]:void 0,s=void 0===c?n:a(c,n);s>l;)t[l++]=e;return t}},428:function(e,t,n){var i=n(28).f,a=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in a||n(10)&&i(a,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var i=n(0),a=n.n(i),r=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var i=n(1),a=n(0),r=n.n(a),o=n(39),l=n(432),c=n(20),s=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,p=n||c,u=Object(l.a)(p),d=Object(a.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!m&&u&&window.docusaurus.prefetch(p),function(){m&&t&&t.disconnect()}}),[p,m,u]),p&&u?r.a.createElement(o.b,Object(i.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(p),d.current=!0)},innerRef:function(e){var n,i;m&&e&&u&&(n=e,i=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),i())}))}))).observe(n))},to:p})):r.a.createElement("a",Object(i.a)({},e,{href:p}))}},431:function(e,t,n){"use strict";var i=n(0),a=n.n(i),r=n(430),o=n(423),l=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,i=e.badge,o=e.leftIcon,c=e.rightIcon,s=e.size,p=e.target,u=e.to,d=l()("jump-to","jump-to--"+s,n),m=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},o&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+o})),a.a.createElement("div",{className:"jump-to--main"},i?a.a.createElement("span",{className:"badge badge--primary badge--right"},i):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return p?a.a.createElement("a",{href:u,target:p,className:d},m):a.a.createElement(r.a,{to:u,className:d},m)}},432:function(e,t,n){"use strict";function i(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return i}))}}]); \ No newline at end of file diff --git a/58379094.51fa5043.js.LICENSE.txt b/55ef6d6a.4a1758f9.js.LICENSE.txt similarity index 100% rename from 58379094.51fa5043.js.LICENSE.txt rename to 55ef6d6a.4a1758f9.js.LICENSE.txt diff --git a/55ef6d6a.7a5112f2.js b/55ef6d6a.7a5112f2.js deleted file mode 100644 index 64062614d8..0000000000 --- a/55ef6d6a.7a5112f2.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see 55ef6d6a.7a5112f2.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[99],{250:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return d}));var i=n(1),a=n(9),r=(n(0),n(422)),o=(n(429),n(421)),l=n(426),c={last_modified_on:"2023-04-27",title:"Deployment Pipeline",description:"Learn how to the Environment Deployment Pipeline works"},s={id:"using-qovery/deployment/deployment-pipeline",title:"Deployment Pipeline",description:"Learn how to the Environment Deployment Pipeline works",source:"@site/docs/using-qovery/deployment/deployment-pipeline.md",permalink:"/docs/using-qovery/deployment/deployment-pipeline",sidebar:"docs",previous:{title:"Deploying with your CI/CD",permalink:"/docs/using-qovery/deployment/deploying-with-ci-cd"},next:{title:"Deployment Actions",permalink:"/docs/using-qovery/deployment/deployment-actions"}},p=[{value:"Deployment of a stage",id:"deployment-of-a-stage",children:[]},{value:"Default Pipeline Setup",id:"default-pipeline-setup",children:[]},{value:"Visualizing and Modifying the Pipeline",id:"visualizing-and-modifying-the-pipeline",children:[]}],u={rightToc:p};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(r.b)("wrapper",Object(i.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)(l.a,{name:"documentation",mdxType:"Assumptions"},Object(r.b)("p",null,"You have created an ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment")," and one Service (application, db or job)")),Object(r.b)("p",null,"When the deployment of an environment is triggered, Qovery executes what we call ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment Pipeline"),". It basically defines the operations shall be performed to properly deploy every service defined within your environment (build the code of service X, push the image on a registry, deploy service X on the Kubernetes cluster etc..)"),Object(r.b)("p",null,"A pipeline is composed of an ordered list of ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment Stages"),". Each Stage has an execution order assigned within the pipeline: If a stage A has an execution order lower than stage B then B can be executed only if the execution of stage A is completed."),Object(r.b)("p",null,"Each service of your environment belongs to one (and only one) ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment Stage"),". This allows you to define at which moment of the deployment pipeline a service should be deployed and thus respect any service inter-dependency (e.g. your front-end needs to be started after the back-end, your db needs to be started before your back-end etc..)."),Object(r.b)("p",null,"Below you can find a visual example of how the pipeline looks like:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/deployment/example_deployment_pipeline.png",alt:"Deployment Pipeline"})),Object(r.b)("h2",{id:"deployment-of-a-stage"},"Deployment of a stage"),Object(r.b)("p",null,"When the deployment pipeline execute the deployment of a stage, the services within it will go through the ",Object(r.b)("inlineCode",{parentName:"p"},"Build")," and ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment")," phases. "),Object(r.b)("p",null,"The Building process is managed by the Qovery CI which downloads your repository and generates the final image that will be run on your Kubernetes cluster. "),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"By default, the nodes building your application have the following resources: 4CPU and 4 GB memory. If you need more resources, get in touch with our support.")),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Important note"),": If you already have an image available on a container registry that has been previously created by your own CI/CD, it might be interesting for you to reuse it instead of re-building it again on Qovery side. Have a look at ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/"}),"this section")," on how to deploy it.")),Object(r.b)("p",null,"The build and deploy operation of each service within a deployment stage are executed in parallel with a parallism of 4. "),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Example"),"\nIf you have 6 applications to be deployed within a stage, Qovery will:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"build 4 applications in parallel. Once the build of one application is terminated, Qovery will start immediately another one until all the applications are built."),Object(r.b)("li",{parentName:"ul"},"deploy 4 applications in parallel on your Kubernetes cluster. Once the deployment of one application is terminated, Qovery will start immediately another one until all the applications are deployed.")),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"The parallel build and deployment is a feature in beta and free for everyone during the beta phase")),Object(r.b)("h2",{id:"default-pipeline-setup"},"Default Pipeline Setup"),Object(r.b)("p",null,"By default, the deployment pipeline is constituted of 4 deployment stages with a default service assignment rule:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},'"0.DEFAULT DATABASE": any new service of type ',Object(r.b)("inlineCode",{parentName:"li"},"DATABASE")," will be added to this stage."),Object(r.b)("li",{parentName:"ul"},'"1.DEFAULT JOB": any new service of type ',Object(r.b)("inlineCode",{parentName:"li"},"JOB")," will be added to this stage."),Object(r.b)("li",{parentName:"ul"},'"2.DEFAULT CONTAINER": any new service of type ',Object(r.b)("inlineCode",{parentName:"li"},"CONTAINER")," will be added to this stage (application deployed from a container image)."),Object(r.b)("li",{parentName:"ul"},'"3.DEFAULT APPLICATION": any new service of type ',Object(r.b)("inlineCode",{parentName:"li"},"APPLICATION")," will be added to this stage (application deployed from a git repository).")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/deployment/default_deployment_pipeline.png",alt:"Default Deployment Pipeline"})),Object(r.b)("p",null,"Once the service is created, the assigned stage can be modified afterwards. See ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#deployment-pipeline"}),"this section")," for more information."),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"This default assignment is maintained as long as you do not delete or rename the default stage. If the default stage is modified or deleted, the service will be automatically added to the latest stage (based on the stage deployment)")),Object(r.b)("h2",{id:"visualizing-and-modifying-the-pipeline"},"Visualizing and Modifying the Pipeline"),Object(r.b)("p",null,"You can access and modify the pipeline configuration from the environment settings. Have a look at ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#deployment-pipeline"}),"this section")," to know more."))}d.isMDXComponent=!0},420:function(e,t,n){var i;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),p=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},u=function(e){var t=p(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(i.forwardRef)((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,o=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),u=p(n),m=i,b=u["".concat(o,".").concat(m)]||u[m]||d[m]||r;return n?a.a.createElement(b,l({ref:t},s,{components:n})):a.a.createElement(b,l({ref:t},s))}));function b(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:i,o[1]=l;for(var s=2;s1?arguments[1]:void 0,n),c=o>2?arguments[2]:void 0,s=void 0===c?n:a(c,n);s>l;)t[l++]=e;return t}},425:function(e,t,n){var i=n(28).f,a=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in a||n(10)&&i(a,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var i=n(0),a=n.n(i),r=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var i=n(1),a=n(0),r=n.n(a),o=n(39),l=n(430),c=n(20),s=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,p=n||c,u=Object(l.a)(p),d=Object(a.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!m&&u&&window.docusaurus.prefetch(p),function(){m&&t&&t.disconnect()}}),[p,m,u]),p&&u?r.a.createElement(o.b,Object(i.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(p),d.current=!0)},innerRef:function(e){var n,i;m&&e&&u&&(n=e,i=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),i())}))}))).observe(n))},to:p})):r.a.createElement("a",Object(i.a)({},e,{href:p}))}},429:function(e,t,n){"use strict";var i=n(0),a=n.n(i),r=n(427),o=n(420),l=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,i=e.badge,o=e.leftIcon,c=e.rightIcon,s=e.size,p=e.target,u=e.to,d=l()("jump-to","jump-to--"+s,n),m=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},o&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+o})),a.a.createElement("div",{className:"jump-to--main"},i?a.a.createElement("span",{className:"badge badge--primary badge--right"},i):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return p?a.a.createElement("a",{href:u,target:p,className:d},m):a.a.createElement(r.a,{to:u,className:d},m)}},430:function(e,t,n){"use strict";function i(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return i}))}}]); \ No newline at end of file diff --git a/56c0a343.2d6f3c22.js b/56c0a343.824050c2.js similarity index 98% rename from 56c0a343.2d6f3c22.js rename to 56c0a343.824050c2.js index a79e3e0d3c..45c9b0c3d8 100644 --- a/56c0a343.2d6f3c22.js +++ b/56c0a343.824050c2.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[100],{251:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return p}));var a=n(1),o=n(9),r=(n(0),n(422)),i=n(421),l=(n(434),n(426)),s={last_modified_on:"2023-09-08",$schema:"/.meta/.schemas/guides.json",title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",description:"Step-by-step guide to build e2e testing ephemeral environments with GitHub Actions and Qovery",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",description:"Step-by-step guide to build e2e testing ephemeral environments with GitHub Actions and Qovery",permalink:"/guides/tutorial/build-e2e-testing-ephemeral-environments",readingTime:"12 min read",source:"@site/guides/tutorial/build-e2e-testing-ephemeral-environments.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",truncated:!1,prevItem:{title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",permalink:"/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws"},nextItem:{title:"Continuous Integration",permalink:"/guides/advanced/continuous-integration"}},b=[{value:"Why E2E Testing?",id:"why-e2e-testing",children:[]},{value:"The Importance of Ephemeral Environments",id:"the-importance-of-ephemeral-environments",children:[]},{value:"GitHub Actions and Qovery: A Perfect Match",id:"github-actions-and-qovery-a-perfect-match",children:[]},{value:"What You'll Learn",id:"what-youll-learn",children:[]},{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Tools",id:"tools",children:[]},{value:"7 Steps to build E2E testing ephemeral environments with GitHub Actions and Qovery",id:"7-steps-to-build-e2e-testing-ephemeral-environments-with-github-actions-and-qovery",children:[{value:"1. Prepare Qovery blueprint environment",id:"1-prepare-qovery-blueprint-environment",children:[]},{value:"2. Build and push container image",id:"2-build-and-push-container-image",children:[]},{value:"3. Create an Ephemeral Environment with GitHub Actions and Qovery",id:"3-create-an-ephemeral-environment-with-github-actions-and-qovery",children:[]},{value:"4. Run E2E tests with K6",id:"4-run-e2e-tests-with-k6",children:[]},{value:"5. Display test results in Pull Request",id:"5-display-test-results-in-pull-request",children:[]},{value:"6. Destroy Ephemeral Environment and clean up resources",id:"6-destroy-ephemeral-environment-and-clean-up-resources",children:[]}]},{value:"Wrapping up",id:"wrapping-up",children:[]}],u={rightToc:b};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Welcome to this comprehensive step-by-step guide on building End-to-End (E2E) testing ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/ephemeral-environments"}),"ephemeral environments")," using ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/features/actions"}),"GitHub Actions")," and ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com"}),"Qovery"),". If you've been seeking ways to automate your testing processes, reduce operational overhead, and improve the efficiency of your development cycle, then you're in the right place."),Object(r.b)("p",null,Object(r.b)("em",{parentName:"p"},"This article is available in the webinar format as well")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/1be8d4229cb74ed7b0526cc2acbca8ad",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"why-e2e-testing"},"Why E2E Testing?"),Object(r.b)("p",null,"End-to-End testing is a critical phase in the software development lifecycle. It validates that your application works cohesively from start to finish, mimicking real-world scenarios."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/e2e-pyramid.png",alt:"E2E vs UI Tests vs Integation Tests vs Unit Tests - from SemaphoreCI"})),Object(r.b)("p",null,"While unit tests and integration tests offer valuable insights, they do not replicate how multiple components interact in a live production environment. E2E testing fills that gap and ensures that your application performs as expected when it goes live."),Object(r.b)("h2",{id:"the-importance-of-ephemeral-environments"},"The Importance of Ephemeral Environments"),Object(r.b)("p",null,"In the world of DevOps and CI/CD, ephemeral environments (aka ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/blog/why-preview-environments-are-the-new-thing-in-devops"}),"Preview Environments"),") serve as temporary, isolated setups where you can test your applications. These environments are increasingly vital in agile development frameworks where frequent changes are the norm. They can be provisioned quickly, teared down when no longer needed, and replicated easily. This means you can push your changes more rapidly into production with confidence."),Object(r.b)("h2",{id:"github-actions-and-qovery-a-perfect-match"},"GitHub Actions and Qovery: A Perfect Match"),Object(r.b)("p",null,"GitHub Actions offers a powerful platform for automating workflows, allowing you to build, test, and deploy your code right from GitHub. Qovery, on the other hand, simplifies the provisioning and management of cloud resources, making it incredibly straightforward to set up ephemeral environments. When used in tandem, these tools provide a seamless, automated pipeline for E2E testing."),Object(r.b)("h2",{id:"what-youll-learn"},"What You'll Learn"),Object(r.b)("p",null,"This guide is designed to walk you through the entire process of setting up an automated E2E testing pipeline. We'll start by setting up GitHub Actions, move on to configuring ephemeral environments with Qovery, and finally, integrate these components into a cohesive, automated testing solution."),Object(r.b)("p",null,"By the end of this guide, you'll have a fully operational E2E testing pipeline that will allow you to:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Automate your testing process"),Object(r.b)("li",{parentName:"ol"},"Quickly provision and de-provision environments"),Object(r.b)("li",{parentName:"ol"},"Integrate closely with your GitHub repository"),Object(r.b)("li",{parentName:"ol"},"Save both time and operational costs")),Object(r.b)("p",null,"So, whether you are a developer, a DevOps engineer, a QA specialist, an engineering manager, or even a CTO, this guide offers valuable insights for anyone involved in the software development process."),Object(r.b)("p",null,"Let's dive in!"),Object(r.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(r.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://start.qovery.com"}),"sign in on Qovery")),Object(r.b)("li",{parentName:"ul"},"You have a GitHub account"))),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Contact us via ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum")," if you have any questions concerning Qovery")),Object(r.b)("h2",{id:"tools"},"Tools"),Object(r.b)("p",null,"Here are the tools we will use in this guide:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.qovery.com"}),"Qovery")," for the infrastructure and the ephemeral environment"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/features/actions"}),"GitHub Actions")," for the CI/CD pipeline"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://k6.io/"}),"K6")," for the e2e tests")),Object(r.b)("h2",{id:"7-steps-to-build-e2e-testing-ephemeral-environments-with-github-actions-and-qovery"},"7 Steps to build E2E testing ephemeral environments with GitHub Actions and Qovery"),Object(r.b)("p",null,"Here is the big picture of what we will build:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/1.png",alt:"e2e testing Workflow with github actions and Qovery"})),Object(r.b)("p",null,"We will focus on the most important parts of the workflow - from label number 2 to 11. I assume that you already know GitHub and how to create a Pull Request :)"),Object(r.b)("p",null,"Let's go!"),Object(r.b)("h3",{id:"1-prepare-qovery-blueprint-environment"},"1. Prepare Qovery blueprint environment"),Object(r.b)("p",null,"If you are not already familiar with Qovery, I recommend you to ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/getting-started/what-is-qovery/"}),"What's Qovery"),". In this guide, we will use Qovery to provision our ephemeral environments composed of a Java application (",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app"}),"TODO app"),") and a PostgreSQL database. For this, we will create a blueprint environment that will be used as a template to create ephemeral environments."),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can skip this part if you already have an environment that you want to use as a base for your ephemeral environments.")),Object(r.b)("p",null,"Here are the steps I did to create my blueprint environment:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Connect to ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://console.qovery.com"}),"Qovery"),"."),Object(r.b)("li",{parentName:"ol"},"Create a new project."),Object(r.b)("li",{parentName:"ol"},"Create a new environment named ",Object(r.b)("inlineCode",{parentName:"li"},"blueprint"),"."),Object(r.b)("li",{parentName:"ol"},"Add a ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"/guides/getting-started/create-a-database/"}),"PostgreSQL database")," inside your ",Object(r.b)("inlineCode",{parentName:"li"},"blueprint")," environment."),Object(r.b)("li",{parentName:"ol"},"Add a ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/application/#create-an-application"}),"TODO app")," by using my ECR container registry where I push my image from GitHub Actions (cf next step).")),Object(r.b)("p",null,"At the end of those steps, you should have something like this:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/2.png",alt:"Blueprint environment"})),Object(r.b)("p",null,"If you want to use my ",Object(r.b)("inlineCode",{parentName:"p"},"TODO app")," as an example, you need to properly configure the environment variables of the application. Here is a table with the environment variables you need to set:"),Object(r.b)("details",null,Object(r.b)("summary",null,"Environment Variables"),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Name"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Is Alias?"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Scope"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Value"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Comment"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_DB_NAME")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._DEFAULT_DATABASE_NAME")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database name")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_HOST")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._HOST_INTERNAL")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database host")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_PORT")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._PORT")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database port")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_DATASOURCE_USERNAME")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._LOGIN")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database login")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_DATASOURCE_PASSWORD")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._PASSWORD")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database password")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"QUARKUS_DATASOURCE_JDBC_URL")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"No"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"jdbc:postgresql://{{POSTGRES_HOST}}:{{POSTGRES_PORT}}/{{POSTGRES_DB_NAME}}"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Connection string to the PostgreSQL database"))))),Object(r.b)("p",null,"You're good to go! Now, let's move on to the next step."),Object(r.b)("h3",{id:"2-build-and-push-container-image"},"2. Build and push container image"),Object(r.b)("p",null,"In this step, we will build and push the container image of our application to our ECR container registry. We will use GitHub Actions to do that."),Object(r.b)("p",null,"Create your GitHub Actions workflow inside ",Object(r.b)("inlineCode",{parentName:"p"},".github/workflows")," folder. I named mine ",Object(r.b)("inlineCode",{parentName:"p"},"build-and-push-image.yml"),". Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"...\n build-and-push-container:\n runs-on: ubuntu-latest\n needs: run-unit-tests\n steps:\n - name: Checkout code\n uses: actions/checkout@v3\n\n - name: Configure AWS credentials\n uses: aws-actions/configure-aws-credentials@v2\n with:\n aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}\n aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}\n aws-region: eu-west-3\n\n - name: Login to Amazon ECR\n id: login-ecr\n uses: aws-actions/amazon-ecr-login@v1\n with:\n mask-password: 'true'\n\n - name: Build, Tag, and push image to Amazon ECR\n env:\n ECR_REGISTRY: 687975725498.dkr.ecr.eu-west-3.amazonaws.com\n ECR_REPOSITORY: todo-app\n IMAGE_TAG: ${{ github.sha }}\n run: |\n docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .\n docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest\n docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Find my complete file ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/build-and-push-image.yml"}),"here"))),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"AWS_ACCESS_KEY_ID")," and ",Object(r.b)("inlineCode",{parentName:"p"},"AWS_SECRET_ACCESS_KEY")," are stored as ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.github.com/en/actions/reference/encrypted-secrets"}),"GitHub secrets"),"."),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"The ECR registry is also connected to my Qovery account - so I can pull the pushed image from Qovery as well.")),Object(r.b)("h3",{id:"3-create-an-ephemeral-environment-with-github-actions-and-qovery"},"3. Create an Ephemeral Environment with GitHub Actions and Qovery"),Object(r.b)("p",null,"In this step, we will create an ephemeral environment with GitHub Actions and Qovery. We will use the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI")," inside our GitHub Actions workflow to do that."),Object(r.b)("p",null,"Create your GitHub Actions workflow inside ",Object(r.b)("inlineCode",{parentName:"p"},".github/workflows")," folder. I named mine ",Object(r.b)("inlineCode",{parentName:"p"},"pull-request-run-e2e-tests.yml"),". Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'...\njobs:\n create-e2e-environment:\n if: ${{ github.event.label.name == \'e2e\' }}\n runs-on: ubuntu-latest\n permissions:\n pull-requests: write\n steps:\n - id: create-environment\n name: Create and deploy Qovery E2E environment\n env:\n QOVERY_CLI_ACCESS_TOKEN: ${{ secrets.QOVERY_CLI_ACCESS_TOKEN }}\n run: |\n # Download and install Qovery CLI\n curl -s https://get.qovery.com | bash\n\n echo "Organization name: ${{ vars.QOVERY_ORGANIZATION_NAME }}"\n echo "Project name: ${{ vars.QOVERY_PROJECT_NAME }}"\n echo "Blueprint name: ${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}"\n\n new_environment_name="${GITHUB_HEAD_REF}"\n\n echo "Let\'s clone \'${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}\' environment into \'$new_environment_name\' environment"\n\n qovery environment clone \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}" \\\n --new-environment-name "$new_environment_name"\n\n qovery container update \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}" \\\n --container "${{ vars.QOVERY_APPLICATION_NAME }}" \\\n --tag ${{ github.sha }}\n\n qovery environment deploy \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n -w\n\n qovery_status_markdown_output=`qovery service list \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n --markdown`\n\n echo "QOVERY_STATUS_MARKDOWN_OUTPUT<> "$GITHUB_OUTPUT"\n echo "$qovery_status_markdown_output" >> "$GITHUB_OUTPUT"\n echo "EOF" >> "$GITHUB_OUTPUT"\n')),Object(r.b)("p",null,"Basically, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery environment clone")," command to clone our blueprint environment into a new environment. Then, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery container update")," command to update the container tag of our application. Finally, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery environment deploy")," command to deploy our application. The option ",Object(r.b)("inlineCode",{parentName:"p"},"-w")," is used to wait for the deployment to be completed. We also use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery service list")," command to get the status of our environment and store it in a GitHub output variable. This variable will be used in the next step to display the status of the environment in the Pull Request."),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"...\n - name: PR Comment with URL\n uses: mshick/add-pr-comment@v2\n with:\n message-id: qovery-e2e-environment-status\n message: |\n ${{ steps.create-environment.outputs.QOVERY_STATUS_MARKDOWN_OUTPUT }}\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Find my complete file ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-run-e2e-tests.yml"}),"here"))),Object(r.b)("p",null,"You can see the result of this step in the Pull Request:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/3.png",alt:"Ephemeral environment status in Pull Request"})),Object(r.b)("h3",{id:"4-run-e2e-tests-with-k6"},"4. Run E2E tests with K6"),Object(r.b)("p",null,"In this step, we will run our E2E tests with ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://k6.io"}),"K6"),". K6 is a modern load testing tool that allows you to write tests in JavaScript. It's a great tool to run E2E tests as well. Here is the script we will use:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"import http from 'k6/http';\nimport {check, group, sleep, fail} from 'k6';\nimport {uuidv4} from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';\n\nconst api_host = `${__ENV.API_HOST}/api`;\nexport const options = {\n stages: [\n {duration: '5m', target: 100}, // traffic ramp-up from 1 to 100 users over 5 minutes.\n //{ duration: '30m', target: 100 }, // stay at 100 users for 30 minutes\n {duration: '1m', target: 50}, // ramp-down to 50 users\n ]\n}\n\nexport function setup() {\n // add some data\n const params = {\n headers: {\n 'Content-Type': 'application/json',\n },\n };\n\n for (let i = 0; i < 20; i++) {\n const res = http.post(api_host, JSON.stringify({title: uuidv4()}), params);\n check(res, {'item added': (r) => r.status === 201});\n }\n}\n\nexport default function () {\n http.get(api_host);\n}\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete script is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/e2e/e2e.js"}),"here"))),Object(r.b)("p",null,"We will use the ",Object(r.b)("inlineCode",{parentName:"p"},"setup")," function to add some data to our database. Then, we will use the ",Object(r.b)("inlineCode",{parentName:"p"},"default")," function to get the list of items from our API. We will use the ",Object(r.b)("inlineCode",{parentName:"p"},"options")," variable to define the number of users we want to simulate. In this example, we will simulate 100 users for 5 minutes. You can find more information about the ",Object(r.b)("inlineCode",{parentName:"p"},"options")," variable ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://k6.io/docs/using-k6/options"}),"here"),"."),Object(r.b)("p",null,"To run our E2E tests, we will use the ",Object(r.b)("inlineCode",{parentName:"p"},"k6 run")," command inside our GitHub Actions workflow. Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),' run-e2e-tests:\n if: ${{ github.event.label.name == \'e2e\' }}\n runs-on: ubuntu-latest\n needs: create-e2e-environment\n permissions:\n pull-requests: write\n steps:\n - name: Checkout code\n uses: actions/checkout@v3\n\n - id: run-e2e\n name: Run E2E tests\n env:\n QOVERY_CLI_ACCESS_TOKEN: ${{ secrets.QOVERY_CLI_ACCESS_TOKEN }}\n run: |\n # Download and install Qovery CLI\n curl -s https://get.qovery.com | bash\n\n sudo gpg -k\n sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69\n echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list\n sudo apt-get update\n sudo apt-get install k6\n\n new_environment_name="${GITHUB_HEAD_REF}"\n\n api_domain=`qovery container domain list \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n --container "${{ vars.QOVERY_APPLICATION_NAME }}" | grep "BUILT_IN_DOMAIN" | head -1 | awk \'{print $5}\' | sed -e \'s/\\x1b\\[[0-9;]*m//g\'`\n\n echo "api_domain: $api_domain"\n\n api_host="https://$api_domain"\n echo "API_HOST: $api_host"\n\n e2e_report=`k6 --no-color -q -e API_HOST=$api_host run e2e/e2e.js`\n\n echo "E2E_REPORT<> $GITHUB_OUTPUT\n echo "$e2e_report" >> $GITHUB_OUTPUT\n echo "EOF" >> $GITHUB_OUTPUT\n')),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete file is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-run-e2e-tests.yml"}),"here"))),Object(r.b)("p",null,"We use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery container domain list")," command to get the domain of our application. Then, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"k6")," command to run our E2E tests. We store the result of the tests in a GitHub output variable."),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"The ",Object(r.b)("inlineCode",{parentName:"p"},"qovery container domain list")," command returns ANSI color codes. We use the ",Object(r.b)("inlineCode",{parentName:"p"},"sed -e 's/\\x1b\\[[0-9;]*m//g'")," command to remove them.")),Object(r.b)("h3",{id:"5-display-test-results-in-pull-request"},"5. Display test results in Pull Request"),Object(r.b)("p",null,"In this step, we will display the result of our E2E tests in the Pull Request. We will use the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-output-parameter"}),"GitHub Actions output variables")," to do that. Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"})," - name: Display E2E Report\n uses: mshick/add-pr-comment@v2\n with:\n message-id: e2e-report\n message: |\n E2E Tests Report\n\n --\n\n ```\n ${{ steps.run-e2e.outputs.E2E_REPORT }}\n ```\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete file is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-run-e2e-tests.yml#L109C1-L120C16"}),"here"))),Object(r.b)("p",null,"You can see the result of this step in the Pull Request:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/4.png",alt:"E2E report in Pull Request"})),Object(r.b)("h3",{id:"6-destroy-ephemeral-environment-and-clean-up-resources"},"6. Destroy Ephemeral Environment and clean up resources"),Object(r.b)("p",null,"Now we will destroy the ephemeral environment and clean up the resources when the Pull Request is closed or merged. Here is the yaml:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'name: Destroy and clean up E2E Tests Environment\n\non:\n pull_request:\n types: [ closed ]\n\njobs:\n delete-e2e-environment:\n runs-on: ubuntu-latest\n steps:\n - id: delete-environment\n name: Delete Qovery E2E environment\n env:\n QOVERY_CLI_ACCESS_TOKEN: ${{ secrets.QOVERY_CLI_ACCESS_TOKEN }}\n run: |\n # Download and install Qovery CLI\n curl -s https://get.qovery.com | bash\n\n echo "Organization name: ${{ vars.QOVERY_ORGANIZATION_NAME }}"\n echo "Project name: ${{ vars.QOVERY_PROJECT_NAME }}"\n echo "Blueprint name: ${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}"\n\n new_environment_name="${GITHUB_HEAD_REF}"\n\n echo "Let\'s delete \'$new_environment_name\' environment and release its resources"\n\n qovery environment delete \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n -w\n')),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete file is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-destroy-e2e-environment.yml"}),"here"))),Object(r.b)("p",null,"We just use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery environment delete")," command to delete the ephemeral environment. The option ",Object(r.b)("inlineCode",{parentName:"p"},"-w")," is used to wait for the deletion to be completed. Qovery will automatically release the resources used by the environment."),Object(r.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(r.b)("p",null,"Congratulations! You've successfully built an automated E2E testing pipeline with GitHub Actions and Qovery. You can now run your tests in a fully isolated environment, provisioned and de-provisioned automatically, and integrated with your GitHub repository."),Object(r.b)("p",null,"Some resources:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://semaphoreci.com/blog/e2e-testing"}),"https://semaphoreci.com/blog/e2e-testing")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.loom.com/share/1be8d4229cb74ed7b0526cc2acbca8ad"}),"Webinar record"))))}p.isMDXComponent=!0},421:function(e,t,n){"use strict";n(423);var a=n(0),o=n.n(a),r=n(420),i=n.n(r);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,r=e.icon,l=e.type,s=null;switch(l){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return o.a.createElement("div",{className:i()(n,"alert","alert--"+l,{"alert--fill":a,"alert--icon":!1!==r}),role:"alert"},!1!==r&&o.a.createElement("i",{className:i()("feather","icon-"+(r||s))}),t)}},425:function(e,t,n){var a=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&a(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),o=n.n(a),r=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},434:function(e,t,n){"use strict";var a=n(1),o=(n(439),n(436),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(446),l=n(420),s=n.n(l),c=n(428),b=n.n(c),u=n(445),p=37,m=39;function d(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,o=e.className,i=e.handleKeydown,l=e.style,c=e.values,b=e.selectedValue,u=e.tabRefs;return r.a.createElement("div",{className:n?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:s()("tabs",o,{"tabs--block":t}),style:l},c.map((function(e){var t=e.value,n=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:s()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return i(u,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function h(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,o=e.size,l=e.values,s=l;if(s[0].group){var c=_.groupBy(s,"group");s=Object.keys(c).map((function(e){return{label:e,options:c[e]}}))}return r.a.createElement(i.a,{className:"react-select-container react-select--"+o,classNamePrefix:"react-select",options:s,isClearable:n,placeholder:t,value:l.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,i=e.groupId,l=e.label,s=e.placeholder,c=e.select,O=e.size,v=(e.style,e.values),g=e.urlKey,j=Object(u.a)(),E=j.tabGroupChoices,y=j.setTabGroupChoices,f=Object(o.useState)(n),N=f[0],w=f[1];if(null!=i){var _=E[i];null!=_&&_!==N&&w(_)}var T=function(e){w(e),null!=i&&y(i,e)},R=[],A=function(e,t,n){switch(n.keyCode){case m:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(o.useEffect)((function(){if("undefined"!=typeof window&&window.location&&g){var e=b.a.parse(window.location.search);e[g]&&w(e[g])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(O||"md")},l&&r.a.createElement("div",{className:"margin-vert--sm"},l),v.length>1&&(c?r.a.createElement(h,Object(a.a)({changeSelectedValue:T,handleKeydown:A,placeholder:s,selectedValue:N,size:O,tabRefs:R},e)):r.a.createElement(d,Object(a.a)({changeSelectedValue:T,handleKeydown:A,selectedValue:N,tabRefs:R},e)))),o.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[102],{253:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return p}));var a=n(1),o=n(9),r=(n(0),n(425)),i=n(424),l=(n(437),n(429)),s={last_modified_on:"2023-09-08",$schema:"/.meta/.schemas/guides.json",title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",description:"Step-by-step guide to build e2e testing ephemeral environments with GitHub Actions and Qovery",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",description:"Step-by-step guide to build e2e testing ephemeral environments with GitHub Actions and Qovery",permalink:"/guides/tutorial/build-e2e-testing-ephemeral-environments",readingTime:"12 min read",source:"@site/guides/tutorial/build-e2e-testing-ephemeral-environments.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",truncated:!1,prevItem:{title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",permalink:"/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws"},nextItem:{title:"Continuous Integration",permalink:"/guides/advanced/continuous-integration"}},b=[{value:"Why E2E Testing?",id:"why-e2e-testing",children:[]},{value:"The Importance of Ephemeral Environments",id:"the-importance-of-ephemeral-environments",children:[]},{value:"GitHub Actions and Qovery: A Perfect Match",id:"github-actions-and-qovery-a-perfect-match",children:[]},{value:"What You'll Learn",id:"what-youll-learn",children:[]},{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Tools",id:"tools",children:[]},{value:"7 Steps to build E2E testing ephemeral environments with GitHub Actions and Qovery",id:"7-steps-to-build-e2e-testing-ephemeral-environments-with-github-actions-and-qovery",children:[{value:"1. Prepare Qovery blueprint environment",id:"1-prepare-qovery-blueprint-environment",children:[]},{value:"2. Build and push container image",id:"2-build-and-push-container-image",children:[]},{value:"3. Create an Ephemeral Environment with GitHub Actions and Qovery",id:"3-create-an-ephemeral-environment-with-github-actions-and-qovery",children:[]},{value:"4. Run E2E tests with K6",id:"4-run-e2e-tests-with-k6",children:[]},{value:"5. Display test results in Pull Request",id:"5-display-test-results-in-pull-request",children:[]},{value:"6. Destroy Ephemeral Environment and clean up resources",id:"6-destroy-ephemeral-environment-and-clean-up-resources",children:[]}]},{value:"Wrapping up",id:"wrapping-up",children:[]}],u={rightToc:b};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Welcome to this comprehensive step-by-step guide on building End-to-End (E2E) testing ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/ephemeral-environments"}),"ephemeral environments")," using ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/features/actions"}),"GitHub Actions")," and ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com"}),"Qovery"),". If you've been seeking ways to automate your testing processes, reduce operational overhead, and improve the efficiency of your development cycle, then you're in the right place."),Object(r.b)("p",null,Object(r.b)("em",{parentName:"p"},"This article is available in the webinar format as well")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/1be8d4229cb74ed7b0526cc2acbca8ad",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"why-e2e-testing"},"Why E2E Testing?"),Object(r.b)("p",null,"End-to-End testing is a critical phase in the software development lifecycle. It validates that your application works cohesively from start to finish, mimicking real-world scenarios."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/e2e-pyramid.png",alt:"E2E vs UI Tests vs Integation Tests vs Unit Tests - from SemaphoreCI"})),Object(r.b)("p",null,"While unit tests and integration tests offer valuable insights, they do not replicate how multiple components interact in a live production environment. E2E testing fills that gap and ensures that your application performs as expected when it goes live."),Object(r.b)("h2",{id:"the-importance-of-ephemeral-environments"},"The Importance of Ephemeral Environments"),Object(r.b)("p",null,"In the world of DevOps and CI/CD, ephemeral environments (aka ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/blog/why-preview-environments-are-the-new-thing-in-devops"}),"Preview Environments"),") serve as temporary, isolated setups where you can test your applications. These environments are increasingly vital in agile development frameworks where frequent changes are the norm. They can be provisioned quickly, teared down when no longer needed, and replicated easily. This means you can push your changes more rapidly into production with confidence."),Object(r.b)("h2",{id:"github-actions-and-qovery-a-perfect-match"},"GitHub Actions and Qovery: A Perfect Match"),Object(r.b)("p",null,"GitHub Actions offers a powerful platform for automating workflows, allowing you to build, test, and deploy your code right from GitHub. Qovery, on the other hand, simplifies the provisioning and management of cloud resources, making it incredibly straightforward to set up ephemeral environments. When used in tandem, these tools provide a seamless, automated pipeline for E2E testing."),Object(r.b)("h2",{id:"what-youll-learn"},"What You'll Learn"),Object(r.b)("p",null,"This guide is designed to walk you through the entire process of setting up an automated E2E testing pipeline. We'll start by setting up GitHub Actions, move on to configuring ephemeral environments with Qovery, and finally, integrate these components into a cohesive, automated testing solution."),Object(r.b)("p",null,"By the end of this guide, you'll have a fully operational E2E testing pipeline that will allow you to:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Automate your testing process"),Object(r.b)("li",{parentName:"ol"},"Quickly provision and de-provision environments"),Object(r.b)("li",{parentName:"ol"},"Integrate closely with your GitHub repository"),Object(r.b)("li",{parentName:"ol"},"Save both time and operational costs")),Object(r.b)("p",null,"So, whether you are a developer, a DevOps engineer, a QA specialist, an engineering manager, or even a CTO, this guide offers valuable insights for anyone involved in the software development process."),Object(r.b)("p",null,"Let's dive in!"),Object(r.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(r.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://start.qovery.com"}),"sign in on Qovery")),Object(r.b)("li",{parentName:"ul"},"You have a GitHub account"))),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Contact us via ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum")," if you have any questions concerning Qovery")),Object(r.b)("h2",{id:"tools"},"Tools"),Object(r.b)("p",null,"Here are the tools we will use in this guide:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.qovery.com"}),"Qovery")," for the infrastructure and the ephemeral environment"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/features/actions"}),"GitHub Actions")," for the CI/CD pipeline"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://k6.io/"}),"K6")," for the e2e tests")),Object(r.b)("h2",{id:"7-steps-to-build-e2e-testing-ephemeral-environments-with-github-actions-and-qovery"},"7 Steps to build E2E testing ephemeral environments with GitHub Actions and Qovery"),Object(r.b)("p",null,"Here is the big picture of what we will build:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/1.png",alt:"e2e testing Workflow with github actions and Qovery"})),Object(r.b)("p",null,"We will focus on the most important parts of the workflow - from label number 2 to 11. I assume that you already know GitHub and how to create a Pull Request :)"),Object(r.b)("p",null,"Let's go!"),Object(r.b)("h3",{id:"1-prepare-qovery-blueprint-environment"},"1. Prepare Qovery blueprint environment"),Object(r.b)("p",null,"If you are not already familiar with Qovery, I recommend you to ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/getting-started/what-is-qovery/"}),"What's Qovery"),". In this guide, we will use Qovery to provision our ephemeral environments composed of a Java application (",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app"}),"TODO app"),") and a PostgreSQL database. For this, we will create a blueprint environment that will be used as a template to create ephemeral environments."),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can skip this part if you already have an environment that you want to use as a base for your ephemeral environments.")),Object(r.b)("p",null,"Here are the steps I did to create my blueprint environment:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Connect to ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://console.qovery.com"}),"Qovery"),"."),Object(r.b)("li",{parentName:"ol"},"Create a new project."),Object(r.b)("li",{parentName:"ol"},"Create a new environment named ",Object(r.b)("inlineCode",{parentName:"li"},"blueprint"),"."),Object(r.b)("li",{parentName:"ol"},"Add a ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"/guides/getting-started/create-a-database/"}),"PostgreSQL database")," inside your ",Object(r.b)("inlineCode",{parentName:"li"},"blueprint")," environment."),Object(r.b)("li",{parentName:"ol"},"Add a ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/application/#create-an-application"}),"TODO app")," by using my ECR container registry where I push my image from GitHub Actions (cf next step).")),Object(r.b)("p",null,"At the end of those steps, you should have something like this:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/2.png",alt:"Blueprint environment"})),Object(r.b)("p",null,"If you want to use my ",Object(r.b)("inlineCode",{parentName:"p"},"TODO app")," as an example, you need to properly configure the environment variables of the application. Here is a table with the environment variables you need to set:"),Object(r.b)("details",null,Object(r.b)("summary",null,"Environment Variables"),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Name"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Is Alias?"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Scope"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Value"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Comment"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_DB_NAME")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._DEFAULT_DATABASE_NAME")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database name")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_HOST")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._HOST_INTERNAL")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database host")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_PORT")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._PORT")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database port")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_DATASOURCE_USERNAME")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._LOGIN")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database login")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"POSTGRES_DATASOURCE_PASSWORD")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Yes for ",Object(r.b)("inlineCode",{parentName:"td"},"QOVERY_POSTGRESQL_Z..._PASSWORD")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"N/A"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Database password")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"QUARKUS_DATASOURCE_JDBC_URL")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"No"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Service"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"jdbc:postgresql://{{POSTGRES_HOST}}:{{POSTGRES_PORT}}/{{POSTGRES_DB_NAME}}"),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Connection string to the PostgreSQL database"))))),Object(r.b)("p",null,"You're good to go! Now, let's move on to the next step."),Object(r.b)("h3",{id:"2-build-and-push-container-image"},"2. Build and push container image"),Object(r.b)("p",null,"In this step, we will build and push the container image of our application to our ECR container registry. We will use GitHub Actions to do that."),Object(r.b)("p",null,"Create your GitHub Actions workflow inside ",Object(r.b)("inlineCode",{parentName:"p"},".github/workflows")," folder. I named mine ",Object(r.b)("inlineCode",{parentName:"p"},"build-and-push-image.yml"),". Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"...\n build-and-push-container:\n runs-on: ubuntu-latest\n needs: run-unit-tests\n steps:\n - name: Checkout code\n uses: actions/checkout@v3\n\n - name: Configure AWS credentials\n uses: aws-actions/configure-aws-credentials@v2\n with:\n aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}\n aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}\n aws-region: eu-west-3\n\n - name: Login to Amazon ECR\n id: login-ecr\n uses: aws-actions/amazon-ecr-login@v1\n with:\n mask-password: 'true'\n\n - name: Build, Tag, and push image to Amazon ECR\n env:\n ECR_REGISTRY: 687975725498.dkr.ecr.eu-west-3.amazonaws.com\n ECR_REPOSITORY: todo-app\n IMAGE_TAG: ${{ github.sha }}\n run: |\n docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .\n docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest\n docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Find my complete file ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/build-and-push-image.yml"}),"here"))),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"AWS_ACCESS_KEY_ID")," and ",Object(r.b)("inlineCode",{parentName:"p"},"AWS_SECRET_ACCESS_KEY")," are stored as ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.github.com/en/actions/reference/encrypted-secrets"}),"GitHub secrets"),"."),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"The ECR registry is also connected to my Qovery account - so I can pull the pushed image from Qovery as well.")),Object(r.b)("h3",{id:"3-create-an-ephemeral-environment-with-github-actions-and-qovery"},"3. Create an Ephemeral Environment with GitHub Actions and Qovery"),Object(r.b)("p",null,"In this step, we will create an ephemeral environment with GitHub Actions and Qovery. We will use the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI")," inside our GitHub Actions workflow to do that."),Object(r.b)("p",null,"Create your GitHub Actions workflow inside ",Object(r.b)("inlineCode",{parentName:"p"},".github/workflows")," folder. I named mine ",Object(r.b)("inlineCode",{parentName:"p"},"pull-request-run-e2e-tests.yml"),". Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'...\njobs:\n create-e2e-environment:\n if: ${{ github.event.label.name == \'e2e\' }}\n runs-on: ubuntu-latest\n permissions:\n pull-requests: write\n steps:\n - id: create-environment\n name: Create and deploy Qovery E2E environment\n env:\n QOVERY_CLI_ACCESS_TOKEN: ${{ secrets.QOVERY_CLI_ACCESS_TOKEN }}\n run: |\n # Download and install Qovery CLI\n curl -s https://get.qovery.com | bash\n\n echo "Organization name: ${{ vars.QOVERY_ORGANIZATION_NAME }}"\n echo "Project name: ${{ vars.QOVERY_PROJECT_NAME }}"\n echo "Blueprint name: ${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}"\n\n new_environment_name="${GITHUB_HEAD_REF}"\n\n echo "Let\'s clone \'${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}\' environment into \'$new_environment_name\' environment"\n\n qovery environment clone \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}" \\\n --new-environment-name "$new_environment_name"\n\n qovery container update \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}" \\\n --container "${{ vars.QOVERY_APPLICATION_NAME }}" \\\n --tag ${{ github.sha }}\n\n qovery environment deploy \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n -w\n\n qovery_status_markdown_output=`qovery service list \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n --markdown`\n\n echo "QOVERY_STATUS_MARKDOWN_OUTPUT<> "$GITHUB_OUTPUT"\n echo "$qovery_status_markdown_output" >> "$GITHUB_OUTPUT"\n echo "EOF" >> "$GITHUB_OUTPUT"\n')),Object(r.b)("p",null,"Basically, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery environment clone")," command to clone our blueprint environment into a new environment. Then, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery container update")," command to update the container tag of our application. Finally, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery environment deploy")," command to deploy our application. The option ",Object(r.b)("inlineCode",{parentName:"p"},"-w")," is used to wait for the deployment to be completed. We also use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery service list")," command to get the status of our environment and store it in a GitHub output variable. This variable will be used in the next step to display the status of the environment in the Pull Request."),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"...\n - name: PR Comment with URL\n uses: mshick/add-pr-comment@v2\n with:\n message-id: qovery-e2e-environment-status\n message: |\n ${{ steps.create-environment.outputs.QOVERY_STATUS_MARKDOWN_OUTPUT }}\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Find my complete file ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-run-e2e-tests.yml"}),"here"))),Object(r.b)("p",null,"You can see the result of this step in the Pull Request:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/3.png",alt:"Ephemeral environment status in Pull Request"})),Object(r.b)("h3",{id:"4-run-e2e-tests-with-k6"},"4. Run E2E tests with K6"),Object(r.b)("p",null,"In this step, we will run our E2E tests with ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://k6.io"}),"K6"),". K6 is a modern load testing tool that allows you to write tests in JavaScript. It's a great tool to run E2E tests as well. Here is the script we will use:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"import http from 'k6/http';\nimport {check, group, sleep, fail} from 'k6';\nimport {uuidv4} from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';\n\nconst api_host = `${__ENV.API_HOST}/api`;\nexport const options = {\n stages: [\n {duration: '5m', target: 100}, // traffic ramp-up from 1 to 100 users over 5 minutes.\n //{ duration: '30m', target: 100 }, // stay at 100 users for 30 minutes\n {duration: '1m', target: 50}, // ramp-down to 50 users\n ]\n}\n\nexport function setup() {\n // add some data\n const params = {\n headers: {\n 'Content-Type': 'application/json',\n },\n };\n\n for (let i = 0; i < 20; i++) {\n const res = http.post(api_host, JSON.stringify({title: uuidv4()}), params);\n check(res, {'item added': (r) => r.status === 201});\n }\n}\n\nexport default function () {\n http.get(api_host);\n}\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete script is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/e2e/e2e.js"}),"here"))),Object(r.b)("p",null,"We will use the ",Object(r.b)("inlineCode",{parentName:"p"},"setup")," function to add some data to our database. Then, we will use the ",Object(r.b)("inlineCode",{parentName:"p"},"default")," function to get the list of items from our API. We will use the ",Object(r.b)("inlineCode",{parentName:"p"},"options")," variable to define the number of users we want to simulate. In this example, we will simulate 100 users for 5 minutes. You can find more information about the ",Object(r.b)("inlineCode",{parentName:"p"},"options")," variable ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://k6.io/docs/using-k6/options"}),"here"),"."),Object(r.b)("p",null,"To run our E2E tests, we will use the ",Object(r.b)("inlineCode",{parentName:"p"},"k6 run")," command inside our GitHub Actions workflow. Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),' run-e2e-tests:\n if: ${{ github.event.label.name == \'e2e\' }}\n runs-on: ubuntu-latest\n needs: create-e2e-environment\n permissions:\n pull-requests: write\n steps:\n - name: Checkout code\n uses: actions/checkout@v3\n\n - id: run-e2e\n name: Run E2E tests\n env:\n QOVERY_CLI_ACCESS_TOKEN: ${{ secrets.QOVERY_CLI_ACCESS_TOKEN }}\n run: |\n # Download and install Qovery CLI\n curl -s https://get.qovery.com | bash\n\n sudo gpg -k\n sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69\n echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list\n sudo apt-get update\n sudo apt-get install k6\n\n new_environment_name="${GITHUB_HEAD_REF}"\n\n api_domain=`qovery container domain list \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n --container "${{ vars.QOVERY_APPLICATION_NAME }}" | grep "BUILT_IN_DOMAIN" | head -1 | awk \'{print $5}\' | sed -e \'s/\\x1b\\[[0-9;]*m//g\'`\n\n echo "api_domain: $api_domain"\n\n api_host="https://$api_domain"\n echo "API_HOST: $api_host"\n\n e2e_report=`k6 --no-color -q -e API_HOST=$api_host run e2e/e2e.js`\n\n echo "E2E_REPORT<> $GITHUB_OUTPUT\n echo "$e2e_report" >> $GITHUB_OUTPUT\n echo "EOF" >> $GITHUB_OUTPUT\n')),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete file is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-run-e2e-tests.yml"}),"here"))),Object(r.b)("p",null,"We use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery container domain list")," command to get the domain of our application. Then, we use the ",Object(r.b)("inlineCode",{parentName:"p"},"k6")," command to run our E2E tests. We store the result of the tests in a GitHub output variable."),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"The ",Object(r.b)("inlineCode",{parentName:"p"},"qovery container domain list")," command returns ANSI color codes. We use the ",Object(r.b)("inlineCode",{parentName:"p"},"sed -e 's/\\x1b\\[[0-9;]*m//g'")," command to remove them.")),Object(r.b)("h3",{id:"5-display-test-results-in-pull-request"},"5. Display test results in Pull Request"),Object(r.b)("p",null,"In this step, we will display the result of our E2E tests in the Pull Request. We will use the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-output-parameter"}),"GitHub Actions output variables")," to do that. Here is the content of the file:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"})," - name: Display E2E Report\n uses: mshick/add-pr-comment@v2\n with:\n message-id: e2e-report\n message: |\n E2E Tests Report\n\n --\n\n ```\n ${{ steps.run-e2e.outputs.E2E_REPORT }}\n ```\n")),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete file is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-run-e2e-tests.yml#L109C1-L120C16"}),"here"))),Object(r.b)("p",null,"You can see the result of this step in the Pull Request:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/e2e-with-github-actions-and-qovery/4.png",alt:"E2E report in Pull Request"})),Object(r.b)("h3",{id:"6-destroy-ephemeral-environment-and-clean-up-resources"},"6. Destroy Ephemeral Environment and clean up resources"),Object(r.b)("p",null,"Now we will destroy the ephemeral environment and clean up the resources when the Pull Request is closed or merged. Here is the yaml:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'name: Destroy and clean up E2E Tests Environment\n\non:\n pull_request:\n types: [ closed ]\n\njobs:\n delete-e2e-environment:\n runs-on: ubuntu-latest\n steps:\n - id: delete-environment\n name: Delete Qovery E2E environment\n env:\n QOVERY_CLI_ACCESS_TOKEN: ${{ secrets.QOVERY_CLI_ACCESS_TOKEN }}\n run: |\n # Download and install Qovery CLI\n curl -s https://get.qovery.com | bash\n\n echo "Organization name: ${{ vars.QOVERY_ORGANIZATION_NAME }}"\n echo "Project name: ${{ vars.QOVERY_PROJECT_NAME }}"\n echo "Blueprint name: ${{ vars.QOVERY_BLUEPRINT_ENVIRONMENT_NAME }}"\n\n new_environment_name="${GITHUB_HEAD_REF}"\n\n echo "Let\'s delete \'$new_environment_name\' environment and release its resources"\n\n qovery environment delete \\\n --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \\\n --project "${{ vars.QOVERY_PROJECT_NAME }}" \\\n --environment "$new_environment_name" \\\n -w\n')),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"The complete file is available ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/todo-demo-app/blob/master/.github/workflows/pull-request-destroy-e2e-environment.yml"}),"here"))),Object(r.b)("p",null,"We just use the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery environment delete")," command to delete the ephemeral environment. The option ",Object(r.b)("inlineCode",{parentName:"p"},"-w")," is used to wait for the deletion to be completed. Qovery will automatically release the resources used by the environment."),Object(r.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(r.b)("p",null,"Congratulations! You've successfully built an automated E2E testing pipeline with GitHub Actions and Qovery. You can now run your tests in a fully isolated environment, provisioned and de-provisioned automatically, and integrated with your GitHub repository."),Object(r.b)("p",null,"Some resources:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://semaphoreci.com/blog/e2e-testing"}),"https://semaphoreci.com/blog/e2e-testing")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.loom.com/share/1be8d4229cb74ed7b0526cc2acbca8ad"}),"Webinar record"))))}p.isMDXComponent=!0},424:function(e,t,n){"use strict";n(426);var a=n(0),o=n.n(a),r=n(423),i=n.n(r);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,r=e.icon,l=e.type,s=null;switch(l){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return o.a.createElement("div",{className:i()(n,"alert","alert--"+l,{"alert--fill":a,"alert--icon":!1!==r}),role:"alert"},!1!==r&&o.a.createElement("i",{className:i()("feather","icon-"+(r||s))}),t)}},428:function(e,t,n){var a=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&a(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),o=n.n(a),r=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},437:function(e,t,n){"use strict";var a=n(1),o=(n(442),n(439),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(449),l=n(423),s=n.n(l),c=n(433),b=n.n(c),u=n(448),p=37,m=39;function d(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,o=e.className,i=e.handleKeydown,l=e.style,c=e.values,b=e.selectedValue,u=e.tabRefs;return r.a.createElement("div",{className:n?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:s()("tabs",o,{"tabs--block":t}),style:l},c.map((function(e){var t=e.value,n=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:s()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return i(u,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function h(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,o=e.size,l=e.values,s=l;if(s[0].group){var c=_.groupBy(s,"group");s=Object.keys(c).map((function(e){return{label:e,options:c[e]}}))}return r.a.createElement(i.a,{className:"react-select-container react-select--"+o,classNamePrefix:"react-select",options:s,isClearable:n,placeholder:t,value:l.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,i=e.groupId,l=e.label,s=e.placeholder,c=e.select,O=e.size,v=(e.style,e.values),g=e.urlKey,j=Object(u.a)(),E=j.tabGroupChoices,y=j.setTabGroupChoices,f=Object(o.useState)(n),N=f[0],w=f[1];if(null!=i){var _=E[i];null!=_&&_!==N&&w(_)}var T=function(e){w(e),null!=i&&y(i,e)},R=[],A=function(e,t,n){switch(n.keyCode){case m:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(o.useEffect)((function(){if("undefined"!=typeof window&&window.location&&g){var e=b.a.parse(window.location.search);e[g]&&w(e[g])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(O||"md")},l&&r.a.createElement("div",{className:"margin-vert--sm"},l),v.length>1&&(c?r.a.createElement(h,Object(a.a)({changeSelectedValue:T,handleKeydown:A,placeholder:s,selectedValue:N,size:O,tabRefs:R},e)):r.a.createElement(d,Object(a.a)({changeSelectedValue:T,handleKeydown:A,selectedValue:N,tabRefs:R},e)))),o.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}}}]); \ No newline at end of file diff --git a/56cfbe62.7e282154.js b/56cfbe62.ae1ea43d.js similarity index 89% rename from 56cfbe62.7e282154.js rename to 56cfbe62.ae1ea43d.js index da4f93e833..3d3bf4e299 100644 --- a/56cfbe62.7e282154.js +++ b/56cfbe62.ae1ea43d.js @@ -1,2 +1,2 @@ -/*! For license information please see 56cfbe62.7e282154.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[101],{252:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return l}));var r=n(1),o=n(9),a=(n(0),n(422)),c=n(429),i={last_modified_on:"2023-05-29",title:"Using Qovery",description:"Everything you need to know to configure and use your applications on Qovery",sidebar_label:"hidden",hide_pagination:!0},u={id:"using-qovery",title:"Using Qovery",description:"Everything you need to know to configure and use your applications on Qovery",source:"@site/docs/using-qovery.md",permalink:"/docs/using-qovery",sidebar_label:"hidden",sidebar:"docs",previous:{title:"What's next?",permalink:"/docs/getting-started/whats-next"},next:{title:"Interface",permalink:"/docs/using-qovery/interface"}},s=[],p={rightToc:s};function l(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"This section covers everything you need to know to configure and use your applications on Qovery:"),Object(a.b)(c.a,{to:"/docs/using-qovery/audit-logs/",mdxType:"Jump"},"Audit logs"),Object(a.b)(c.a,{to:"/docs/using-qovery/configuration/",mdxType:"Jump"},"Configuration"),Object(a.b)(c.a,{to:"/docs/using-qovery/deployment/",mdxType:"Jump"},"Deployment"),Object(a.b)(c.a,{to:"/docs/using-qovery/integration/",mdxType:"Jump"},"Integration"),Object(a.b)(c.a,{to:"/docs/using-qovery/interface/",mdxType:"Jump"},"Interface"),Object(a.b)(c.a,{to:"/docs/using-qovery/maintenance/",mdxType:"Jump"},"Maintenance"),Object(a.b)(c.a,{to:"/docs/using-qovery/troubleshoot/",mdxType:"Jump"},"Troubleshoot"))}l.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),p=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},l=function(e){var t=p(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),l=p(n),d=r,m=l["".concat(c,".").concat(d)]||l[d]||f[d]||a;return n?o.a.createElement(m,i({ref:t},s,{components:n})):o.a.createElement(m,i({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,c=new Array(a);c[0]=d;var i={};for(var u in t)hasOwnProperty.call(t,u)&&(i[u]=t[u]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var s=2;s0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:p})):a.a.createElement("a",Object(r.a)({},e,{href:p}))}},429:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(427),c=n(420),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,c=e.leftIcon,u=e.rightIcon,s=e.size,p=e.target,l=e.to,f=i()("jump-to","jump-to--"+s,n),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},c&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+c})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return p?o.a.createElement("a",{href:l,target:p,className:f},d):o.a.createElement(a.a,{to:l,className:f},d)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file +/*! For license information please see 56cfbe62.ae1ea43d.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[103],{254:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return l}));var r=n(1),o=n(9),a=(n(0),n(425)),c=n(431),i={last_modified_on:"2023-05-29",title:"Using Qovery",description:"Everything you need to know to configure and use your applications on Qovery",sidebar_label:"hidden",hide_pagination:!0},u={id:"using-qovery",title:"Using Qovery",description:"Everything you need to know to configure and use your applications on Qovery",source:"@site/docs/using-qovery.md",permalink:"/docs/using-qovery",sidebar_label:"hidden",sidebar:"docs",previous:{title:"What's next?",permalink:"/docs/getting-started/whats-next"},next:{title:"Interface",permalink:"/docs/using-qovery/interface"}},s=[],p={rightToc:s};function l(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"This section covers everything you need to know to configure and use your applications on Qovery:"),Object(a.b)(c.a,{to:"/docs/using-qovery/audit-logs/",mdxType:"Jump"},"Audit logs"),Object(a.b)(c.a,{to:"/docs/using-qovery/configuration/",mdxType:"Jump"},"Configuration"),Object(a.b)(c.a,{to:"/docs/using-qovery/deployment/",mdxType:"Jump"},"Deployment"),Object(a.b)(c.a,{to:"/docs/using-qovery/integration/",mdxType:"Jump"},"Integration"),Object(a.b)(c.a,{to:"/docs/using-qovery/interface/",mdxType:"Jump"},"Interface"),Object(a.b)(c.a,{to:"/docs/using-qovery/maintenance/",mdxType:"Jump"},"Maintenance"),Object(a.b)(c.a,{to:"/docs/using-qovery/troubleshoot/",mdxType:"Jump"},"Troubleshoot"))}l.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),p=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},l=function(e){var t=p(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),l=p(n),d=r,m=l["".concat(c,".").concat(d)]||l[d]||f[d]||a;return n?o.a.createElement(m,i({ref:t},s,{components:n})):o.a.createElement(m,i({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,c=new Array(a);c[0]=d;var i={};for(var u in t)hasOwnProperty.call(t,u)&&(i[u]=t[u]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var s=2;s0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:p})):a.a.createElement("a",Object(r.a)({},e,{href:p}))}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(430),c=n(423),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,c=e.leftIcon,u=e.rightIcon,s=e.size,p=e.target,l=e.to,f=i()("jump-to","jump-to--"+s,n),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},c&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+c})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return p?o.a.createElement("a",{href:l,target:p,className:f},d):o.a.createElement(a.a,{to:l,className:f},d)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/592d28ca.026831f9.js.LICENSE.txt b/56cfbe62.ae1ea43d.js.LICENSE.txt similarity index 100% rename from 592d28ca.026831f9.js.LICENSE.txt rename to 56cfbe62.ae1ea43d.js.LICENSE.txt diff --git a/5751c945.27590fe9.js b/5751c945.90bbd82d.js similarity index 95% rename from 5751c945.27590fe9.js rename to 5751c945.90bbd82d.js index bd91701133..a6fc279e7f 100644 --- a/5751c945.27590fe9.js +++ b/5751c945.90bbd82d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[102],{253:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return i})),t.d(r,"metadata",(function(){return c})),t.d(r,"rightToc",(function(){return u})),t.d(r,"default",(function(){return p}));var n=t(1),o=t(9),a=(t(0),t(422)),i={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Amazon Web Services account",description:"Learn how to install Qovery on your Amazon Web Services (AWS) account",author_github:"https://github.com/evoxmusic",tags:["type: guide","cloud_provider: aws"]},c={categories:[{name:"cloud-provider",title:"Cloud Provider",description:"Install Qovery on your favorite cloud provider.",permalink:"/guides/cloud-provider"}],coverLabel:"Install Qovery on your Amazon Web Services account",description:"Learn how to install Qovery on your Amazon Web Services (AWS) account",permalink:"/guides/cloud-provider/guide-amazon-web-services",readingTime:"1 min read",source:"@site/guides/cloud-provider/guide-amazon-web-services.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Install Qovery on your Amazon Web Services account",truncated:!1,prevItem:{title:"Import your environment variables with the Qovery CLI",permalink:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli"},nextItem:{title:"Install Qovery on your Kubernetes cluster",permalink:"/guides/provider/guide-kubernetes"}},u=[],l={rightToc:u};function p(e){var r=e.components,t=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},l,t,{components:r,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Eager to know how to deploy your apps on your AWS account with Qovery?\nClick \ud83d\udc49 ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes/"}),"here")," \ud83d\udc48 to follow the white rabbit \ud83d\udc07"))}p.isMDXComponent=!0},422:function(e,r,t){"use strict";t.d(r,"a",(function(){return s})),t.d(r,"b",(function(){return y}));var n=t(0),o=t.n(n);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function c(e){for(var r=1;r=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=o.a.createContext({}),p=function(e){var r=o.a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},s=function(e){var r=p(e.components);return o.a.createElement(l.Provider,{value:r},e.children)},d={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},m=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),s=p(t),m=n,y=s["".concat(i,".").concat(m)]||s[m]||d[m]||a;return t?o.a.createElement(y,c({ref:r},l,{components:t})):o.a.createElement(y,c({ref:r},l))}));function y(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var a=t.length,i=new Array(a);i[0]=m;var c={};for(var u in r)hasOwnProperty.call(r,u)&&(c[u]=r[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=o.a.createContext({}),p=function(e){var r=o.a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},s=function(e){var r=p(e.components);return o.a.createElement(l.Provider,{value:r},e.children)},d={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},m=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),s=p(t),m=n,y=s["".concat(i,".").concat(m)]||s[m]||d[m]||a;return t?o.a.createElement(y,c({ref:r},l,{components:t})):o.a.createElement(y,c({ref:r},l))}));function y(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var a=t.length,i=new Array(a);i[0]=m;var c={};for(var u in r)hasOwnProperty.call(r,u)&&(c[u]=r[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=o.a.createContext({}),p=function(e){var t=o.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},u=function(e){var t=p(e.components);return o.a.createElement(l.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=p(r),b=n,y=u["".concat(i,".").concat(b)]||u[b]||f[b]||a;return r?o.a.createElement(y,c({ref:t},l,{components:r})):o.a.createElement(y,c({ref:t},l))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=r.length,i=new Array(a);i[0]=b;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l1?arguments[1]:void 0,r),s=i>2?arguments[2]:void 0,l=void 0===s?r:o(s,r);l>c;)t[c++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see 58379094.d2c96ad3.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[105],{256:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return c})),r.d(t,"metadata",(function(){return s})),r.d(t,"rightToc",(function(){return l})),r.d(t,"default",(function(){return u}));var n=r(1),o=r(9),a=(r(0),r(425)),i=r(424),c={last_modified_on:"2023-04-19",title:"Web interface",description:"How to use the Qovery web interface"},s={id:"using-qovery/interface/web-interface",title:"Web interface",description:"How to use the Qovery web interface",source:"@site/docs/using-qovery/interface/web-interface.md",permalink:"/docs/using-qovery/interface/web-interface",sidebar:"docs",previous:{title:"Interface",permalink:"/docs/using-qovery/interface"},next:{title:"CLI",permalink:"/docs/using-qovery/interface/cli"}},l=[{value:"First sign-up",id:"first-sign-up",children:[]},{value:"Deploy your first application",id:"deploy-your-first-application",children:[]}],p={rightToc:l};function u(e){var t=e.components,r=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},p,r,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,"Use Infrastructure as Code (IaC) with ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"Terraform")," and our ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/interface/rest-api/"}),"REST API")," to manage Qovery and deploy your apps.")),Object(a.b)("p",null,"Qovery provides a ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"management console")," which allows you to interact with your projects and manage your environments."),Object(a.b)("h2",{id:"first-sign-up"},"First sign-up"),Object(a.b)("p",null,"Sign in to the ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web interface"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("a",{href:"https://onboarding.qovery.com/"},Object(a.b)("img",{src:"/img/Qovery_Sign_Up_Page.jpg",alt:"Qovery Sign-up page"}))),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"When you first sign into the Qovery Console, you need to provide your Git provider account credentials. This allows you to later take advantage of a Single Sign-On process through your Git provider. However, by default, Qovery is then allowed to access all the resources stored on your Git provider account."),Object(a.b)("p",null,"For better control, as a Github user, you can install the Qovery Github App, and define which Github repositories Qovery can access. For more information, see ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/git-repository-access/"}),"Managing Git Permissions with the Qovery Github App"),".")),Object(a.b)("h2",{id:"deploy-your-first-application"},"Deploy your first application"),Object(a.b)("p",null,"Now that you have signed up on the web interface, check out ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"how to deploy your first application")))}u.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=o.a.createContext({}),p=function(e){var t=o.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},u=function(e){var t=p(e.components);return o.a.createElement(l.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=p(r),b=n,y=u["".concat(i,".").concat(b)]||u[b]||f[b]||a;return r?o.a.createElement(y,c({ref:t},l,{components:r})):o.a.createElement(y,c({ref:t},l))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=r.length,i=new Array(a);i[0]=b;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l1?arguments[1]:void 0,r),s=i>2?arguments[2]:void 0,l=void 0===s?r:o(s,r);l>c;)t[c++]=e;return t}}}]); \ No newline at end of file diff --git a/5b5f8b70.2d5c46c3.js.LICENSE.txt b/58379094.d2c96ad3.js.LICENSE.txt similarity index 100% rename from 5b5f8b70.2d5c46c3.js.LICENSE.txt rename to 58379094.d2c96ad3.js.LICENSE.txt diff --git a/59157ba2.2930c648.js b/59157ba2.9ab45ca7.js similarity index 98% rename from 59157ba2.2930c648.js rename to 59157ba2.9ab45ca7.js index ce46d05a61..6fe75fe128 100644 --- a/59157ba2.2930c648.js +++ b/59157ba2.9ab45ca7.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[104],{255:function(e,t,o){"use strict";o.r(t),o.d(t,"frontMatter",(function(){return i})),o.d(t,"metadata",(function(){return s})),o.d(t,"rightToc",(function(){return c})),o.d(t,"default",(function(){return l}));var r=o(1),n=o(9),a=(o(0),o(422)),i={last_modified_on:"2023-11-24",title:"FAQ",description:"Frequently Asked Questions"},s={id:"useful-resources/faq",title:"FAQ",description:"Frequently Asked Questions",source:"@site/docs/useful-resources/faq.md",permalink:"/docs/useful-resources/faq",sidebar:"docs",previous:{title:"SOC2",permalink:"/docs/security-and-compliance/soc2"},next:{title:"Help and Support",permalink:"/docs/useful-resources/help-and-support"}},c=[{value:"What is the difference between a Project, an Application, and an Environment?",id:"what-is-the-difference-between-a-project-an-application-and-an-environment",children:[]},{value:"How does Qovery manage databases?",id:"how-does-qovery-manage-databases",children:[]},{value:"Does Qovery replace Kubernetes?",id:"does-qovery-replace-kubernetes",children:[]},{value:"Does Qovery support mono repository?",id:"does-qovery-support-mono-repository",children:[]},{value:"Does Qovery support microservices?",id:"does-qovery-support-microservices",children:[]},{value:"What Git providers do you support?",id:"what-git-providers-do-you-support",children:[]},{value:"Do you support GitHub Enterprise or Gitlab Self-hosted?",id:"do-you-support-github-enterprise-or-gitlab-self-hosted",children:[]},{value:"Does Qovery support private Git repository?",id:"does-qovery-support-private-git-repository",children:[]},{value:"Which IP address does my cluster use to communicate externally over the Internet?",id:"which-ip-address-does-my-cluster-use-to-communicate-externally-over-the-internet",children:[]},{value:"If I have N custom domains under the same root domain, do I need to create N CNAME records, or just creating one for the root domain is enough ?",id:"if-i-have-n-custom-domains-under-the-same-root-domain-do-i-need-to-create-n-cname-records-or-just-creating-one-for-the-root-domain-is-enough-",children:[]},{value:"How do you support new Kubernetes version?",id:"how-do-you-support-new-kubernetes-version",children:[]},{value:"Can I upgrade my cluster myself",id:"can-i-upgrade-my-cluster-myself",children:[]},{value:"Can I have access to my Kubernetes cluster?",id:"can-i-have-access-to-my-kubernetes-cluster",children:[]},{value:"Can I have access to my application with a shell?",id:"can-i-have-access-to-my-application-with-a-shell",children:[]},{value:"How application auto-scaling works?",id:"how-application-auto-scaling-works",children:[]},{value:"Why you should use Qovery?",id:"why-you-should-use-qovery",children:[{value:"The power of Kubernetes",id:"the-power-of-kubernetes",children:[]},{value:"Reliable infrastructure",id:"reliable-infrastructure",children:[]},{value:"Simple and Powerful",id:"simple-and-powerful",children:[]},{value:"Built for all developers",id:"built-for-all-developers",children:[]},{value:"Fully customizable for advanced business use cases",id:"fully-customizable-for-advanced-business-use-cases",children:[]}]},{value:"How Qovery works under the hood?",id:"how-qovery-works-under-the-hood",children:[]},{value:"What is an Active User?",id:"what-is-an-active-user",children:[]},{value:"How can I contact you?",id:"how-can-i-contact-you",children:[]}],u={rightToc:c};function l(e){var t=e.components,o=Object(n.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},u,o,{components:t,mdxType:"MDXLayout"}),Object(a.b)("h2",{id:"what-is-the-difference-between-a-project-an-application-and-an-environment"},"What is the difference between a Project, an Application, and an Environment?"),Object(a.b)("p",null,"A ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/project/"}),"project")," is the site that you're working on. Each project can contain multiple ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/"}),"applications")," and be deployed in multiple ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"environments"),". An environment is a standalone copy of your site, including apps, databases, storage, data, and all other services. By default, ",Object(a.b)("inlineCode",{parentName:"p"},"main")," branch is the production environment, while all other branches can be set up as identical copies of the prod environment for testing purposes."),Object(a.b)("h2",{id:"how-does-qovery-manage-databases"},"How does Qovery manage databases?"),Object(a.b)("p",null,"Qovery provides ",Object(a.b)("inlineCode",{parentName:"p"},"managed")," and ",Object(a.b)("inlineCode",{parentName:"p"},"container")," modes for your databases. Basically, ",Object(a.b)("inlineCode",{parentName:"p"},"managed")," mode relies on the managed database provided by the cloud provider. E.g. if you choose ",Object(a.b)("inlineCode",{parentName:"p"},"Postgres")," with the ",Object(a.b)("inlineCode",{parentName:"p"},"managed")," mode while your environment is running on AWS, then Qovery provides an ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://aws.amazon.com/rds"}),"AWS RDS")," instance. Please check out our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/"}),"database section")," for further details."),Object(a.b)("h2",{id:"does-qovery-replace-kubernetes"},"Does Qovery replace Kubernetes?"),Object(a.b)("p",null,"Behind the scene, Qovery uses ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://kubernetes.io/"}),"Kubernetes"),". Qovery extends Kubernetes to make it accessible to any developer teams.\nImportant: Qovery does not modify Kubernetes. It only deploys his services in a ",Object(a.b)("inlineCode",{parentName:"p"},"qovery")," Kubernetes namespace."),Object(a.b)("h2",{id:"does-qovery-support-mono-repository"},"Does Qovery support mono repository?"),Object(a.b)("p",null,"Yes, absolutely! Check out ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/advanced/monorepository/"}),"our monorepo guide"),"."),Object(a.b)("h2",{id:"does-qovery-support-microservices"},"Does Qovery support microservices?"),Object(a.b)("p",null,"Yes, absolutely! Check out ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/advanced/microservices/"}),"our microservices guide"),"."),Object(a.b)("h2",{id:"what-git-providers-do-you-support"},"What Git providers do you support?"),Object(a.b)("p",null,"GitHub, GitLab, BitBucket."),Object(a.b)("h2",{id:"do-you-support-github-enterprise-or-gitlab-self-hosted"},"Do you support GitHub Enterprise or Gitlab Self-hosted?"),Object(a.b)("p",null,"Not at the moment, but you can upvote for this feature in ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://roadmap.qovery.com/"}),"our roadmap"),"."),Object(a.b)("h2",{id:"does-qovery-support-private-git-repository"},"Does Qovery support private Git repository?"),Object(a.b)("p",null,"Yes, absolutely!"),Object(a.b)("h2",{id:"which-ip-address-does-my-cluster-use-to-communicate-externally-over-the-internet"},"Which IP address does my cluster use to communicate externally over the Internet?"),Object(a.b)("p",null,"There isn't just one public cluster IP adress dedicated to external communication. However, ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#what-is-a-cluster"}),"worker nodes")," inside your cluster each have a public IP automatically attached to them. You can view those default public IPs in the details of your worker nodes (EC2 instances for AWS users) which belong to the node group in your cluster."),Object(a.b)("p",null,"For improved security and control, the ",Object(a.b)("inlineCode",{parentName:"p"},"Static IP")," feature allows you to ensure that outbound traffic from your cluster uses specific IP addresses. For more information on the ",Object(a.b)("inlineCode",{parentName:"p"},"Static IP")," feature and how to enable it at cluster creation, see ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#static-ip"}),"Static IP"),"."),Object(a.b)("h2",{id:"if-i-have-n-custom-domains-under-the-same-root-domain-do-i-need-to-create-n-cname-records-or-just-creating-one-for-the-root-domain-is-enough-"},"If I have N custom domains under the same root domain, do I need to create N CNAME records, or just creating one for the root domain is enough ?"),Object(a.b)("p",null,"You have to create N CNAME, one per custom domain"),Object(a.b)("h2",{id:"how-do-you-support-new-kubernetes-version"},"How do you support new Kubernetes version?"),Object(a.b)("p",null,"The Qovery team manages your Kubernetes cluster's upgrade, and you don't have to think about it. Upgrades from one minor Kubernetes version to another require a good amount of tests to make sure everything goes smoothly with zero interruptions for your app. This is why Qovery always provides 1 or 2 minor versions below the last one offered by the cloud provider. Our goal is to guarantee you the maximum uptime."),Object(a.b)("p",null,"More details on this dedicated section: ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#how-does-qovery-handle-cluster-updates-and-upgrades"}),"how-does-qovery-handle-cluster-updates-and-upgrades")),Object(a.b)("h2",{id:"can-i-upgrade-my-cluster-myself"},"Can I upgrade my cluster myself"),Object(a.b)("p",null,"NO and you SHOULDN'T !\nMore details on this dedicated section: ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#how-does-qovery-handle-cluster-updates-and-upgrades"}),"how-does-qovery-handle-cluster-updates-and-upgrades")),Object(a.b)("h2",{id:"can-i-have-access-to-my-kubernetes-cluster"},"Can I have access to my Kubernetes cluster?"),Object(a.b)("p",null,"Absolutely, you can follow ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"this guide"),"."),Object(a.b)("h2",{id:"can-i-have-access-to-my-application-with-a-shell"},"Can I have access to my application with a shell?"),Object(a.b)("p",null,"Absolutely, check out our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#shell"}),"CLI")," and the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery shell")," command."),Object(a.b)("h2",{id:"how-application-auto-scaling-works"},"How application auto-scaling works?"),Object(a.b)("p",null,"Take a look at ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#auto-scaling"}),"our application documentation"),"."),Object(a.b)("h2",{id:"why-you-should-use-qovery"},"Why you should use Qovery?"),Object(a.b)("h3",{id:"the-power-of-kubernetes"},"The power of Kubernetes"),Object(a.b)("p",null,"Under the hood, Qovery uses ",Object(a.b)("strong",{parentName:"p"},"containers")," and ",Object(a.b)("strong",{parentName:"p"},"Kubernetes")," to run applications. With us, your applications scale accordingly to your traffic and needs. We rely on major cloud providers to provide reliable infrastructure to make your applications highly available."),Object(a.b)("h3",{id:"reliable-infrastructure"},"Reliable infrastructure"),Object(a.b)("p",null,"What's more, we took on our shoulders the complexity of providing and managing other infrastructure requirements you need (like databases or message brokers), so you can focus merely on developing business features."),Object(a.b)("h3",{id:"simple-and-powerful"},"Simple and Powerful"),Object(a.b)("p",null,"With Qovery, the cloud is simple again. Get all the benefits of using cloud and Kubernetes without dealing with its complexity. You don't need to hire infrastructure experts - configuring continuous integration, deployment, databases, message brokers, storage, DNS, SSL/TLS, VPCs, and many others - we do it all for you. On Qovery, you can spin up a set of microservices, databases, and other cloud services in minutes with a single Git push!"),Object(a.b)("h3",{id:"built-for-all-developers"},"Built for all developers"),Object(a.b)("p",null,"Qovery is designed by developers for developers. Our goal is to make your life easier and allow you to move faster. Developer experience is at our heart. Building cloud-native applications was never that fast and simple!"),Object(a.b)("h3",{id:"fully-customizable-for-advanced-business-use-cases"},"Fully customizable for advanced business use cases"),Object(a.b)("p",null,"Create teams, split responsibilities, manage privileges, enforce company-wide rules, deploy to multiple clouds, plug in your own CI solutions. Qovery Business allows you to bring your organization to the next level with ease."),Object(a.b)("h2",{id:"how-qovery-works-under-the-hood"},"How Qovery works under the hood?"),Object(a.b)("p",null,Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/how-qovery-works/"}),"Here")," is a detailed explanation on how Qovery works under the hood."),Object(a.b)("h2",{id:"what-is-an-active-user"},"What is an Active User?"),Object(a.b)("p",null,"An Active User is someone who made a code change on git or deployed an application in the last 30 days. We do not count contributions to public (open-source) repositories."),Object(a.b)("h2",{id:"how-can-i-contact-you"},"How can I contact you?"),Object(a.b)("p",null,"Feel free to join our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discord.qovery.com"}),"Discord server")," or contact us by email at hello (at) qovery.com."))}l.isMDXComponent=!0},422:function(e,t,o){"use strict";o.d(t,"a",(function(){return d})),o.d(t,"b",(function(){return h}));var r=o(0),n=o.n(r);function a(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function i(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,r)}return o}function s(e){for(var t=1;t=0||(n[o]=e[o]);return n}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(n[o]=e[o])}return n}var u=n.a.createContext({}),l=function(e){var t=n.a.useContext(u),o=t;return e&&(o="function"==typeof e?e(t):s({},t,{},e)),o},d=function(e){var t=l(e.components);return n.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var o=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),d=l(o),b=r,h=d["".concat(i,".").concat(b)]||d[b]||p[b]||a;return o?n.a.createElement(h,s({ref:t},u,{components:o})):n.a.createElement(h,s({ref:t},u))}));function h(e,t){var o=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=o.length,i=new Array(a);i[0]=b;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s.mdxType="string"==typeof e?e:r,i[1]=s;for(var u=2;u=0||(n[o]=e[o]);return n}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(n[o]=e[o])}return n}var u=n.a.createContext({}),l=function(e){var t=n.a.useContext(u),o=t;return e&&(o="function"==typeof e?e(t):s({},t,{},e)),o},d=function(e){var t=l(e.components);return n.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var o=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),d=l(o),b=r,h=d["".concat(i,".").concat(b)]||d[b]||p[b]||a;return o?n.a.createElement(h,s({ref:t},u,{components:o})):n.a.createElement(h,s({ref:t},u))}));function h(e,t){var o=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=o.length,i=new Array(a);i[0]=b;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s.mdxType="string"==typeof e?e:r,i[1]=s;for(var u=2;u=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},d=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,a=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=s(n),f=r,b=d["".concat(a,".").concat(f)]||d[f]||p[f]||i;return n?o.a.createElement(b,c({ref:t},u,{components:n})):o.a.createElement(b,c({ref:t},u))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=f;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,a[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=a>2?arguments[2]:void 0,u=void 0===l?n:o(l,n);u>c;)t[c++]=e;return t}},427:function(e,t,n){"use strict";var r=n(1),o=n(0),i=n.n(o),a=n(39),c=n(430),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,d=Object(c.a)(s),p=Object(o.useRef)(!1),f=u.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!f&&d&&window.docusaurus.prefetch(s),function(){f&&t&&t.disconnect()}}),[s,f,d]),s&&d?i.a.createElement(a.b,Object(r.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,r;f&&e&&d&&(n=e,r=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:s})):i.a.createElement("a",Object(r.a)({},e,{href:s}))}},429:function(e,t,n){"use strict";var r=n(0),o=n.n(r),i=n(427),a=n(420),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,a=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,d=e.to,p=c()("jump-to","jump-to--"+u,n),f=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},a&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+a})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?o.a.createElement("a",{href:d,target:s,className:p},f):o.a.createElement(i.a,{to:d,className:p},f)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file +/*! For license information please see 592d28ca.c053c156.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[107],{258:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),i=(n(0),n(425)),a=n(424),c=n(431),l={last_modified_on:"2023-05-20",title:"Monitoring",description:"Learn how to configure your Monitoring provider in Qovery",sidebar_label:"hidden",hide_pagination:!0},u={id:"using-qovery/integration/monitoring",title:"Monitoring",description:"Learn how to configure your Monitoring provider in Qovery",source:"@site/docs/using-qovery/integration/monitoring.md",permalink:"/docs/using-qovery/integration/monitoring",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Jenkins",permalink:"/docs/using-qovery/integration/continuous-integration/jenkins"},next:{title:"Datadog",permalink:"/docs/using-qovery/integration/monitoring/datadog"}},s=[{value:"FAQ",id:"faq",children:[{value:"I don't find my Monitoring provider, what should I do?",id:"i-dont-find-my-monitoring-provider-what-should-i-do",children:[]},{value:"By using the Qovery Lifecycle Jobs",id:"by-using-the-qovery-lifecycle-jobs",children:[]},{value:"By using kubectl",id:"by-using-kubectl",children:[]},{value:"Do you need help?",id:"do-you-need-help",children:[]}]}],d={rightToc:s};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(r.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(c.a,{to:"/docs/using-qovery/integration/monitoring/datadog",mdxType:"Jump"},"Datadog"),Object(i.b)(c.a,{to:"/docs/using-qovery/integration/monitoring/new-relic",mdxType:"Jump"},"New Relic"),Object(i.b)("h2",{id:"faq"},"FAQ"),Object(i.b)("h3",{id:"i-dont-find-my-monitoring-provider-what-should-i-do"},"I don't find my Monitoring provider, what should I do?"),Object(i.b)("p",null,"Basically, Qovery relies on Kubernetes to run your apps. Meaning, Qovery will support your monitoring solution if their maintainers provide a ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://helm.sh"}),"Helm Chart"),"."),Object(i.b)("p",null,"If your monitoring platform provides a Helm Chart, then you can install it:"),Object(i.b)("h3",{id:"by-using-the-qovery-lifecycle-jobs"},"By using the Qovery Lifecycle Jobs"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"Follow ",Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/guides/tutorial/how-to-deploy-helm-charts/"}),"this guide")," to deploy your Helm Chart with the Qovery Lifecycle Jobs.")),Object(i.b)("h3",{id:"by-using-kubectl"},"By using kubectl"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"Connect to your Qovery Kubernetes cluster"),"."),Object(i.b)("li",{parentName:"ol"},"Install the helm chart.")),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Helm is a Kubernetes package manager.")),Object(i.b)("h3",{id:"do-you-need-help"},"Do you need help?"),Object(i.b)("p",null,"Feel free to open a thread on our ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community Forum"),". We will be happy to help you."))}p.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},d=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,a=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=s(n),f=r,b=d["".concat(a,".").concat(f)]||d[f]||p[f]||i;return n?o.a.createElement(b,c({ref:t},u,{components:n})):o.a.createElement(b,c({ref:t},u))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=f;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,a[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=a>2?arguments[2]:void 0,u=void 0===l?n:o(l,n);u>c;)t[c++]=e;return t}},430:function(e,t,n){"use strict";var r=n(1),o=n(0),i=n.n(o),a=n(39),c=n(432),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,d=Object(c.a)(s),p=Object(o.useRef)(!1),f=u.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!f&&d&&window.docusaurus.prefetch(s),function(){f&&t&&t.disconnect()}}),[s,f,d]),s&&d?i.a.createElement(a.b,Object(r.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,r;f&&e&&d&&(n=e,r=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:s})):i.a.createElement("a",Object(r.a)({},e,{href:s}))}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),i=n(430),a=n(423),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,a=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,d=e.to,p=c()("jump-to","jump-to--"+u,n),f=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},a&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+a})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?o.a.createElement("a",{href:d,target:s,className:p},f):o.a.createElement(i.a,{to:d,className:p},f)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/5b8d4026.37aaf03b.js.LICENSE.txt b/592d28ca.c053c156.js.LICENSE.txt similarity index 100% rename from 5b8d4026.37aaf03b.js.LICENSE.txt rename to 592d28ca.c053c156.js.LICENSE.txt diff --git a/c0ab55e0.0f325bb8.js b/5b5f8b70.9b52baf5.js similarity index 95% rename from c0ab55e0.0f325bb8.js rename to 5b5f8b70.9b52baf5.js index 1ad3f43a1f..f010ba66f7 100644 --- a/c0ab55e0.0f325bb8.js +++ b/5b5f8b70.9b52baf5.js @@ -1,2 +1,2 @@ -/*! For license information please see c0ab55e0.0f325bb8.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[198],{349:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return u}));var a=n(1),i=n(9),r=(n(0),n(422)),o=(n(429),n(421)),c=(n(426),{last_modified_on:"2023-04-22",$schema:"/.meta/.schemas/guides.json",title:"Use AWS IAM roles with Qovery",description:"Give AWS IAM permissions to your application/container/job with Qovery",author_github:"https://github.com/deimosfr",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Use AWS IAM roles with Qovery",description:"Give AWS IAM permissions to your application/container/job with Qovery",permalink:"/guides/tutorial/use-aws-iam-roles-with-qovery",readingTime:"8 min read",source:"@site/guides/tutorial/use-aws-iam-roles-with-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Use AWS IAM roles with Qovery",truncated:!1,prevItem:{title:"Use an API gateway in front of multiple services",permalink:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services"},nextItem:{title:"Using Amazon SQS and Lambda on Qovery",permalink:"/guides/tutorial/aws-sqs-lambda-with-qovery"}},s=[{value:"Application requiring S3 permissions",id:"application-requiring-s3-permissions",children:[{value:"Create an application",id:"create-an-application",children:[]},{value:"Get Kubernetes namespace name",id:"get-kubernetes-namespace-name",children:[]}]},{value:"Configure OIDC provider",id:"configure-oidc-provider",children:[{value:"Get your Cluster OIDC provider URL",id:"get-your-cluster-oidc-provider-url",children:[]},{value:"Create an Identity provider",id:"create-an-identity-provider",children:[]}]},{value:"Configure AWS IAM roles",id:"configure-aws-iam-roles",children:[{value:"Create a role",id:"create-a-role",children:[]},{value:"Role permissions",id:"role-permissions",children:[]},{value:"Configure trusted entities",id:"configure-trusted-entities",children:[]}]},{value:"Create a service account",id:"create-a-service-account",children:[{value:"Kubernetes authentication",id:"kubernetes-authentication",children:[]},{value:"Create a Lifecycle job",id:"create-a-lifecycle-job",children:[]}]},{value:"Set application service account",id:"set-application-service-account",children:[{value:"Set service account",id:"set-service-account",children:[]},{value:"Validate access",id:"validate-access",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],b={rightToc:s};function u(e){var t=e.components,n=Object(i.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"AWS IAM (Identity & Access Management) service allows AWS services to interact with each other by using roles. Those roles can easily be used to give permissions to your Qovery application, container or job."),Object(r.b)("p",null,"It is a secure way to give your application permissions without having to manage credentials. More than that, it rotates the token automatically."),Object(r.b)("p",null,"This tutorial will show you how to add AWS IAM roles to your Qovery application, container or job."),Object(r.b)("h2",{id:"application-requiring-s3-permissions"},"Application requiring S3 permissions"),Object(r.b)("p",null,"In this first step, we will create a simple application that needs AWS permissions to access s3 buckets."),Object(r.b)("h3",{id:"create-an-application"},"Create an application"),Object(r.b)("p",null,"We are going to will create a simple container, but you can use an existing one if you want (or an application or job). "),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You do not have to deploy it now, just create one container this way.")),Object(r.b)("p",null,"Here is a simple Debian container example:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/debian_app.png",alt:"debian app"})),Object(r.b)("p",null,"Set only 1 instance and 128MB of memory is enough for this example. Then continue until you have the ",Object(r.b)("inlineCode",{parentName:"p"},"Create")," button, there is nothing more to setup."),Object(r.b)("h3",{id:"get-kubernetes-namespace-name"},"Get Kubernetes namespace name"),Object(r.b)("p",null,"Then in this container (or any application in this environment) ",Object(r.b)("inlineCode",{parentName:"p"},"Variables"),", search for the variable called ",Object(r.b)("inlineCode",{parentName:"p"},"QOVERY_KUBERNETES_NAMESPACE_NAME")," and copy its value somewhere."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/debian_namespace.png",alt:"debian app"})),Object(r.b)("p",null,"It is the Kubernetes namespace name where the container is located."),Object(r.b)("h2",{id:"configure-oidc-provider"},"Configure OIDC provider"),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"This step should be done only once per cluster")),Object(r.b)("h3",{id:"get-your-cluster-oidc-provider-url"},"Get your Cluster OIDC provider URL"),Object(r.b)("p",null,"On your AWS console, go to your EKS cluster and ",Object(r.b)("inlineCode",{parentName:"p"},"Overview")," section. Copy the ",Object(r.b)("inlineCode",{parentName:"p"},"OpenID Connect provider URL"),":"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/eks_oidc.png",alt:"EKS OIDC"})),Object(r.b)("h3",{id:"create-an-identity-provider"},"Create an Identity provider"),Object(r.b)("p",null,"On your AWS console, go to ",Object(r.b)("inlineCode",{parentName:"p"},"IAM")," service, then ",Object(r.b)("inlineCode",{parentName:"p"},"Identity providers")," section, and ",Object(r.b)("inlineCode",{parentName:"p"},"Add provider")," button:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Select the ",Object(r.b)("inlineCode",{parentName:"li"},"OpenID Connect")," provider type"),Object(r.b)("li",{parentName:"ol"},"Paste the ",Object(r.b)("inlineCode",{parentName:"li"},"OpenID Connect provider URL")," previously copied to ",Object(r.b)("inlineCode",{parentName:"li"},"Provider URL")),Object(r.b)("li",{parentName:"ol"},"Click on ",Object(r.b)("inlineCode",{parentName:"li"},"Get thumbprint")," button, once done the button will change to ",Object(r.b)("inlineCode",{parentName:"li"},"Edit URL")),Object(r.b)("li",{parentName:"ol"},"Add ",Object(r.b)("inlineCode",{parentName:"li"},"sts.amazonaws.com")," as ",Object(r.b)("inlineCode",{parentName:"li"},"Audience")),Object(r.b)("li",{parentName:"ol"},"Click on ",Object(r.b)("inlineCode",{parentName:"li"},"Add provider")," button")),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/oidc_connect.png",alt:"OIDC Connect"})),Object(r.b)("h2",{id:"configure-aws-iam-roles"},"Configure AWS IAM roles"),Object(r.b)("h3",{id:"create-a-role"},"Create a role"),Object(r.b)("p",null,"Now we can create a role. In the ",Object(r.b)("inlineCode",{parentName:"p"},"IAM")," service, go to ",Object(r.b)("inlineCode",{parentName:"p"},"Roles")," section, and click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create role")," button."),Object(r.b)("p",null,"You have to select the Trusted entity type. For this tutorial, we are going to use the ",Object(r.b)("inlineCode",{parentName:"p"},"Web identity")," type."),Object(r.b)("p",null,"Set the ",Object(r.b)("inlineCode",{parentName:"p"},"Identity provider")," to the one you just created, and the ",Object(r.b)("inlineCode",{parentName:"p"},"Audience")," to ",Object(r.b)("inlineCode",{parentName:"p"},"sts.amazonaws.com"),". Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Next")," button."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/role_create_step1.png",alt:"Role create step 1"})),Object(r.b)("h3",{id:"role-permissions"},"Role permissions"),Object(r.b)("p",null,"Select the policy of your choice. For this example, the policy ",Object(r.b)("inlineCode",{parentName:"p"},"AmazonS3ReadOnlyAccess")," will be used to list S3 buckets. Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Next")," button."),Object(r.b)("p",null,"To finish, set the role name and description of your choice and click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create role")," button."),Object(r.b)("h3",{id:"configure-trusted-entities"},"Configure trusted entities"),Object(r.b)("h4",{id:"qovery-environment-scoped-role"},"Qovery environment scoped role"),Object(r.b)("p",null,"Once created, select your freshly created role, go to the ",Object(r.b)("inlineCode",{parentName:"p"},"Trust relationships")," tab, and click on ",Object(r.b)("inlineCode",{parentName:"p"},"Edit trust policy")," button."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/role_trusted_entities_default.png",alt:"role trusted default"})),Object(r.b)("p",null,"Update the policy line regarding the ",Object(r.b)("inlineCode",{parentName:"p"},"OIDC")," condition from:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{}),'"oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:aud": "sts.amazonaws.com"\n')),Object(r.b)("p",null,"to:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{}),'"oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:sub": "system:serviceaccount:kubernetes_namespace:service_account_name"\n')),Object(r.b)("p",null,"Replace:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"kubernetes_namespace"),": with the namespace name, corresponding to the Qovery environment (",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"#get-kubernetes-namespace-name"}),"previously copied in step 1"),")"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"service_account_name"),": define a service account name which will be re-use later (ex: ",Object(r.b)("inlineCode",{parentName:"li"},"my-s3-role"),")")),Object(r.b)("p",null,"Once done, click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Update policy")," button."),Object(r.b)("p",null,"Last element to copy and save somewhere: is the role ",Object(r.b)("inlineCode",{parentName:"p"},"ARN"),"."),Object(r.b)("p",null,"In the end, you should have something like:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Effect": "Allow",\n "Principal": {\n "Federated": "arn:aws:iam::yyyyyyy:oidc-provider/oidc.eks.us-east-2.amazonaws.com/id/xxxxxxx"\n },\n "Action": "sts:AssumeRoleWithWebIdentity",\n "Condition": {\n "StringEquals": {\n "oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:sub": "system:serviceaccount:kubernetes_namespace:service_account_name"\n }\n }\n }\n ]\n}\n')),Object(r.b)("h4",{id:"cluster-scoped-role"},"Cluster scoped role"),Object(r.b)("p",null,'If you want to be able to keep the Role and permissions with the "On-demand environment" and "Clone" features, then you have to scope the role "cluster side" instead of the "Kubernetes namespace" side.'),Object(r.b)("p",null,"To do so, update the ",Object(r.b)("inlineCode",{parentName:"p"},"Condition")," with ",Object(r.b)("inlineCode",{parentName:"p"},"StringLike")," instead of ",Object(r.b)("inlineCode",{parentName:"p"},"StringEquals"),", and use a wildcard instead of the namespace name:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'"Condition": {\n "StringLike": {\n "oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:sub": "system:serviceaccount:z*:service_account_name"\n }\n}\n')),Object(r.b)("p",null,"Replace:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"service_account_name"),": define a service account name which will be re-use later (ex: ",Object(r.b)("inlineCode",{parentName:"li"},"my-s3-role"),")"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"z*"),": the wildcard to use to match all namespaces deployed with Qovery")),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Do not forget to set the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"#create-a-service-account"}),"Service Account")," as well in those environments.")),Object(r.b)("h2",{id:"create-a-service-account"},"Create a service account"),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"If you already have an existing service account on your Kubernetes cluster and want to use it, you can skip this step.")),Object(r.b)(o.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Kubernetes reminder: ",Object(r.b)("strong",{parentName:"p"},"a deployed service account in a Kubernetes namespace, becomes available by all applications in the same namespace."))),Object(r.b)("p",null,"This step will help you on deploying a service account on your Kubernetes cluster. In case you want to do it manually on the cluster with ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl"),", you just have to push a service account like:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"apiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: $SERVICE_ACCOUNT_NAME\n namespace: $QOVERY_KUBERNETES_NAMESPACE_NAME\n annotations:\n eks.amazonaws.com/role-arn: $AWS_ROLE_ARN\n")),Object(r.b)("h3",{id:"kubernetes-authentication"},"Kubernetes authentication"),Object(r.b)("p",null,"On AWS, there are ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/eks/latest/userguide/cluster-auth.html"}),"several ways to authenticate to Kubernetes"),". To make it simple, we are going to use a dedicated IAM user, but you can select the best method for your need."),Object(r.b)("p",null,"From your AWS Console, create an IAM user account, get ",Object(r.b)("inlineCode",{parentName:"p"},"Access key ID")," and ",Object(r.b)("inlineCode",{parentName:"p"},"Secret access key")," and save them somewhere."),Object(r.b)("p",null,"Qovery helps ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/#add-your-iam-user-to-the-admin-group"}),"IAM users to get quick access to the Kubernetes cluster"),". Simply add this user to the ",Object(r.b)("inlineCode",{parentName:"p"},"Admins")," group."),Object(r.b)("h3",{id:"create-a-lifecycle-job"},"Create a Lifecycle job"),Object(r.b)("p",null,"In the same environment than your application, create a ",Object(r.b)("inlineCode",{parentName:"p"},"Lifecycle job")," which will be used to deploy a service account on the Kubernetes cluster:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step1.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Here a container ",Object(r.b)("inlineCode",{parentName:"p"},"qoveryrd/create-sa:1.0")," available on ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://hub.docker.com/r/qoveryrd/create-sa"}),"DockerHub")," made by Qovery is used, but you can fork ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/create_service_account"}),"this repository")," and update to your needs if you prefer."),Object(r.b)("p",null,"Click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button and select the ",Object(r.b)("inlineCode",{parentName:"p"},"Start")," event because we want to deploy the service account at the environment start and ",Object(r.b)("inlineCode",{parentName:"p"},"Delete")," to delete it if we decide to remove it. Set parameters as well with the according action:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step2.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button, set the resources (128Mb is enough) and click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",null,"Then add the following environment variables to the ",Object(r.b)("inlineCode",{parentName:"p"},"job")," scope:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"KUBERNETES_VERSION"),": the version of your Kubernetes cluster which will be used to download kubectl (ex: 1.23.0)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"SERVICE_ACCOUNT_NAME"),": the name of the service account in Kubernetes (the same name ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"#configure-trusted-entities"}),"you have declared")," for the role in the ",Object(r.b)("inlineCode",{parentName:"li"},"Trusted entities")," policy section)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"AWS_ROLE_ARN"),": the AWS ARN role you have just created"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"AWS_ACCESS_KEY_ID"),": the AWS access key ID of the IAM user you have created (if you decided to use this authentication method)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"AWS_SECRET_ACCESS_KEY"),": the AWS secret access key of the IAM user you have created (if you decided to use this authentication method)")),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step2.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Then ",Object(r.b)("inlineCode",{parentName:"p"},"Create")," the ",Object(r.b)("inlineCode",{parentName:"p"},"Lifecycle job"),". Go into the ",Object(r.b)("inlineCode",{parentName:"p"},"Variables")," tab and create a ",Object(r.b)("inlineCode",{parentName:"p"},"Variable Alias")," on ",Object(r.b)("inlineCode",{parentName:"p"},"QOVERY_CLOUD_PROVIDER_REGION"),", name it ",Object(r.b)("inlineCode",{parentName:"p"},"AWS_DEFAULT_REGION")," and scope it to the ",Object(r.b)("inlineCode",{parentName:"p"},"job"),"."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step3.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"You can now run your job by clicking on the ",Object(r.b)("inlineCode",{parentName:"p"},"Deploy now")," button. You should see the following output in your job logs:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{}),"-> Ensuring required environment variables are present\n-> Downloading kubectl version 1.23.0\n-> Generated service account:\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: my-s3-role\n namespace: xxxxxx\n annotations:\n eks.amazonaws.com/role-arn: arn:aws:iam::xxxxxx:role/my-s3-role\n-> Getting kubeconfig\nAdded new context arn:aws:eks:region:id:cluster/cluster-name to /root/.kube/config\n-> Deploying service account\nserviceaccount/aws-permissions created\n")),Object(r.b)("h2",{id:"set-application-service-account"},"Set application service account"),Object(r.b)("h3",{id:"set-service-account"},"Set service account"),Object(r.b)("p",null,"The final step is to set this service account (pointing to the AWS role) to your application. Go into your application ",Object(r.b)("inlineCode",{parentName:"p"},"Advanced settings")," and set the ",Object(r.b)("inlineCode",{parentName:"p"},"Service account")," to the one you have just created:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/debian_sa.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Deploy your application with the ",Object(r.b)("inlineCode",{parentName:"p"},"Deploy now")," button."),Object(r.b)("p",null,"At this stage, the job should have been executed and the service account should be deployed on your Kubernetes cluster, and the Debian container, running."),Object(r.b)("h3",{id:"validate-access"},"Validate access"),Object(r.b)("p",null,"To validate the AWS role has correctly been deployed, we can connect to the pod, and see if we have the AWS token. We will use the Qovery CLI to connect to our pod:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell\nQovery: Select organization\nOrganization:\n\u2714 Qovery\nQovery: Select project\nProject:\n\u2714 AWS roles tutorial\nQovery: Select environment\nEnvironment:\n\u2714 aws-role\nQovery: Select service\nServices:\n\u2714 debian\n")),Object(r.b)("p",null,"Now we are connected to the pod, we can check the AWS token:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ env | grep AWS\nAWS_DEFAULT_REGION=us-east-2\nAWS_REGION=us-east-2\nAWS_ROLE_ARN=arn:aws:iam::xxxxxx:role/my-s3-role\nAWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token\nAWS_STS_REGIONAL_ENDPOINTS=regional\n")),Object(r.b)("p",null,"Token is here! Let's install the AWS CLI and validate the role access. We should be able to list S3 buckets:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ apt-get update && apt-get -y install awscli\n$ aws s3 ls\n2022-09-23 06:56:38 aws-cloudtrail-logs-qovery\n...\n")),Object(r.b)("p",null,"It works! We have access to S3 buckets using the AWS role."),Object(r.b)("h2",{id:"conclusion"},"Conclusion"),Object(r.b)("p",null,"The first setup phase can be time-consuming. However, once done, applying roles to your applications is very easy and fast. You can now use roles to access any AWS service!"))}u.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function i(){for(var e=[],t=0;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=i.a.createContext({}),b=function(e){var t=i.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=b(e.components);return i.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=b(n),d=a,m=u["".concat(o,".").concat(d)]||u[d]||p[d]||r;return n?i.a.createElement(m,c({ref:t},s,{components:n})):i.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,o[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=o>2?arguments[2]:void 0,s=void 0===l?n:i(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var a=n(28).f,i=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in i||n(10)&&a(i,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),i=n.n(a),r=n(421);t.a=function(e){var t=e.children,n=e.name;return i.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},i.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),i=n(0),r=n.n(i),o=n(39),c=n(430),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,u=Object(c.a)(b),p=Object(i.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?r.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var n,a;d&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:b})):r.a.createElement("a",Object(a.a)({},e,{href:b}))}},429:function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=n(427),o=n(420),c=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,o=e.leftIcon,l=e.rightIcon,s=e.size,b=e.target,u=e.to,p=c()("jump-to","jump-to--"+s,n),d=i.a.createElement("div",{className:"jump-to--inner"},i.a.createElement("div",{className:"jump-to--inner-2"},o&&i.a.createElement("div",{className:"jump-to--left"},i.a.createElement("i",{className:"feather icon-"+o})),i.a.createElement("div",{className:"jump-to--main"},a?i.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),i.a.createElement("div",{className:"jump-to--right"},i.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return b?i.a.createElement("a",{href:u,target:b,className:p},d):i.a.createElement(r.a,{to:u,className:p},d)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see 5b5f8b70.9b52baf5.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[108],{259:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return u}));var a=n(1),i=n(9),r=(n(0),n(425)),o=(n(431),n(424)),c=(n(429),{last_modified_on:"2023-04-22",$schema:"/.meta/.schemas/guides.json",title:"Use AWS IAM roles with Qovery",description:"Give AWS IAM permissions to your application/container/job with Qovery",author_github:"https://github.com/deimosfr",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Use AWS IAM roles with Qovery",description:"Give AWS IAM permissions to your application/container/job with Qovery",permalink:"/guides/tutorial/use-aws-iam-roles-with-qovery",readingTime:"8 min read",source:"@site/guides/tutorial/use-aws-iam-roles-with-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Use AWS IAM roles with Qovery",truncated:!1,prevItem:{title:"Use an API gateway in front of multiple services",permalink:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services"},nextItem:{title:"Using Amazon SQS and Lambda on Qovery",permalink:"/guides/tutorial/aws-sqs-lambda-with-qovery"}},s=[{value:"Application requiring S3 permissions",id:"application-requiring-s3-permissions",children:[{value:"Create an application",id:"create-an-application",children:[]},{value:"Get Kubernetes namespace name",id:"get-kubernetes-namespace-name",children:[]}]},{value:"Configure OIDC provider",id:"configure-oidc-provider",children:[{value:"Get your Cluster OIDC provider URL",id:"get-your-cluster-oidc-provider-url",children:[]},{value:"Create an Identity provider",id:"create-an-identity-provider",children:[]}]},{value:"Configure AWS IAM roles",id:"configure-aws-iam-roles",children:[{value:"Create a role",id:"create-a-role",children:[]},{value:"Role permissions",id:"role-permissions",children:[]},{value:"Configure trusted entities",id:"configure-trusted-entities",children:[]}]},{value:"Create a service account",id:"create-a-service-account",children:[{value:"Kubernetes authentication",id:"kubernetes-authentication",children:[]},{value:"Create a Lifecycle job",id:"create-a-lifecycle-job",children:[]}]},{value:"Set application service account",id:"set-application-service-account",children:[{value:"Set service account",id:"set-service-account",children:[]},{value:"Validate access",id:"validate-access",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],b={rightToc:s};function u(e){var t=e.components,n=Object(i.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"AWS IAM (Identity & Access Management) service allows AWS services to interact with each other by using roles. Those roles can easily be used to give permissions to your Qovery application, container or job."),Object(r.b)("p",null,"It is a secure way to give your application permissions without having to manage credentials. More than that, it rotates the token automatically."),Object(r.b)("p",null,"This tutorial will show you how to add AWS IAM roles to your Qovery application, container or job."),Object(r.b)("h2",{id:"application-requiring-s3-permissions"},"Application requiring S3 permissions"),Object(r.b)("p",null,"In this first step, we will create a simple application that needs AWS permissions to access s3 buckets."),Object(r.b)("h3",{id:"create-an-application"},"Create an application"),Object(r.b)("p",null,"We are going to will create a simple container, but you can use an existing one if you want (or an application or job). "),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You do not have to deploy it now, just create one container this way.")),Object(r.b)("p",null,"Here is a simple Debian container example:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/debian_app.png",alt:"debian app"})),Object(r.b)("p",null,"Set only 1 instance and 128MB of memory is enough for this example. Then continue until you have the ",Object(r.b)("inlineCode",{parentName:"p"},"Create")," button, there is nothing more to setup."),Object(r.b)("h3",{id:"get-kubernetes-namespace-name"},"Get Kubernetes namespace name"),Object(r.b)("p",null,"Then in this container (or any application in this environment) ",Object(r.b)("inlineCode",{parentName:"p"},"Variables"),", search for the variable called ",Object(r.b)("inlineCode",{parentName:"p"},"QOVERY_KUBERNETES_NAMESPACE_NAME")," and copy its value somewhere."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/debian_namespace.png",alt:"debian app"})),Object(r.b)("p",null,"It is the Kubernetes namespace name where the container is located."),Object(r.b)("h2",{id:"configure-oidc-provider"},"Configure OIDC provider"),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"This step should be done only once per cluster")),Object(r.b)("h3",{id:"get-your-cluster-oidc-provider-url"},"Get your Cluster OIDC provider URL"),Object(r.b)("p",null,"On your AWS console, go to your EKS cluster and ",Object(r.b)("inlineCode",{parentName:"p"},"Overview")," section. Copy the ",Object(r.b)("inlineCode",{parentName:"p"},"OpenID Connect provider URL"),":"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/eks_oidc.png",alt:"EKS OIDC"})),Object(r.b)("h3",{id:"create-an-identity-provider"},"Create an Identity provider"),Object(r.b)("p",null,"On your AWS console, go to ",Object(r.b)("inlineCode",{parentName:"p"},"IAM")," service, then ",Object(r.b)("inlineCode",{parentName:"p"},"Identity providers")," section, and ",Object(r.b)("inlineCode",{parentName:"p"},"Add provider")," button:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Select the ",Object(r.b)("inlineCode",{parentName:"li"},"OpenID Connect")," provider type"),Object(r.b)("li",{parentName:"ol"},"Paste the ",Object(r.b)("inlineCode",{parentName:"li"},"OpenID Connect provider URL")," previously copied to ",Object(r.b)("inlineCode",{parentName:"li"},"Provider URL")),Object(r.b)("li",{parentName:"ol"},"Click on ",Object(r.b)("inlineCode",{parentName:"li"},"Get thumbprint")," button, once done the button will change to ",Object(r.b)("inlineCode",{parentName:"li"},"Edit URL")),Object(r.b)("li",{parentName:"ol"},"Add ",Object(r.b)("inlineCode",{parentName:"li"},"sts.amazonaws.com")," as ",Object(r.b)("inlineCode",{parentName:"li"},"Audience")),Object(r.b)("li",{parentName:"ol"},"Click on ",Object(r.b)("inlineCode",{parentName:"li"},"Add provider")," button")),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/oidc_connect.png",alt:"OIDC Connect"})),Object(r.b)("h2",{id:"configure-aws-iam-roles"},"Configure AWS IAM roles"),Object(r.b)("h3",{id:"create-a-role"},"Create a role"),Object(r.b)("p",null,"Now we can create a role. In the ",Object(r.b)("inlineCode",{parentName:"p"},"IAM")," service, go to ",Object(r.b)("inlineCode",{parentName:"p"},"Roles")," section, and click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create role")," button."),Object(r.b)("p",null,"You have to select the Trusted entity type. For this tutorial, we are going to use the ",Object(r.b)("inlineCode",{parentName:"p"},"Web identity")," type."),Object(r.b)("p",null,"Set the ",Object(r.b)("inlineCode",{parentName:"p"},"Identity provider")," to the one you just created, and the ",Object(r.b)("inlineCode",{parentName:"p"},"Audience")," to ",Object(r.b)("inlineCode",{parentName:"p"},"sts.amazonaws.com"),". Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Next")," button."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/role_create_step1.png",alt:"Role create step 1"})),Object(r.b)("h3",{id:"role-permissions"},"Role permissions"),Object(r.b)("p",null,"Select the policy of your choice. For this example, the policy ",Object(r.b)("inlineCode",{parentName:"p"},"AmazonS3ReadOnlyAccess")," will be used to list S3 buckets. Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Next")," button."),Object(r.b)("p",null,"To finish, set the role name and description of your choice and click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create role")," button."),Object(r.b)("h3",{id:"configure-trusted-entities"},"Configure trusted entities"),Object(r.b)("h4",{id:"qovery-environment-scoped-role"},"Qovery environment scoped role"),Object(r.b)("p",null,"Once created, select your freshly created role, go to the ",Object(r.b)("inlineCode",{parentName:"p"},"Trust relationships")," tab, and click on ",Object(r.b)("inlineCode",{parentName:"p"},"Edit trust policy")," button."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/role_trusted_entities_default.png",alt:"role trusted default"})),Object(r.b)("p",null,"Update the policy line regarding the ",Object(r.b)("inlineCode",{parentName:"p"},"OIDC")," condition from:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{}),'"oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:aud": "sts.amazonaws.com"\n')),Object(r.b)("p",null,"to:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{}),'"oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:sub": "system:serviceaccount:kubernetes_namespace:service_account_name"\n')),Object(r.b)("p",null,"Replace:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"kubernetes_namespace"),": with the namespace name, corresponding to the Qovery environment (",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"#get-kubernetes-namespace-name"}),"previously copied in step 1"),")"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"service_account_name"),": define a service account name which will be re-use later (ex: ",Object(r.b)("inlineCode",{parentName:"li"},"my-s3-role"),")")),Object(r.b)("p",null,"Once done, click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Update policy")," button."),Object(r.b)("p",null,"Last element to copy and save somewhere: is the role ",Object(r.b)("inlineCode",{parentName:"p"},"ARN"),"."),Object(r.b)("p",null,"In the end, you should have something like:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Effect": "Allow",\n "Principal": {\n "Federated": "arn:aws:iam::yyyyyyy:oidc-provider/oidc.eks.us-east-2.amazonaws.com/id/xxxxxxx"\n },\n "Action": "sts:AssumeRoleWithWebIdentity",\n "Condition": {\n "StringEquals": {\n "oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:sub": "system:serviceaccount:kubernetes_namespace:service_account_name"\n }\n }\n }\n ]\n}\n')),Object(r.b)("h4",{id:"cluster-scoped-role"},"Cluster scoped role"),Object(r.b)("p",null,'If you want to be able to keep the Role and permissions with the "On-demand environment" and "Clone" features, then you have to scope the role "cluster side" instead of the "Kubernetes namespace" side.'),Object(r.b)("p",null,"To do so, update the ",Object(r.b)("inlineCode",{parentName:"p"},"Condition")," with ",Object(r.b)("inlineCode",{parentName:"p"},"StringLike")," instead of ",Object(r.b)("inlineCode",{parentName:"p"},"StringEquals"),", and use a wildcard instead of the namespace name:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'"Condition": {\n "StringLike": {\n "oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:sub": "system:serviceaccount:z*:service_account_name"\n }\n}\n')),Object(r.b)("p",null,"Replace:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"service_account_name"),": define a service account name which will be re-use later (ex: ",Object(r.b)("inlineCode",{parentName:"li"},"my-s3-role"),")"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"z*"),": the wildcard to use to match all namespaces deployed with Qovery")),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Do not forget to set the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"#create-a-service-account"}),"Service Account")," as well in those environments.")),Object(r.b)("h2",{id:"create-a-service-account"},"Create a service account"),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"If you already have an existing service account on your Kubernetes cluster and want to use it, you can skip this step.")),Object(r.b)(o.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Kubernetes reminder: ",Object(r.b)("strong",{parentName:"p"},"a deployed service account in a Kubernetes namespace, becomes available by all applications in the same namespace."))),Object(r.b)("p",null,"This step will help you on deploying a service account on your Kubernetes cluster. In case you want to do it manually on the cluster with ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl"),", you just have to push a service account like:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"apiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: $SERVICE_ACCOUNT_NAME\n namespace: $QOVERY_KUBERNETES_NAMESPACE_NAME\n annotations:\n eks.amazonaws.com/role-arn: $AWS_ROLE_ARN\n")),Object(r.b)("h3",{id:"kubernetes-authentication"},"Kubernetes authentication"),Object(r.b)("p",null,"On AWS, there are ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/eks/latest/userguide/cluster-auth.html"}),"several ways to authenticate to Kubernetes"),". To make it simple, we are going to use a dedicated IAM user, but you can select the best method for your need."),Object(r.b)("p",null,"From your AWS Console, create an IAM user account, get ",Object(r.b)("inlineCode",{parentName:"p"},"Access key ID")," and ",Object(r.b)("inlineCode",{parentName:"p"},"Secret access key")," and save them somewhere."),Object(r.b)("p",null,"Qovery helps ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/#add-your-iam-user-to-the-admin-group"}),"IAM users to get quick access to the Kubernetes cluster"),". Simply add this user to the ",Object(r.b)("inlineCode",{parentName:"p"},"Admins")," group."),Object(r.b)("h3",{id:"create-a-lifecycle-job"},"Create a Lifecycle job"),Object(r.b)("p",null,"In the same environment than your application, create a ",Object(r.b)("inlineCode",{parentName:"p"},"Lifecycle job")," which will be used to deploy a service account on the Kubernetes cluster:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step1.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Here a container ",Object(r.b)("inlineCode",{parentName:"p"},"qoveryrd/create-sa:1.0")," available on ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://hub.docker.com/r/qoveryrd/create-sa"}),"DockerHub")," made by Qovery is used, but you can fork ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/create_service_account"}),"this repository")," and update to your needs if you prefer."),Object(r.b)("p",null,"Click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button and select the ",Object(r.b)("inlineCode",{parentName:"p"},"Start")," event because we want to deploy the service account at the environment start and ",Object(r.b)("inlineCode",{parentName:"p"},"Delete")," to delete it if we decide to remove it. Set parameters as well with the according action:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step2.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button, set the resources (128Mb is enough) and click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",null,"Then add the following environment variables to the ",Object(r.b)("inlineCode",{parentName:"p"},"job")," scope:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"KUBERNETES_VERSION"),": the version of your Kubernetes cluster which will be used to download kubectl (ex: 1.23.0)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"SERVICE_ACCOUNT_NAME"),": the name of the service account in Kubernetes (the same name ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"#configure-trusted-entities"}),"you have declared")," for the role in the ",Object(r.b)("inlineCode",{parentName:"li"},"Trusted entities")," policy section)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"AWS_ROLE_ARN"),": the AWS ARN role you have just created"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"AWS_ACCESS_KEY_ID"),": the AWS access key ID of the IAM user you have created (if you decided to use this authentication method)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"AWS_SECRET_ACCESS_KEY"),": the AWS secret access key of the IAM user you have created (if you decided to use this authentication method)")),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step2.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Then ",Object(r.b)("inlineCode",{parentName:"p"},"Create")," the ",Object(r.b)("inlineCode",{parentName:"p"},"Lifecycle job"),". Go into the ",Object(r.b)("inlineCode",{parentName:"p"},"Variables")," tab and create a ",Object(r.b)("inlineCode",{parentName:"p"},"Variable Alias")," on ",Object(r.b)("inlineCode",{parentName:"p"},"QOVERY_CLOUD_PROVIDER_REGION"),", name it ",Object(r.b)("inlineCode",{parentName:"p"},"AWS_DEFAULT_REGION")," and scope it to the ",Object(r.b)("inlineCode",{parentName:"p"},"job"),"."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step3.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"You can now run your job by clicking on the ",Object(r.b)("inlineCode",{parentName:"p"},"Deploy now")," button. You should see the following output in your job logs:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{}),"-> Ensuring required environment variables are present\n-> Downloading kubectl version 1.23.0\n-> Generated service account:\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: my-s3-role\n namespace: xxxxxx\n annotations:\n eks.amazonaws.com/role-arn: arn:aws:iam::xxxxxx:role/my-s3-role\n-> Getting kubeconfig\nAdded new context arn:aws:eks:region:id:cluster/cluster-name to /root/.kube/config\n-> Deploying service account\nserviceaccount/aws-permissions created\n")),Object(r.b)("h2",{id:"set-application-service-account"},"Set application service account"),Object(r.b)("h3",{id:"set-service-account"},"Set service account"),Object(r.b)("p",null,"The final step is to set this service account (pointing to the AWS role) to your application. Go into your application ",Object(r.b)("inlineCode",{parentName:"p"},"Advanced settings")," and set the ",Object(r.b)("inlineCode",{parentName:"p"},"Service account")," to the one you have just created:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/debian_sa.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Deploy your application with the ",Object(r.b)("inlineCode",{parentName:"p"},"Deploy now")," button."),Object(r.b)("p",null,"At this stage, the job should have been executed and the service account should be deployed on your Kubernetes cluster, and the Debian container, running."),Object(r.b)("h3",{id:"validate-access"},"Validate access"),Object(r.b)("p",null,"To validate the AWS role has correctly been deployed, we can connect to the pod, and see if we have the AWS token. We will use the Qovery CLI to connect to our pod:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell\nQovery: Select organization\nOrganization:\n\u2714 Qovery\nQovery: Select project\nProject:\n\u2714 AWS roles tutorial\nQovery: Select environment\nEnvironment:\n\u2714 aws-role\nQovery: Select service\nServices:\n\u2714 debian\n")),Object(r.b)("p",null,"Now we are connected to the pod, we can check the AWS token:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ env | grep AWS\nAWS_DEFAULT_REGION=us-east-2\nAWS_REGION=us-east-2\nAWS_ROLE_ARN=arn:aws:iam::xxxxxx:role/my-s3-role\nAWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token\nAWS_STS_REGIONAL_ENDPOINTS=regional\n")),Object(r.b)("p",null,"Token is here! Let's install the AWS CLI and validate the role access. We should be able to list S3 buckets:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ apt-get update && apt-get -y install awscli\n$ aws s3 ls\n2022-09-23 06:56:38 aws-cloudtrail-logs-qovery\n...\n")),Object(r.b)("p",null,"It works! We have access to S3 buckets using the AWS role."),Object(r.b)("h2",{id:"conclusion"},"Conclusion"),Object(r.b)("p",null,"The first setup phase can be time-consuming. However, once done, applying roles to your applications is very easy and fast. You can now use roles to access any AWS service!"))}u.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function i(){for(var e=[],t=0;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=i.a.createContext({}),b=function(e){var t=i.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=b(e.components);return i.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=b(n),d=a,m=u["".concat(o,".").concat(d)]||u[d]||p[d]||r;return n?i.a.createElement(m,c({ref:t},s,{components:n})):i.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,o[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=o>2?arguments[2]:void 0,s=void 0===l?n:i(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var a=n(28).f,i=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in i||n(10)&&a(i,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),i=n.n(a),r=n(424);t.a=function(e){var t=e.children,n=e.name;return i.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},i.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),i=n(0),r=n.n(i),o=n(39),c=n(432),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,u=Object(c.a)(b),p=Object(i.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?r.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var n,a;d&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:b})):r.a.createElement("a",Object(a.a)({},e,{href:b}))}},431:function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=n(430),o=n(423),c=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,o=e.leftIcon,l=e.rightIcon,s=e.size,b=e.target,u=e.to,p=c()("jump-to","jump-to--"+s,n),d=i.a.createElement("div",{className:"jump-to--inner"},i.a.createElement("div",{className:"jump-to--inner-2"},o&&i.a.createElement("div",{className:"jump-to--left"},i.a.createElement("i",{className:"feather icon-"+o})),i.a.createElement("div",{className:"jump-to--main"},a?i.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),i.a.createElement("div",{className:"jump-to--right"},i.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return b?i.a.createElement("a",{href:u,target:b,className:p},d):i.a.createElement(r.a,{to:u,className:p},d)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/5b95bed2.61d54c87.js.LICENSE.txt b/5b5f8b70.9b52baf5.js.LICENSE.txt similarity index 100% rename from 5b95bed2.61d54c87.js.LICENSE.txt rename to 5b5f8b70.9b52baf5.js.LICENSE.txt diff --git a/5b8d4026.37aaf03b.js b/5b8d4026.310993d6.js similarity index 91% rename from 5b8d4026.37aaf03b.js rename to 5b8d4026.310993d6.js index 11cd29c622..3bcb3842f4 100644 --- a/5b8d4026.37aaf03b.js +++ b/5b8d4026.310993d6.js @@ -1,2 +1,2 @@ -/*! For license information please see 5b8d4026.37aaf03b.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[107],{258:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return c})),a.d(t,"metadata",(function(){return l})),a.d(t,"rightToc",(function(){return s})),a.d(t,"default",(function(){return p}));var n=a(1),r=a(9),o=(a(0),a(422)),i=(a(429),a(421)),c=(a(426),{last_modified_on:"2022-11-18",$schema:"/.meta/.schemas/guides.json",title:"Grafana setup with Qovery",description:"Easily setup Grafana with Qovery",author_github:"https://github.com/deimosfr",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Grafana setup with Qovery",description:"Easily setup Grafana with Qovery",permalink:"/guides/tutorial/grafana-install",readingTime:"3 min read",source:"@site/guides/tutorial/grafana-install.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Grafana setup with Qovery",truncated:!1,prevItem:{title:"Getting Started with Preview Environments on AWS",permalink:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners"},nextItem:{title:"Helm Charts",permalink:"/guides/advanced/helm-chart"}},s=[{value:"Grafana setup",id:"grafana-setup",children:[{value:"Create a Grafana application",id:"create-a-grafana-application",children:[]},{value:"Configure database storage",id:"configure-database-storage",children:[]}]},{value:"Usage",id:"usage",children:[]},{value:"Cloudwatch Datasource",id:"cloudwatch-datasource",children:[]},{value:"Links",id:"links",children:[]}],u={rightToc:s};function p(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},u,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://grafana.com/grafana/"}),"Grafana")," is a famous Open Source solution to observe graphs and logs, supporting many data sources."),Object(o.b)("p",null,"This tutorial explains how to install Grafana on Qovery, and you will see how easy it is."),Object(o.b)("h2",{id:"grafana-setup"},"Grafana setup"),Object(o.b)("p",null,"First of all, create a project and an environment. Then let's create Grafana application."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"At the moment, Qovery does not support configuration file injection into Docker. So it can't be connected to an external database.\nThe currently used database is stored on the volume, so data will be lost on an application deletion. Qovery is going to implement configuration files for Docker in the coming weeks")),Object(o.b)("h3",{id:"create-a-grafana-application"},"Create a Grafana application"),Object(o.b)("p",null,"Connect to the console and add a new application:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_create_app.png",alt:"create gafana app"})),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Set an application name"),Object(o.b)("li",{parentName:"ol"},"Select the application source type: Container registry"),Object(o.b)("li",{parentName:"ol"},"Select DockerHub Public (or the one you have. If you do not have one, create a registry pointing to DockerHub)"),Object(o.b)("li",{parentName:"ol"},"Set the image name: grafana/grafana"),Object(o.b)("li",{parentName:"ol"},"Take a look at the latest ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://hub.docker.com/r/grafana/grafana/tags"}),"Grafana tags")," and set the tag you want to use (do not use latest one to avoid later issues)")),Object(o.b)("p",null,"Then set the resources to 1 instance and let other default values (Grafana doesn't consume a lot of resources):"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_set_resources.png",alt:"set resources"})),Object(o.b)("p",null,"Add a port mapping to the application, and set it to ",Object(o.b)("inlineCode",{parentName:"p"},"3000"),":"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_set_port.png",alt:"set port"})),Object(o.b)("p",null,"Finally, click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Create")," button:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_create.png",alt:"create app"})),Object(o.b)("h3",{id:"configure-database-storage"},"Configure database storage"),Object(o.b)("p",null,"We're now going to create a volume that will contain Grafana default database:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_volume.png",alt:"create app"})),Object(o.b)("p",null,"Go into Settings > Storage > Add Storage. Set the ",Object(o.b)("inlineCode",{parentName:"p"},"Path")," to ",Object(o.b)("inlineCode",{parentName:"p"},"/var/lib/grafana")," and the ",Object(o.b)("inlineCode",{parentName:"p"},"Size")," to ",Object(o.b)("inlineCode",{parentName:"p"},"4Gi"),". Click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create"),"."),Object(o.b)("h2",{id:"usage"},"Usage"),Object(o.b)("p",null,"Now you can deploy Grafana :). On the top right, you have the ",Object(o.b)("inlineCode",{parentName:"p"},"Open links")," button which will help you to get quick access. Then connect with those credentials:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Login: admin"),Object(o.b)("li",{parentName:"ul"},"Password: admin")),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Update the default password with a strong one as it is publicly exposed.")),Object(o.b)("h2",{id:"cloudwatch-datasource"},"Cloudwatch Datasource"),Object(o.b)("p",null,"You can add several data sources to Grafana. One we recommend at Qovery for full-text search is Cloudwatch. First of all, you have to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/cloudwatch-integration/"}),"follow this guide")," to ensure all your logs are sent to Cloudwatch. Then, you can add a new data source in Grafana:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/grafana_cloudwatch.png",alt:"grafana cloudwatch"})),Object(o.b)("p",null,"We advise you to use ",Object(o.b)("inlineCode",{parentName:"p"},"assume role")," or use a dedicated service account in read-only to access your logs. In this case, those permissions will be required:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Sid": "AllowReadingLogsFromCloudWatch",\n "Effect": "Allow",\n "Action": [\n "logs:DescribeLogGroups",\n "logs:GetLogGroupFields",\n "logs:StartQuery",\n "logs:StopQuery",\n "logs:GetQueryResults",\n "logs:GetLogEvents"\n ],\n "Resource": "*"\n },\n {\n "Sid": "AllowReadingTagsInstancesRegionsFromEC2",\n "Effect": "Allow",\n "Action": ["ec2:DescribeTags", "ec2:DescribeInstances", "ec2:DescribeRegions"],\n "Resource": "*"\n },\n {\n "Sid": "AllowReadingResourcesForTags",\n "Effect": "Allow",\n "Action": "tag:GetResources",\n "Resource": "*"\n }\n ]\n}\n')),Object(o.b)("p",null,"More info: ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://grafana.com/docs/grafana/latest/datasources/aws-cloudwatch/"}),"https://grafana.com/docs/grafana/latest/datasources/aws-cloudwatch/")),Object(o.b)("p",null,"Once done, you're able to create dashboards using Cloudwatch datasource and perform queries to your logs."),Object(o.b)("h2",{id:"links"},"Links"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://grafana.com/docs/grafana/v9.0/setup-grafana/configure-docker/#configure-aws-credentials-for-cloudwatch-support"}),"Add Cloudwatch support to Grafana")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://grafana.com/docs/grafana/latest/datasources/aws-cloudwatch/"}),"Grafana configuration for AWS"))))}p.isMDXComponent=!0},420:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):c({},t,{},e)),a},p=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(a),d=n,f=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return a?r.a.createElement(f,c({ref:t},s,{components:a})):r.a.createElement(f,c({ref:t},s))}));function f(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s1?arguments[1]:void 0,a),l=i>2?arguments[2]:void 0,s=void 0===l?a:r(l,a);s>c;)t[c++]=e;return t}},425:function(e,t,a){var n=a(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var n=a(0),r=a.n(n),o=a(421);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},427:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),i=a(39),c=a(430),l=a(20),s=a.n(l);t.a=function(e){var t,a=e.to,l=e.href,u=a||l,p=Object(c.a)(u),b=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?o.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var a,n;d&&e&&p&&(a=e,n=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:u})):o.a.createElement("a",Object(n.a)({},e,{href:u}))}},429:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(427),i=a(420),c=a.n(i);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+s,a),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:p,target:u,className:b},d):r.a.createElement(o.a,{to:p,className:b},d)}},430:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))}}]); \ No newline at end of file +/*! For license information please see 5b8d4026.310993d6.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[109],{260:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return c})),a.d(t,"metadata",(function(){return l})),a.d(t,"rightToc",(function(){return s})),a.d(t,"default",(function(){return p}));var n=a(1),r=a(9),o=(a(0),a(425)),i=(a(431),a(424)),c=(a(429),{last_modified_on:"2022-11-18",$schema:"/.meta/.schemas/guides.json",title:"Grafana setup with Qovery",description:"Easily setup Grafana with Qovery",author_github:"https://github.com/deimosfr",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Grafana setup with Qovery",description:"Easily setup Grafana with Qovery",permalink:"/guides/tutorial/grafana-install",readingTime:"3 min read",source:"@site/guides/tutorial/grafana-install.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Grafana setup with Qovery",truncated:!1,prevItem:{title:"Getting Started with Preview Environments on AWS",permalink:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners"},nextItem:{title:"Helm Charts",permalink:"/guides/advanced/helm-chart"}},s=[{value:"Grafana setup",id:"grafana-setup",children:[{value:"Create a Grafana application",id:"create-a-grafana-application",children:[]},{value:"Configure database storage",id:"configure-database-storage",children:[]}]},{value:"Usage",id:"usage",children:[]},{value:"Cloudwatch Datasource",id:"cloudwatch-datasource",children:[]},{value:"Links",id:"links",children:[]}],u={rightToc:s};function p(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},u,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://grafana.com/grafana/"}),"Grafana")," is a famous Open Source solution to observe graphs and logs, supporting many data sources."),Object(o.b)("p",null,"This tutorial explains how to install Grafana on Qovery, and you will see how easy it is."),Object(o.b)("h2",{id:"grafana-setup"},"Grafana setup"),Object(o.b)("p",null,"First of all, create a project and an environment. Then let's create Grafana application."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"At the moment, Qovery does not support configuration file injection into Docker. So it can't be connected to an external database.\nThe currently used database is stored on the volume, so data will be lost on an application deletion. Qovery is going to implement configuration files for Docker in the coming weeks")),Object(o.b)("h3",{id:"create-a-grafana-application"},"Create a Grafana application"),Object(o.b)("p",null,"Connect to the console and add a new application:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_create_app.png",alt:"create gafana app"})),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Set an application name"),Object(o.b)("li",{parentName:"ol"},"Select the application source type: Container registry"),Object(o.b)("li",{parentName:"ol"},"Select DockerHub Public (or the one you have. If you do not have one, create a registry pointing to DockerHub)"),Object(o.b)("li",{parentName:"ol"},"Set the image name: grafana/grafana"),Object(o.b)("li",{parentName:"ol"},"Take a look at the latest ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://hub.docker.com/r/grafana/grafana/tags"}),"Grafana tags")," and set the tag you want to use (do not use latest one to avoid later issues)")),Object(o.b)("p",null,"Then set the resources to 1 instance and let other default values (Grafana doesn't consume a lot of resources):"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_set_resources.png",alt:"set resources"})),Object(o.b)("p",null,"Add a port mapping to the application, and set it to ",Object(o.b)("inlineCode",{parentName:"p"},"3000"),":"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_set_port.png",alt:"set port"})),Object(o.b)("p",null,"Finally, click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Create")," button:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_create.png",alt:"create app"})),Object(o.b)("h3",{id:"configure-database-storage"},"Configure database storage"),Object(o.b)("p",null,"We're now going to create a volume that will contain Grafana default database:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_volume.png",alt:"create app"})),Object(o.b)("p",null,"Go into Settings > Storage > Add Storage. Set the ",Object(o.b)("inlineCode",{parentName:"p"},"Path")," to ",Object(o.b)("inlineCode",{parentName:"p"},"/var/lib/grafana")," and the ",Object(o.b)("inlineCode",{parentName:"p"},"Size")," to ",Object(o.b)("inlineCode",{parentName:"p"},"4Gi"),". Click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create"),"."),Object(o.b)("h2",{id:"usage"},"Usage"),Object(o.b)("p",null,"Now you can deploy Grafana :). On the top right, you have the ",Object(o.b)("inlineCode",{parentName:"p"},"Open links")," button which will help you to get quick access. Then connect with those credentials:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Login: admin"),Object(o.b)("li",{parentName:"ul"},"Password: admin")),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Update the default password with a strong one as it is publicly exposed.")),Object(o.b)("h2",{id:"cloudwatch-datasource"},"Cloudwatch Datasource"),Object(o.b)("p",null,"You can add several data sources to Grafana. One we recommend at Qovery for full-text search is Cloudwatch. First of all, you have to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/cloudwatch-integration/"}),"follow this guide")," to ensure all your logs are sent to Cloudwatch. Then, you can add a new data source in Grafana:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/grafana_cloudwatch.png",alt:"grafana cloudwatch"})),Object(o.b)("p",null,"We advise you to use ",Object(o.b)("inlineCode",{parentName:"p"},"assume role")," or use a dedicated service account in read-only to access your logs. In this case, those permissions will be required:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Sid": "AllowReadingLogsFromCloudWatch",\n "Effect": "Allow",\n "Action": [\n "logs:DescribeLogGroups",\n "logs:GetLogGroupFields",\n "logs:StartQuery",\n "logs:StopQuery",\n "logs:GetQueryResults",\n "logs:GetLogEvents"\n ],\n "Resource": "*"\n },\n {\n "Sid": "AllowReadingTagsInstancesRegionsFromEC2",\n "Effect": "Allow",\n "Action": ["ec2:DescribeTags", "ec2:DescribeInstances", "ec2:DescribeRegions"],\n "Resource": "*"\n },\n {\n "Sid": "AllowReadingResourcesForTags",\n "Effect": "Allow",\n "Action": "tag:GetResources",\n "Resource": "*"\n }\n ]\n}\n')),Object(o.b)("p",null,"More info: ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://grafana.com/docs/grafana/latest/datasources/aws-cloudwatch/"}),"https://grafana.com/docs/grafana/latest/datasources/aws-cloudwatch/")),Object(o.b)("p",null,"Once done, you're able to create dashboards using Cloudwatch datasource and perform queries to your logs."),Object(o.b)("h2",{id:"links"},"Links"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://grafana.com/docs/grafana/v9.0/setup-grafana/configure-docker/#configure-aws-credentials-for-cloudwatch-support"}),"Add Cloudwatch support to Grafana")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://grafana.com/docs/grafana/latest/datasources/aws-cloudwatch/"}),"Grafana configuration for AWS"))))}p.isMDXComponent=!0},423:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):c({},t,{},e)),a},p=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(a),d=n,f=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return a?r.a.createElement(f,c({ref:t},s,{components:a})):r.a.createElement(f,c({ref:t},s))}));function f(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s1?arguments[1]:void 0,a),l=i>2?arguments[2]:void 0,s=void 0===l?a:r(l,a);s>c;)t[c++]=e;return t}},428:function(e,t,a){var n=a(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var n=a(0),r=a.n(n),o=a(424);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},430:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),i=a(39),c=a(432),l=a(20),s=a.n(l);t.a=function(e){var t,a=e.to,l=e.href,u=a||l,p=Object(c.a)(u),b=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?o.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var a,n;d&&e&&p&&(a=e,n=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:u})):o.a.createElement("a",Object(n.a)({},e,{href:u}))}},431:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(430),i=a(423),c=a.n(i);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+s,a),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:p,target:u,className:b},d):r.a.createElement(o.a,{to:p,className:b},d)}},432:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))}}]); \ No newline at end of file diff --git a/5e5fefd2.f91a8e6d.js.LICENSE.txt b/5b8d4026.310993d6.js.LICENSE.txt similarity index 100% rename from 5e5fefd2.f91a8e6d.js.LICENSE.txt rename to 5b8d4026.310993d6.js.LICENSE.txt diff --git a/b74d0aaa.a4b5b202.js b/5b95bed2.bc5301c8.js similarity index 96% rename from b74d0aaa.a4b5b202.js rename to 5b95bed2.bc5301c8.js index e4f732897e..8566c43b82 100644 --- a/b74d0aaa.a4b5b202.js +++ b/5b95bed2.bc5301c8.js @@ -1,2 +1,2 @@ -/*! For license information please see b74d0aaa.a4b5b202.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[180],{331:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return s})),t.d(n,"metadata",(function(){return c})),t.d(n,"rightToc",(function(){return l})),t.d(n,"default",(function(){return p}));var a=t(1),r=t(9),o=(t(0),t(422)),i=t(421),s=(t(426),t(429),{last_modified_on:"2022-01-06",$schema:"/.meta/.schemas/guides.json",title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3",readingTime:"9 min read",source:"@site/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",truncated:!1,prevItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2"},nextItem:{title:"How to connect to a managed MongoDB instance on AWS",permalink:"/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws"}},l=[{value:"Bootstrapping Frontend",id:"bootstrapping-frontend",children:[]},{value:"Connecting Backend",id:"connecting-backend",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],u={rightToc:l};function p(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},u,t,{components:n,mdxType:"MDXLayout"}),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},"We assume you are familiar with the previous parts of the AppWrite Cloud series."),Object(o.b)("p",null,"In this part of the series, we will go through the process of adding a web user interface to our AppWrite Cloud platform. We\u2019ll use the Next.js framework to create the frontend application, connect it to our AppWrite Cloud GraphQL API and deploy the app on top of Qovery."),Object(o.b)("h2",{id:"bootstrapping-frontend"},"Bootstrapping Frontend"),Object(o.b)("p",null,"In the first step, let\u2019s create a scaffolding to our frontend application:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"yarn create next-app --example with-tailwindcss frontend\n")),Object(o.b)("p",null,"We use ",Object(o.b)("inlineCode",{parentName:"p"},"Tailwind")," for styling, so the command above bootstraps a ",Object(o.b)("inlineCode",{parentName:"p"},"Next.js")," app with TailwindCSS already set up."),Object(o.b)("p",null,"After the scaffolding is created, create a new remote Git repository on Github, Gitlab or Bitbucket with the application code."),Object(o.b)("p",null,"For building and deploying the app on Qovery, we\u2019ll use Docker - to dockerize the application please add a ",Object(o.b)("inlineCode",{parentName:"p"},"Dockerfile")," with the following content:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'# Install dependencies only when needed\nFROM node:alpine AS deps\n# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.\nRUN apk add --no-cache libc6-compat\nWORKDIR /app\nCOPY package.json yarn.lock ./\nRUN yarn install --frozen-lockfile\n\n# Rebuild the source code only when needed\nFROM node:alpine AS builder\nWORKDIR /app\nCOPY . .\nCOPY --from=deps /app/node_modules ./node_modules\nRUN yarn build && yarn install --production --ignore-scripts --prefer-offline\n\n# Production image, copy all the files and run next\nFROM node:alpine AS runner\nWORKDIR /app\n\nENV NODE_ENV production\n\nRUN addgroup -g 1001 -S nodejs\nRUN adduser -S nextjs -u 1001\n\n# You only need to copy next.config.js if you are NOT using the default configuration\n# COPY --from=builder /app/next.config.js ./\nCOPY --from=builder /app/public ./public\nCOPY --from=builder --chown=nextjs:nodejs /app/.next ./.next\nCOPY --from=builder /app/node_modules ./node_modules\nCOPY --from=builder /app/package.json ./package.json\n\nUSER nextjs\n\nEXPOSE 3000\n\n# Next.js collects completely anonymous telemetry data about general usage.\n# Learn more here: https://nextjs.org/telemetry\n# Uncomment the following line in case you want to disable telemetry.\n# ENV NEXT_TELEMETRY_DISABLED 1\n\nCMD ["yarn", "start"]\n')),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"Dockerfile")," will let Qovery know how to build and run the application. After the Dockerfile is created, add a new application in the AppWrite Cloud project on Qovery with port ",Object(o.b)("inlineCode",{parentName:"p"},"3000")," and ",Object(o.b)("inlineCode",{parentName:"p"},"Docker")," build mode:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/1.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"In the next step let\u2019s add a ",Object(o.b)("inlineCode",{parentName:"p"},"APPWRITE_GRAPHQL_BACKEND")," env variable that we will, later on, use in our frontend. This variable will be an alias to the location of our Hasura application, so we can access its GraphQL API:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/2.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h2",{id:"connecting-backend"},"Connecting Backend"),Object(o.b)("p",null,"Now to quickly deploy the app and test the integration, let\u2019s replace the content of ",Object(o.b)("inlineCode",{parentName:"p"},"index.tsx")," with the following:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'import { Disclosure, Menu, Transition } from \'@headlessui/react\';\nimport { BellIcon, MenuIcon, XIcon } from \'@heroicons/react/outline\';\nimport axios from \'axios\';\nimport { Fragment, useState } from \'react\';\nimport { useMutation } from \'react-query\';\n\nconst anonymous = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLXVzZXItaWQiOiI1IiwieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoiYW5vbnltb3VzIiwieC1oYXN1cmEtYWxsb3dlZC1yb2xlcyI6WyJhbm9ueW1vdXMiXX0sImV4cCI6MTY2NjA3NzAwNn0.Op7qVJAlMm3O2p1sSTMueuTUoUJls1K4pdmiusaz1R0"\n\nconst user = {\n name: \'Tom Cook\',\n email: \'tom@example.com\',\n imageUrl:\n \'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80\',\n};\nconst navigation = [{ name: \'Dashboard\', href: \'#\', current: true }];\nconst userNavigation = [\n { name: \'Your Profile\', href: \'#\' },\n { name: \'Settings\', href: \'#\' },\n { name: \'Sign out\', href: \'#\' },\n];\n\nfunction classNames(...classes) {\n return classes.filter(Boolean).join(\' \');\n}\n\nexport default function Dashboard() {\n return (\n
\n
\n \n {({ open }) => (\n <>\n
\n
\n
\n
\n
\n \n
\n
\n
\n {navigation.map((item) => (\n \n {item.name}\n \n ))}\n
\n
\n
\n
\n
\n \n View notifications\n
\n
\n
\n {/* Mobile menu button */}\n \n Open main menu\n {open ? (\n \n
\n
\n
\n
\n\n \n
\n {navigation.map((item) => (\n \n {item.name}\n \n ))}\n
\n
\n
\n
\n \n
\n
\n
\n {user.name}\n
\n
\n {user.email}\n
\n
\n \n View notifications\n
\n
\n {userNavigation.map((item) => (\n \n {item.name}\n \n ))}\n
\n
\n
\n \n )}\n
\n
\n
\n

Dashboard

\n
\n
\n
\n\n
\n
\n \n \n
\n
\n
\n
\n
\n
\n \n );\n}\n\nconst Signin = (email, password) => {\n const mutation = useMutation((event) => {\n event.preventDefault();\n return axios({\n url: graphqlApiEndpoint,\n method: \'post\',\n headers: { \'Authorization\': \'Bearer \' + anonymous },\n data: {\n query: `\n query Singin {\n Singin(email: "${email}", password: "${password}") {\n accessToken\n }\n }\n `,\n },\n })\n });\n return ;\n};\n\nconst Signup = (email, password) => {\n const mutation = useMutation((event) => {\n event.preventDefault();\n return axios({\n url: graphqlApiEndpoint,\n method: \'post\',\n headers: { \'Authorization\': \'Bearer \' + anonymous },\n data: {\n query: `\n query Signup {\n Signup(email: "${email}", password: "${password}") {\n accessToken\n }\n }\n `,\n },\n })\n });\n return ;\n};\n')),Object(o.b)("p",null,"This makes the skeleton of our UI:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/3.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"Clicking on the signup will send a test signup request to our backend - click ",Object(o.b)("inlineCode",{parentName:"p"},"Signup")," and see the response with an access token in the network tab of your browser:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/4.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"To send the request, we use the following piece of code:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"axios({\n url: graphqlApiEndpoint,\n method: 'post',\n headers: { Authorization: 'Bearer ' + anonymous },\n data: {\n query: `\n mutation {\n Signup(input: {email: \"${email}\", password: \"${password}\"}) {\n accessToken\n }\n }\n `,\n },\n}\n")),Object(o.b)("p",null,"We use ",Object(o.b)("inlineCode",{parentName:"p"},"axios")," HTTP library to send a ",Object(o.b)("inlineCode",{parentName:"p"},"POST")," request to our ",Object(o.b)("inlineCode",{parentName:"p"},"graphqlApiEndpoint")," (that uses the value of the environment variable we set previously) to run a GraphQL mutation that creates a new user with a given email and password in our AppWrite Cloud backend. In the response, we receive an access token that we can use in the name of the user to interact with the API."),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"anonymous")," token sent in the request is a way to interact with unauthenticated endpoints in the Hasura backend."),Object(o.b)("p",null,"In the next step let\u2019s take care of the list of user projects:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),"const { isLoading, error, data } = useQuery('projects', () => {\n return axios({\n url: graphqlApiEndpoint,\n method: 'POST',\n headers: { Authorization: 'Bearer ' + token },\n data: {\n query: `query Projects {\n project {\n id\n name\n url\n }\n }\n `,\n },\n });\n });\n")),Object(o.b)("p",null,"In the snippet above, we use ",Object(o.b)("inlineCode",{parentName:"p"},"ReactQuery")," to manage the server state (store the info about the project client-side) and axios for performing the HTTP request. In the headers, we send users\u2019 ",Object(o.b)("inlineCode",{parentName:"p"},"accessToken"),", and the payload allows us to specify data that we are interested in about projects we have access to."),Object(o.b)("p",null,"The response from the query contains info we can use to render the list of AppWrite projects managed by AppWriteCloud:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/5.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"Now, to display it, add the following piece of code into our dashboard component:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),'{appwriteProjects.map((project) => (\n\n \n\n))}\n')),Object(o.b)("p",null,"This should allow us to display a list of user\u2019s projects in the dashboard like this:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/6.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"After improving the sign in form (see the whole code repository ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/appwrite-ui"}),"here"),", the whole flow should now look like this:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/7.gif",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"In this article, we bootstrapped a frontend application and added it to our app write cloud. We created the first version of our frontend that makes use of React, Next.js, ReactQuery and Tailwind. The UI is integrated with our backend GraphQL API that is deployed on Qovery and allows us to manage AppWrite projects deployed on AWS for AppWrite Cloud clients."))}p.isMDXComponent=!0},420:function(e,n,t){var a;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=r.a.createContext({}),u=function(e){var n=r.a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):s({},n,{},e)),t},p=function(e){var n=u(e.components);return r.a.createElement(l.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},m=Object(a.forwardRef)((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=u(t),m=a,b=p["".concat(i,".").concat(m)]||p[m]||d[m]||o;return t?r.a.createElement(b,s({ref:n},l,{components:t})):r.a.createElement(b,s({ref:n},l))}));function b(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,i=new Array(o);i[0]=m;var s={};for(var c in n)hasOwnProperty.call(n,c)&&(s[c]=n[c]);s.originalType=e,s.mdxType="string"==typeof e?e:a,i[1]=s;for(var l=2;l1?arguments[1]:void 0,t),c=i>2?arguments[2]:void 0,l=void 0===c?t:r(c,t);l>s;)n[s++]=e;return n}},425:function(e,n,t){var a=t(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||t(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,n,t){"use strict";t(425);var a=t(0),r=t.n(a),o=t(421);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},427:function(e,n,t){"use strict";var a=t(1),r=t(0),o=t.n(r),i=t(39),s=t(430),c=t(20),l=t.n(c);n.a=function(e){var n,t=e.to,c=e.href,u=t||c,p=Object(s.a)(u),d=Object(r.useRef)(!1),m=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&p&&window.docusaurus.prefetch(u),function(){m&&n&&n.disconnect()}}),[u,m,p]),u&&p?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(u),d.current=!0)},innerRef:function(e){var t,a;m&&e&&p&&(t=e,a=function(){window.docusaurus.prefetch(u)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),a())}))}))).observe(t))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},429:function(e,n,t){"use strict";var a=t(0),r=t.n(a),o=t(427),i=t(420),s=t.n(i);t(133);n.a=function(e){var n=e.children,t=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,l=e.size,u=e.target,p=e.to,d=s()("jump-to","jump-to--"+l,t),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",n),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:p,target:u,className:d},m):r.a.createElement(o.a,{to:p,className:d},m)}},430:function(e,n,t){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see 5b95bed2.bc5301c8.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[110],{261:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return s})),t.d(n,"metadata",(function(){return c})),t.d(n,"rightToc",(function(){return l})),t.d(n,"default",(function(){return p}));var a=t(1),r=t(9),o=(t(0),t(425)),i=t(424),s=(t(429),t(431),{last_modified_on:"2022-01-06",$schema:"/.meta/.schemas/guides.json",title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3",readingTime:"9 min read",source:"@site/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",truncated:!1,prevItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2"},nextItem:{title:"How to connect to a managed MongoDB instance on AWS",permalink:"/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws"}},l=[{value:"Bootstrapping Frontend",id:"bootstrapping-frontend",children:[]},{value:"Connecting Backend",id:"connecting-backend",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],u={rightToc:l};function p(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},u,t,{components:n,mdxType:"MDXLayout"}),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},"We assume you are familiar with the previous parts of the AppWrite Cloud series."),Object(o.b)("p",null,"In this part of the series, we will go through the process of adding a web user interface to our AppWrite Cloud platform. We\u2019ll use the Next.js framework to create the frontend application, connect it to our AppWrite Cloud GraphQL API and deploy the app on top of Qovery."),Object(o.b)("h2",{id:"bootstrapping-frontend"},"Bootstrapping Frontend"),Object(o.b)("p",null,"In the first step, let\u2019s create a scaffolding to our frontend application:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"yarn create next-app --example with-tailwindcss frontend\n")),Object(o.b)("p",null,"We use ",Object(o.b)("inlineCode",{parentName:"p"},"Tailwind")," for styling, so the command above bootstraps a ",Object(o.b)("inlineCode",{parentName:"p"},"Next.js")," app with TailwindCSS already set up."),Object(o.b)("p",null,"After the scaffolding is created, create a new remote Git repository on Github, Gitlab or Bitbucket with the application code."),Object(o.b)("p",null,"For building and deploying the app on Qovery, we\u2019ll use Docker - to dockerize the application please add a ",Object(o.b)("inlineCode",{parentName:"p"},"Dockerfile")," with the following content:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'# Install dependencies only when needed\nFROM node:alpine AS deps\n# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.\nRUN apk add --no-cache libc6-compat\nWORKDIR /app\nCOPY package.json yarn.lock ./\nRUN yarn install --frozen-lockfile\n\n# Rebuild the source code only when needed\nFROM node:alpine AS builder\nWORKDIR /app\nCOPY . .\nCOPY --from=deps /app/node_modules ./node_modules\nRUN yarn build && yarn install --production --ignore-scripts --prefer-offline\n\n# Production image, copy all the files and run next\nFROM node:alpine AS runner\nWORKDIR /app\n\nENV NODE_ENV production\n\nRUN addgroup -g 1001 -S nodejs\nRUN adduser -S nextjs -u 1001\n\n# You only need to copy next.config.js if you are NOT using the default configuration\n# COPY --from=builder /app/next.config.js ./\nCOPY --from=builder /app/public ./public\nCOPY --from=builder --chown=nextjs:nodejs /app/.next ./.next\nCOPY --from=builder /app/node_modules ./node_modules\nCOPY --from=builder /app/package.json ./package.json\n\nUSER nextjs\n\nEXPOSE 3000\n\n# Next.js collects completely anonymous telemetry data about general usage.\n# Learn more here: https://nextjs.org/telemetry\n# Uncomment the following line in case you want to disable telemetry.\n# ENV NEXT_TELEMETRY_DISABLED 1\n\nCMD ["yarn", "start"]\n')),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"Dockerfile")," will let Qovery know how to build and run the application. After the Dockerfile is created, add a new application in the AppWrite Cloud project on Qovery with port ",Object(o.b)("inlineCode",{parentName:"p"},"3000")," and ",Object(o.b)("inlineCode",{parentName:"p"},"Docker")," build mode:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/1.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"In the next step let\u2019s add a ",Object(o.b)("inlineCode",{parentName:"p"},"APPWRITE_GRAPHQL_BACKEND")," env variable that we will, later on, use in our frontend. This variable will be an alias to the location of our Hasura application, so we can access its GraphQL API:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/2.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h2",{id:"connecting-backend"},"Connecting Backend"),Object(o.b)("p",null,"Now to quickly deploy the app and test the integration, let\u2019s replace the content of ",Object(o.b)("inlineCode",{parentName:"p"},"index.tsx")," with the following:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'import { Disclosure, Menu, Transition } from \'@headlessui/react\';\nimport { BellIcon, MenuIcon, XIcon } from \'@heroicons/react/outline\';\nimport axios from \'axios\';\nimport { Fragment, useState } from \'react\';\nimport { useMutation } from \'react-query\';\n\nconst anonymous = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLXVzZXItaWQiOiI1IiwieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoiYW5vbnltb3VzIiwieC1oYXN1cmEtYWxsb3dlZC1yb2xlcyI6WyJhbm9ueW1vdXMiXX0sImV4cCI6MTY2NjA3NzAwNn0.Op7qVJAlMm3O2p1sSTMueuTUoUJls1K4pdmiusaz1R0"\n\nconst user = {\n name: \'Tom Cook\',\n email: \'tom@example.com\',\n imageUrl:\n \'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80\',\n};\nconst navigation = [{ name: \'Dashboard\', href: \'#\', current: true }];\nconst userNavigation = [\n { name: \'Your Profile\', href: \'#\' },\n { name: \'Settings\', href: \'#\' },\n { name: \'Sign out\', href: \'#\' },\n];\n\nfunction classNames(...classes) {\n return classes.filter(Boolean).join(\' \');\n}\n\nexport default function Dashboard() {\n return (\n
\n
\n \n {({ open }) => (\n <>\n
\n
\n
\n
\n
\n \n
\n
\n
\n {navigation.map((item) => (\n \n {item.name}\n \n ))}\n
\n
\n
\n
\n
\n \n View notifications\n
\n
\n
\n {/* Mobile menu button */}\n \n Open main menu\n {open ? (\n \n
\n
\n
\n
\n\n \n
\n {navigation.map((item) => (\n \n {item.name}\n \n ))}\n
\n
\n
\n
\n \n
\n
\n
\n {user.name}\n
\n
\n {user.email}\n
\n
\n \n View notifications\n
\n
\n {userNavigation.map((item) => (\n \n {item.name}\n \n ))}\n
\n
\n
\n \n )}\n
\n
\n
\n

Dashboard

\n
\n
\n
\n\n
\n
\n \n \n
\n
\n
\n
\n
\n
\n \n );\n}\n\nconst Signin = (email, password) => {\n const mutation = useMutation((event) => {\n event.preventDefault();\n return axios({\n url: graphqlApiEndpoint,\n method: \'post\',\n headers: { \'Authorization\': \'Bearer \' + anonymous },\n data: {\n query: `\n query Singin {\n Singin(email: "${email}", password: "${password}") {\n accessToken\n }\n }\n `,\n },\n })\n });\n return ;\n};\n\nconst Signup = (email, password) => {\n const mutation = useMutation((event) => {\n event.preventDefault();\n return axios({\n url: graphqlApiEndpoint,\n method: \'post\',\n headers: { \'Authorization\': \'Bearer \' + anonymous },\n data: {\n query: `\n query Signup {\n Signup(email: "${email}", password: "${password}") {\n accessToken\n }\n }\n `,\n },\n })\n });\n return ;\n};\n')),Object(o.b)("p",null,"This makes the skeleton of our UI:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/3.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"Clicking on the signup will send a test signup request to our backend - click ",Object(o.b)("inlineCode",{parentName:"p"},"Signup")," and see the response with an access token in the network tab of your browser:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/4.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"To send the request, we use the following piece of code:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"axios({\n url: graphqlApiEndpoint,\n method: 'post',\n headers: { Authorization: 'Bearer ' + anonymous },\n data: {\n query: `\n mutation {\n Signup(input: {email: \"${email}\", password: \"${password}\"}) {\n accessToken\n }\n }\n `,\n },\n}\n")),Object(o.b)("p",null,"We use ",Object(o.b)("inlineCode",{parentName:"p"},"axios")," HTTP library to send a ",Object(o.b)("inlineCode",{parentName:"p"},"POST")," request to our ",Object(o.b)("inlineCode",{parentName:"p"},"graphqlApiEndpoint")," (that uses the value of the environment variable we set previously) to run a GraphQL mutation that creates a new user with a given email and password in our AppWrite Cloud backend. In the response, we receive an access token that we can use in the name of the user to interact with the API."),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"anonymous")," token sent in the request is a way to interact with unauthenticated endpoints in the Hasura backend."),Object(o.b)("p",null,"In the next step let\u2019s take care of the list of user projects:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),"const { isLoading, error, data } = useQuery('projects', () => {\n return axios({\n url: graphqlApiEndpoint,\n method: 'POST',\n headers: { Authorization: 'Bearer ' + token },\n data: {\n query: `query Projects {\n project {\n id\n name\n url\n }\n }\n `,\n },\n });\n });\n")),Object(o.b)("p",null,"In the snippet above, we use ",Object(o.b)("inlineCode",{parentName:"p"},"ReactQuery")," to manage the server state (store the info about the project client-side) and axios for performing the HTTP request. In the headers, we send users\u2019 ",Object(o.b)("inlineCode",{parentName:"p"},"accessToken"),", and the payload allows us to specify data that we are interested in about projects we have access to."),Object(o.b)("p",null,"The response from the query contains info we can use to render the list of AppWrite projects managed by AppWriteCloud:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/5.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"Now, to display it, add the following piece of code into our dashboard component:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),'{appwriteProjects.map((project) => (\n\n \n\n))}\n')),Object(o.b)("p",null,"This should allow us to display a list of user\u2019s projects in the dashboard like this:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/6.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"After improving the sign in form (see the whole code repository ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/appwrite-ui"}),"here"),", the whole flow should now look like this:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/7.gif",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"In this article, we bootstrapped a frontend application and added it to our app write cloud. We created the first version of our frontend that makes use of React, Next.js, ReactQuery and Tailwind. The UI is integrated with our backend GraphQL API that is deployed on Qovery and allows us to manage AppWrite projects deployed on AWS for AppWrite Cloud clients."))}p.isMDXComponent=!0},423:function(e,n,t){var a;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=r.a.createContext({}),u=function(e){var n=r.a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):s({},n,{},e)),t},p=function(e){var n=u(e.components);return r.a.createElement(l.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},m=Object(a.forwardRef)((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=u(t),m=a,b=p["".concat(i,".").concat(m)]||p[m]||d[m]||o;return t?r.a.createElement(b,s({ref:n},l,{components:t})):r.a.createElement(b,s({ref:n},l))}));function b(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,i=new Array(o);i[0]=m;var s={};for(var c in n)hasOwnProperty.call(n,c)&&(s[c]=n[c]);s.originalType=e,s.mdxType="string"==typeof e?e:a,i[1]=s;for(var l=2;l1?arguments[1]:void 0,t),c=i>2?arguments[2]:void 0,l=void 0===c?t:r(c,t);l>s;)n[s++]=e;return n}},428:function(e,n,t){var a=t(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||t(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,n,t){"use strict";t(428);var a=t(0),r=t.n(a),o=t(424);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},430:function(e,n,t){"use strict";var a=t(1),r=t(0),o=t.n(r),i=t(39),s=t(432),c=t(20),l=t.n(c);n.a=function(e){var n,t=e.to,c=e.href,u=t||c,p=Object(s.a)(u),d=Object(r.useRef)(!1),m=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&p&&window.docusaurus.prefetch(u),function(){m&&n&&n.disconnect()}}),[u,m,p]),u&&p?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(u),d.current=!0)},innerRef:function(e){var t,a;m&&e&&p&&(t=e,a=function(){window.docusaurus.prefetch(u)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),a())}))}))).observe(t))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},431:function(e,n,t){"use strict";var a=t(0),r=t.n(a),o=t(430),i=t(423),s=t.n(i);t(133);n.a=function(e){var n=e.children,t=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,l=e.size,u=e.target,p=e.to,d=s()("jump-to","jump-to--"+l,t),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",n),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:p,target:u,className:d},m):r.a.createElement(o.a,{to:p,className:d},m)}},432:function(e,n,t){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/6308ca27.a3a143cd.js.LICENSE.txt b/5b95bed2.bc5301c8.js.LICENSE.txt similarity index 100% rename from 6308ca27.a3a143cd.js.LICENSE.txt rename to 5b95bed2.bc5301c8.js.LICENSE.txt diff --git a/b7d53051.48e12bb8.js b/5e5fefd2.870a954e.js similarity index 89% rename from b7d53051.48e12bb8.js rename to 5e5fefd2.870a954e.js index 4dbbf533b1..a4d896c62a 100644 --- a/b7d53051.48e12bb8.js +++ b/5e5fefd2.870a954e.js @@ -1,2 +1,2 @@ -/*! For license information please see b7d53051.48e12bb8.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[184],{335:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),o=(n(0),n(422)),i=(n(431),n(426),n(421),{last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Deploy API Gateway",description:"Learn how to deploy an API Gateway with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),c={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Deploy API Gateway",description:"Learn how to deploy an API Gateway with Qovery",permalink:"/guides/advanced/deploy-api-gateway",readingTime:"1 min read",source:"@site/guides/advanced/deploy-api-gateway.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Deploy API Gateway",truncated:!1,prevItem:{title:"Customizing Preview URL with Qovery CLI",permalink:"/guides/tutorial/customizing-preview-url-with-qovery-cli"},nextItem:{title:"Deploy AWS Services",permalink:"/guides/advanced/deploy-aws-services"}},s=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],u={rightToc:s};function l(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"An API Gateway is a web service that acts as an interface between consumers and your services. It acts as a single point of entry into a system and is responsible for request routing, composition, and protocol translation. It's essentially a middleman that processes requests from clients to services."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to deploy your API Gateway with Qovery"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services/"}),"NGINX API Gateway")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services/"}),"Deploy a NGINX API Gateway with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=api%20gateway"}),'Forum "API Gateway"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=api%20gateway"}),'List "API Gateway" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}l.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),l=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),f=r,m=p["".concat(i,".").concat(f)]||p[f]||d[f]||o;return n?a.a.createElement(m,c({ref:t},u,{components:n})):a.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,u=void 0===s?n:a(s,n);u>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),p=l[0],d=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 5e5fefd2.870a954e.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[111],{262:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),o=(n(0),n(425)),i=(n(434),n(429),n(424),{last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Deploy API Gateway",description:"Learn how to deploy an API Gateway with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),c={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Deploy API Gateway",description:"Learn how to deploy an API Gateway with Qovery",permalink:"/guides/advanced/deploy-api-gateway",readingTime:"1 min read",source:"@site/guides/advanced/deploy-api-gateway.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Deploy API Gateway",truncated:!1,prevItem:{title:"Customizing Preview URL with Qovery CLI",permalink:"/guides/tutorial/customizing-preview-url-with-qovery-cli"},nextItem:{title:"Deploy AWS Services",permalink:"/guides/advanced/deploy-aws-services"}},s=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],u={rightToc:s};function l(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"An API Gateway is a web service that acts as an interface between consumers and your services. It acts as a single point of entry into a system and is responsible for request routing, composition, and protocol translation. It's essentially a middleman that processes requests from clients to services."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to deploy your API Gateway with Qovery"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services/"}),"NGINX API Gateway")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services/"}),"Deploy a NGINX API Gateway with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=api%20gateway"}),'Forum "API Gateway"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=api%20gateway"}),'List "API Gateway" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}l.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),l=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),f=r,m=p["".concat(i,".").concat(f)]||p[f]||d[f]||o;return n?a.a.createElement(m,c({ref:t},u,{components:n})):a.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,u=void 0===s?n:a(s,n);u>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),p=l[0],d=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/6504a542.d1ebc542.js.LICENSE.txt b/5e5fefd2.870a954e.js.LICENSE.txt similarity index 100% rename from 6504a542.d1ebc542.js.LICENSE.txt rename to 5e5fefd2.870a954e.js.LICENSE.txt diff --git a/5e60e078.9116c454.js b/5e60e078.7d90fb79.js similarity index 94% rename from 5e60e078.9116c454.js rename to 5e60e078.7d90fb79.js index e88ae7f19f..8c05626a2a 100644 --- a/5e60e078.9116c454.js +++ b/5e60e078.7d90fb79.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[110],{261:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return c})),t.d(r,"metadata",(function(){return i})),t.d(r,"rightToc",(function(){return p})),t.d(r,"default",(function(){return l}));var n=t(1),o=t(9),a=(t(0),t(422)),c={last_modified_on:"2023-05-20",title:"Doppler",description:"Learn how to configure Doppler"},i={id:"using-qovery/integration/secret-manager/doppler",title:"Doppler",description:"Learn how to configure Doppler",source:"@site/docs/using-qovery/integration/secret-manager/doppler.md",permalink:"/docs/using-qovery/integration/secret-manager/doppler",sidebar:"docs",previous:{title:"Secret Manager",permalink:"/docs/using-qovery/integration/secret-manager"},next:{title:"AWS Secrets Manager",permalink:"/docs/using-qovery/integration/secret-manager/aws-secrets-manager"}},p=[],u={rightToc:p};function l(e){var r=e.components,t=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},u,t,{components:r,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Doppler is a universal secrets manager that integrates with Qovery. Doppler allows you to store and manage your application secrets in a single place and access them from anywhere."),Object(a.b)("p",null,"Check out ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"https://docs.doppler.com/docs/qovery"}),"this Doppler documentation")," to integrate Qovery with your Doppler account."))}l.isMDXComponent=!0},422:function(e,r,t){"use strict";t.d(r,"a",(function(){return s})),t.d(r,"b",(function(){return d}));var n=t(0),o=t.n(n);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function c(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function i(e){for(var r=1;r=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var u=o.a.createContext({}),l=function(e){var r=o.a.useContext(u),t=r;return e&&(t="function"==typeof e?e(r):i({},r,{},e)),t},s=function(e){var r=l(e.components);return o.a.createElement(u.Provider,{value:r},e.children)},f={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},m=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,a=e.originalType,c=e.parentName,u=p(e,["components","mdxType","originalType","parentName"]),s=l(t),m=n,d=s["".concat(c,".").concat(m)]||s[m]||f[m]||a;return t?o.a.createElement(d,i({ref:r},u,{components:t})):o.a.createElement(d,i({ref:r},u))}));function d(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var a=t.length,c=new Array(a);c[0]=m;var i={};for(var p in r)hasOwnProperty.call(r,p)&&(i[p]=r[p]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var u=2;u=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var u=o.a.createContext({}),l=function(e){var r=o.a.useContext(u),t=r;return e&&(t="function"==typeof e?e(r):i({},r,{},e)),t},s=function(e){var r=l(e.components);return o.a.createElement(u.Provider,{value:r},e.children)},f={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},m=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,a=e.originalType,c=e.parentName,u=p(e,["components","mdxType","originalType","parentName"]),s=l(t),m=n,d=s["".concat(c,".").concat(m)]||s[m]||f[m]||a;return t?o.a.createElement(d,i({ref:r},u,{components:t})):o.a.createElement(d,i({ref:r},u))}));function d(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var a=t.length,c=new Array(a);c[0]=m;var i={};for(var p in r)hasOwnProperty.call(r,p)&&(i[p]=r[p]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var u=2;u")," and we select the environment variables to import:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery env import .env.development\n\nQovery: dot env file to import: '.env.development'\n? Do you want to import Environment Variables or Secrets? Environment Variables\n? What environment variables do you want to import? [Use arrows to move, space to select, to all, to none, type to filter]\n [x] COLOR_BACKGROUND=fff\n [ ] AUTH0_API_KEY_SECRET=0xb33f\n> [x] API_URL=https://api.mytld.com\n [ ] STRAPI_API_KEY=x.xxyyyzzz\n")),Object(r.b)("p",null,"Once validated you will see the following import validation:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"? What environment variables do you want to import? COLOR_BACKGROUND=fff, API_URL=https://api.mytld.com\nQovery: \u2705 Environment Variables successfully imported!\n")),Object(r.b)("p",null,"If during the import something goes wrong, you will see the errors and why it failed."),Object(r.b)("h3",{id:"secrets"},"Secrets"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Check out the documentation")," to learn more on how Secrets works.")),Object(r.b)("p",null,"To import the Secrets, you need to run the same command ",Object(r.b)("inlineCode",{parentName:"p"},"qovery env import ")," and select the secrets to import."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery env import .env.development\n\nQovery: dot env file to import: '.env.development'\n? Do you want to import Environment Variables or Secrets? Secrets\n? What environment variables do you want to import? [Use arrows to move, space to select, to all, to none, type to filter]\n [ ] COLOR_BACKGROUND=fff\n [x] AUTH0_API_KEY_SECRET=0xb33f\n [ ] API_URL=https://api.mytld.com\n> [x] STRAPI_API_KEY=x.xxyyyzzz\n")),Object(r.b)("p",null,"Once validated you will see the following import validation:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"? What environment variables do you want to import? STRAPI_API_KEY=x.xxyyyzzz, AUTH0_API_KEY_SECRET=0xb33\nQovery: \u2705 Secrets successfully imported!\n")),Object(r.b)("h2",{id:"check"},"Check"),Object(r.b)("p",null,"Open your environment variables console to check that everything has been set correctly."))}d.isMDXComponent=!0},421:function(e,t,a){"use strict";a(423);var n=a(0),o=a.n(n),r=a(420),l=a.n(r);a(132);t.a=function(e){var t=e.children,a=e.classNames,n=e.fill,r=e.icon,c=e.type,i=null;switch(c){case"danger":i="alert-triangle";break;case"success":i="check-circle";break;case"warning":i="alert-triangle";break;default:i="info"}return o.a.createElement("div",{className:l()(a,"alert","alert--"+c,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&o.a.createElement("i",{className:l()("feather","icon-"+(r||i))}),t)}},425:function(e,t,a){var n=a(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||a(10)&&n(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var n=a(0),o=a.n(n),r=a(421);t.a=function(e){var t=e.children,a=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},427:function(e,t,a){"use strict";var n=a(1),o=a(0),r=a.n(o),l=a(39),c=a(430),i=a(20),s=a.n(i);t.a=function(e){var t,a=e.to,i=e.href,b=a||i,u=Object(c.a)(b),m=Object(o.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!p&&u&&window.docusaurus.prefetch(b),function(){p&&t&&t.disconnect()}}),[b,p,u]),b&&u?r.a.createElement(l.b,Object(n.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(b),m.current=!0)},innerRef:function(e){var a,n;p&&e&&u&&(a=e,n=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:b})):r.a.createElement("a",Object(n.a)({},e,{href:b}))}},429:function(e,t,a){"use strict";var n=a(0),o=a.n(n),r=a(427),l=a(420),c=a.n(l);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,l=e.leftIcon,i=e.rightIcon,s=e.size,b=e.target,u=e.to,m=c()("jump-to","jump-to--"+s,a),p=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},l&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+l})),o.a.createElement("div",{className:"jump-to--main"},n?o.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(i||"chevron-right")+" arrow"}))));return b?o.a.createElement("a",{href:u,target:b,className:m},p):o.a.createElement(r.a,{to:u,className:m},p)}},430:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},434:function(e,t,a){"use strict";var n=a(1),o=(a(439),a(436),a(52),a(29),a(22),a(21),a(0)),r=a.n(o),l=a(446),c=a(420),i=a.n(c),s=a(428),b=a.n(s),u=a(445),m=37,p=39;function d(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,o=e.className,l=e.handleKeydown,c=e.style,s=e.values,b=e.selectedValue,u=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:i()("tabs",o,{"tabs--block":t}),style:c},s.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:i()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return l(u,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function v(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,o=e.size,c=e.values,i=c;if(i[0].group){var s=_.groupBy(i,"group");i=Object.keys(s).map((function(e){return{label:e,options:s[e]}}))}return r.a.createElement(l.a,{className:"react-select-container react-select--"+o,classNamePrefix:"react-select",options:i,isClearable:a,placeholder:t,value:c.find((function(e){return e.value==a})),onChange:function(e){return n(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,a=e.defaultValue,l=e.groupId,c=e.label,i=e.placeholder,s=e.select,h=e.size,y=(e.style,e.values),O=e.urlKey,f=Object(u.a)(),j=f.tabGroupChoices,g=f.setTabGroupChoices,w=Object(o.useState)(a),N=w[0],x=w[1];if(null!=l){var I=j[l];null!=I&&I!==N&&x(I)}var T=function(e){x(e),null!=l&&g(l,e)},C=[],E=function(e,t,a){switch(a.keyCode){case p:!function(e,t){var a=e.indexOf(t)+1;e[a]?e[a].focus():e[0].focus()}(e,t);break;case m:!function(e,t){var a=e.indexOf(t)-1;e[a]?e[a].focus():e[e.length-1].focus()}(e,t)}};return Object(o.useEffect)((function(){if("undefined"!=typeof window&&window.location&&O){var e=b.a.parse(window.location.search);e[O]&&x(e[O])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(h||"md")},c&&r.a.createElement("div",{className:"margin-vert--sm"},c),y.length>1&&(s?r.a.createElement(v,Object(n.a)({changeSelectedValue:T,handleKeydown:E,placeholder:i,selectedValue:N,size:h,tabRefs:C},e)):r.a.createElement(d,Object(n.a)({changeSelectedValue:T,handleKeydown:E,selectedValue:N,tabRefs:C},e)))),o.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},441:function(e,t,a){"use strict";var n=a(0),o=a.n(n);t.a=function(e){return o.a.createElement(o.a.Fragment,null,e.children)}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[113],{264:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return b})),a.d(t,"metadata",(function(){return u})),a.d(t,"rightToc",(function(){return m})),a.d(t,"default",(function(){return d}));var n=a(1),o=a(9),r=(a(0),a(425)),l=a(437),c=a(444),i=a(424),s=a(429),b=(a(431),{last_modified_on:"2023-04-23",$schema:"/.meta/.schemas/guides.json",title:"Import your environment variables with the Qovery CLI",description:"How to import your environment variables and secrets from your dotenv file with the Qovery CLI",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),u={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Import your environment variables with the Qovery CLI",description:"How to import your environment variables and secrets from your dotenv file with the Qovery CLI",permalink:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli",readingTime:"5 min read",source:"@site/guides/tutorial/import-your-environment-variables-with-the-qovery-cli.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Import your environment variables with the Qovery CLI",truncated:!1,prevItem:{title:"How to write a Dockerfile",permalink:"/guides/tutorial/how-to-write-a-dockerfile"},nextItem:{title:"Install Qovery on your Amazon Web Services account",permalink:"/guides/cloud-provider/guide-amazon-web-services"}},m=[{value:"Install Qovery CLI",id:"install-qovery-cli",children:[]},{value:"Set your context",id:"set-your-context",children:[]},{value:"Import",id:"import",children:[{value:"Environment Variables",id:"environment-variables",children:[]},{value:"Secrets",id:"secrets",children:[]}]},{value:"Check",id:"check",children:[]}],p={rightToc:m};function d(e){var t=e.components,a=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(n.a)({},p,a,{components:t,mdxType:"MDXLayout"}),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"The Qovery Web Interface support ",Object(r.b)("inlineCode",{parentName:"p"},".env")," (dot env) file import now. ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#import-environment-variables"}),"Check out the documentation"))),Object(r.b)("p",null,"When dealing with dozens of environment variables, it can be tedious to import them one by one. This is where the Qovery CLI with the env vars import feature helps. In this tutorial, you will learn how to import your environment variables and secrets via the Qovery CLI."),Object(r.b)(s.a,{mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Your dotenv (",Object(r.b)("inlineCode",{parentName:"li"},".env"),") file is ",Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://smartmob-rfc.readthedocs.io/en/latest/2-dotenv.html"}),"compliant to the following specs")),Object(r.b)("li",{parentName:"ul"},"You have created your application in Qovery"))),Object(r.b)("h2",{id:"install-qovery-cli"},"Install Qovery CLI"),Object(r.b)(l.a,{centered:!0,className:"rounded",defaultValue:"linux",placeholder:"Select your OS",select:!1,size:null,values:[{group:"Platforms",label:"Linux",value:"linux"},{group:"Platforms",label:"MacOS",value:"macos"},{group:"Platforms",label:"Windows",value:"windows"},{group:"Platforms",label:"Docker",value:"docker"}],mdxType:"Tabs"},Object(r.b)(c.a,{value:"linux",mdxType:"TabItem"},Object(r.b)(l.a,{centered:!0,className:"rounded",defaultValue:"universal",values:[{label:"*nix",value:"universal"},{label:"Arch Linux",value:"arch"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(c.a,{value:"universal",mdxType:"TabItem"},Object(r.b)("p",null,"To download and install Qovery CLI on any Linux distribution:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(r.b)(c.a,{value:"arch",mdxType:"TabItem"},Object(r.b)("p",null,"Qovery is part of ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(r.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Linux manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(r.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(r.b)(c.a,{value:"macos",mdxType:"TabItem"},Object(r.b)(l.a,{centered:!0,className:"rounded",defaultValue:"homebrew",values:[{label:"Homebrew",value:"homebrew"},{label:"Script",value:"script"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(c.a,{value:"homebrew",mdxType:"TabItem"},Object(r.b)("p",null,"The common solution to install a command line binary on the MacOS is to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery brew repository\n$ brew tap Qovery/qovery-cli\n\n# Install the CLI\n$ brew install qovery-cli\n"))),Object(r.b)(c.a,{value:"script",mdxType:"TabItem"},Object(r.b)("p",null,"To download and install Qovery CLI from the command line:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(r.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Mac OS manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(r.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(r.b)(c.a,{value:"windows",mdxType:"TabItem"},Object(r.b)(l.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(c.a,{value:"scoop",mdxType:"TabItem"},Object(r.b)("p",null,"The classic way to install binaries on Windows is to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery bucket\n$ scoop bucket add qovery https://github.com/Qovery/scoop-qovery-cli\n\n# Install the CLI\n$ scoop install qovery-cli\n"))),Object(r.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Windows manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to\n",Object(r.b)("inlineCode",{parentName:"p"},"C:\\Windows"),".")))),Object(r.b)(c.a,{value:"docker",mdxType:"TabItem"},Object(r.b)("p",null,"Install Docker on your local machine and run the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Pull and Run the latest Qovery CLI\n$ docker run ghcr.io/qovery/qovery-cli:latest help\n")),Object(r.b)("p",null,"Change ",Object(r.b)("inlineCode",{parentName:"p"},"latest")," by the version you want to use. For example, to use the version 0.58.4, run:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ docker run ghcr.io/qovery/qovery-cli:0.58.4 help\n")),Object(r.b)("p",null,"Note: ",Object(r.b)("inlineCode",{parentName:"p"},"ghcr.io")," is the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/pkgs/container/qovery-cli"}),"GitHub Container Registry"),"."))),Object(r.b)("h2",{id:"set-your-context"},"Set your context"),Object(r.b)("p",null,"Once you are authenticated with ",Object(r.b)("inlineCode",{parentName:"p"},"qovery auth"),", you must choose the application where you want to set the environment variables with the command ",Object(r.b)("inlineCode",{parentName:"p"},"qovery context set"),"."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="connect to qovery"',title:'"connect',to:!0,'qovery"':!0}),"$ qovery auth\n")),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="set the context"',title:'"set',the:!0,'context"':!0}),"~/Desktop $ qovery context set\nQovery: Current context:\nOrganization | Qovery Community\nProject | posthog\nEnvironment | prod\nApplication | proxy\n\nQovery: Select new context\nOrganization:\n\u2714 Qovery Realm\nProject:\n\u2714 Posthog\nEnvironment:\n\u2714 prod\nApplication:\n\u2714 nginx-proxy\n\nQovery: New context:\nOrganization | Qovery Realm\nProject | Posthog\nEnvironment | prod\nApplication | nginx-proxy\n")),Object(r.b)("h2",{id:"import"},"Import"),Object(r.b)("p",null,"With Qovery, you make the distinction between Environment Variables and Secrets. Basically, the value of a Secret is encrypted and cannot be revealed."),Object(r.b)("p",null,"Let's say that we have the following dotenv file ",Object(r.b)("inlineCode",{parentName:"p"},".env.development")," that we want to import:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-text",metastring:"title=.env.development",title:".env.development"}),"STRAPI_API_KEY=x.xxyyyzzz\nCOLOR_BACKGROUND=fff\nAUTH0_API_KEY_SECRET=0xb33f\nAPI_URL=https://api.mytld.com\n")),Object(r.b)("p",null,"The ",Object(r.b)("inlineCode",{parentName:"p"},"STRAPI_API_KEY")," and ",Object(r.b)("inlineCode",{parentName:"p"},"AUTH0_API_KEY_SECRET")," are Secrets. ",Object(r.b)("inlineCode",{parentName:"p"},"COLOR_BACKGROUND")," and ",Object(r.b)("inlineCode",{parentName:"p"},"API_URL")," are Environment Variables."),Object(r.b)("h3",{id:"environment-variables"},"Environment Variables"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Check out the documentation")," to learn more on how Environment Variables works.")),Object(r.b)("p",null,"To import the Environment Variables from this file we run the command ",Object(r.b)("inlineCode",{parentName:"p"},"qovery env import ")," and we select the environment variables to import:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery env import .env.development\n\nQovery: dot env file to import: '.env.development'\n? Do you want to import Environment Variables or Secrets? Environment Variables\n? What environment variables do you want to import? [Use arrows to move, space to select, to all, to none, type to filter]\n [x] COLOR_BACKGROUND=fff\n [ ] AUTH0_API_KEY_SECRET=0xb33f\n> [x] API_URL=https://api.mytld.com\n [ ] STRAPI_API_KEY=x.xxyyyzzz\n")),Object(r.b)("p",null,"Once validated you will see the following import validation:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"? What environment variables do you want to import? COLOR_BACKGROUND=fff, API_URL=https://api.mytld.com\nQovery: \u2705 Environment Variables successfully imported!\n")),Object(r.b)("p",null,"If during the import something goes wrong, you will see the errors and why it failed."),Object(r.b)("h3",{id:"secrets"},"Secrets"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Check out the documentation")," to learn more on how Secrets works.")),Object(r.b)("p",null,"To import the Secrets, you need to run the same command ",Object(r.b)("inlineCode",{parentName:"p"},"qovery env import ")," and select the secrets to import."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery env import .env.development\n\nQovery: dot env file to import: '.env.development'\n? Do you want to import Environment Variables or Secrets? Secrets\n? What environment variables do you want to import? [Use arrows to move, space to select, to all, to none, type to filter]\n [ ] COLOR_BACKGROUND=fff\n [x] AUTH0_API_KEY_SECRET=0xb33f\n [ ] API_URL=https://api.mytld.com\n> [x] STRAPI_API_KEY=x.xxyyyzzz\n")),Object(r.b)("p",null,"Once validated you will see the following import validation:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"? What environment variables do you want to import? STRAPI_API_KEY=x.xxyyyzzz, AUTH0_API_KEY_SECRET=0xb33\nQovery: \u2705 Secrets successfully imported!\n")),Object(r.b)("h2",{id:"check"},"Check"),Object(r.b)("p",null,"Open your environment variables console to check that everything has been set correctly."))}d.isMDXComponent=!0},424:function(e,t,a){"use strict";a(426);var n=a(0),o=a.n(n),r=a(423),l=a.n(r);a(132);t.a=function(e){var t=e.children,a=e.classNames,n=e.fill,r=e.icon,c=e.type,i=null;switch(c){case"danger":i="alert-triangle";break;case"success":i="check-circle";break;case"warning":i="alert-triangle";break;default:i="info"}return o.a.createElement("div",{className:l()(a,"alert","alert--"+c,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&o.a.createElement("i",{className:l()("feather","icon-"+(r||i))}),t)}},428:function(e,t,a){var n=a(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||a(10)&&n(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var n=a(0),o=a.n(n),r=a(424);t.a=function(e){var t=e.children,a=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},430:function(e,t,a){"use strict";var n=a(1),o=a(0),r=a.n(o),l=a(39),c=a(432),i=a(20),s=a.n(i);t.a=function(e){var t,a=e.to,i=e.href,b=a||i,u=Object(c.a)(b),m=Object(o.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!p&&u&&window.docusaurus.prefetch(b),function(){p&&t&&t.disconnect()}}),[b,p,u]),b&&u?r.a.createElement(l.b,Object(n.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(b),m.current=!0)},innerRef:function(e){var a,n;p&&e&&u&&(a=e,n=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:b})):r.a.createElement("a",Object(n.a)({},e,{href:b}))}},431:function(e,t,a){"use strict";var n=a(0),o=a.n(n),r=a(430),l=a(423),c=a.n(l);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,l=e.leftIcon,i=e.rightIcon,s=e.size,b=e.target,u=e.to,m=c()("jump-to","jump-to--"+s,a),p=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},l&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+l})),o.a.createElement("div",{className:"jump-to--main"},n?o.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(i||"chevron-right")+" arrow"}))));return b?o.a.createElement("a",{href:u,target:b,className:m},p):o.a.createElement(r.a,{to:u,className:m},p)}},432:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},437:function(e,t,a){"use strict";var n=a(1),o=(a(442),a(439),a(52),a(29),a(22),a(21),a(0)),r=a.n(o),l=a(449),c=a(423),i=a.n(c),s=a(433),b=a.n(s),u=a(448),m=37,p=39;function d(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,o=e.className,l=e.handleKeydown,c=e.style,s=e.values,b=e.selectedValue,u=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:i()("tabs",o,{"tabs--block":t}),style:c},s.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:i()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return l(u,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function v(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,o=e.size,c=e.values,i=c;if(i[0].group){var s=_.groupBy(i,"group");i=Object.keys(s).map((function(e){return{label:e,options:s[e]}}))}return r.a.createElement(l.a,{className:"react-select-container react-select--"+o,classNamePrefix:"react-select",options:i,isClearable:a,placeholder:t,value:c.find((function(e){return e.value==a})),onChange:function(e){return n(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,a=e.defaultValue,l=e.groupId,c=e.label,i=e.placeholder,s=e.select,h=e.size,y=(e.style,e.values),O=e.urlKey,f=Object(u.a)(),j=f.tabGroupChoices,g=f.setTabGroupChoices,w=Object(o.useState)(a),N=w[0],x=w[1];if(null!=l){var I=j[l];null!=I&&I!==N&&x(I)}var T=function(e){x(e),null!=l&&g(l,e)},C=[],E=function(e,t,a){switch(a.keyCode){case p:!function(e,t){var a=e.indexOf(t)+1;e[a]?e[a].focus():e[0].focus()}(e,t);break;case m:!function(e,t){var a=e.indexOf(t)-1;e[a]?e[a].focus():e[e.length-1].focus()}(e,t)}};return Object(o.useEffect)((function(){if("undefined"!=typeof window&&window.location&&O){var e=b.a.parse(window.location.search);e[O]&&x(e[O])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(h||"md")},c&&r.a.createElement("div",{className:"margin-vert--sm"},c),y.length>1&&(s?r.a.createElement(v,Object(n.a)({changeSelectedValue:T,handleKeydown:E,placeholder:i,selectedValue:N,size:h,tabRefs:C},e)):r.a.createElement(d,Object(n.a)({changeSelectedValue:T,handleKeydown:E,selectedValue:N,tabRefs:C},e)))),o.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},444:function(e,t,a){"use strict";var n=a(0),o=a.n(n);t.a=function(e){return o.a.createElement(o.a.Fragment,null,e.children)}}}]); \ No newline at end of file diff --git a/60ad046d.46f80442.js b/60ad046d.18b5dcbd.js similarity index 73% rename from 60ad046d.46f80442.js rename to 60ad046d.18b5dcbd.js index 4654925099..56e6631afa 100644 --- a/60ad046d.46f80442.js +++ b/60ad046d.18b5dcbd.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[112],{263:function(o){o.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"technology-github","name":"technology: github","count":1,"permalink":"/guides/tags/technology-github"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[114],{265:function(o){o.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"technology-github","name":"technology: github","count":1,"permalink":"/guides/tags/technology-github"}')}}]); \ No newline at end of file diff --git a/6308ca27.a3a143cd.js b/6308ca27.aa3f3d38.js similarity index 92% rename from 6308ca27.a3a143cd.js rename to 6308ca27.aa3f3d38.js index 9524ad7450..d051dad8c7 100644 --- a/6308ca27.a3a143cd.js +++ b/6308ca27.aa3f3d38.js @@ -1,2 +1,2 @@ -/*! For license information please see 6308ca27.a3a143cd.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[113],{264:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return s})),r.d(t,"metadata",(function(){return c})),r.d(t,"rightToc",(function(){return l})),r.d(t,"default",(function(){return m}));var i=r(1),n=r(9),a=(r(0),r(422)),o=(r(429),r(421)),s=(r(426),{last_modified_on:"2023-10-27",title:"Image Mirroring",description:"Learn how images are mirrored within your cloud account"}),c={id:"using-qovery/deployment/image-mirroring",title:"Image Mirroring",description:"Learn how images are mirrored within your cloud account",source:"@site/docs/using-qovery/deployment/image-mirroring.md",permalink:"/docs/using-qovery/deployment/image-mirroring",sidebar:"docs",previous:{title:"Deployment Strategies",permalink:"/docs/using-qovery/deployment/deployment-strategies"},next:{title:"Troubleshoot",permalink:"/docs/using-qovery/troubleshoot"}},l=[{value:"Application built via the Qovery pipeline",id:"application-built-via-the-qovery-pipeline",children:[]},{value:"Application deployed from a container registry",id:"application-deployed-from-a-container-registry",children:[{value:"Why image mirroring is necessary",id:"why-image-mirroring-is-necessary",children:[]},{value:"Why unique image tags are necessary",id:"why-unique-image-tags-are-necessary",children:[]}]}],u={rightToc:l};function m(e){var t=e.components,r=Object(n.a)(e,["components"]);return Object(a.b)("wrapper",Object(i.a)({},u,r,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"When a cluster is deployed on your cloud account, a dedicated image registry is created to serve as a mirroring system. "),Object(a.b)("p",null,"This ",Object(a.b)("inlineCode",{parentName:"p"},"mirroring registry")," is also available within the Qovery interface"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/mirror-registry.png",alt:"Mirroring Registry"})),Object(a.b)("h1",{id:"how-does-it-work"},"How does it work"),Object(a.b)("p",null,"Every time an application needs to be deployed on your cluster, the application image is mirrored on the mirroring registry."),Object(a.b)("h2",{id:"application-built-via-the-qovery-pipeline"},"Application built via the Qovery pipeline"),Object(a.b)("p",null,'Images within the mirroring registry are organized by "Qovery service", each service has its own repository (or namespace, naming depends on the cloud provider). This means that each service build and mirroring process is completely isolated from the others.'),Object(a.b)("p",null,"Before building the application A1, Qovery checks within mirroring registry at the repository of the application A1 if an image has already being built with the same version (commit id and environment variables). "),Object(a.b)("p",null,"If the image already exists, the built is skipped and Qovery starts the deployment of that image on the Kubernetes cluster."),Object(a.b)("p",null,"Otherwise, the image is built by the Qovery pipeline the resulting image is pushed on the mirroring registry at the repository of the application A1, deleting any previous image."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/build-mirror.png",alt:"Mirroring built image"})),Object(a.b)("p",null,"Given this isolation mechanism, if the same application is cloned (via the ",Object(a.b)("a",Object(i.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#clone-environment"}),"clone")," or ",Object(a.b)("a",Object(i.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#preview-environment"}),"preview environment")," feature), Qovery will re-build the application since the environment variables have changed (the ones at environment level)."),Object(a.b)("h2",{id:"application-deployed-from-a-container-registry"},"Application deployed from a container registry"),Object(a.b)("p",null,"The Qovery behaviour in this case will depend on the chosen ",Object(a.b)("a",Object(i.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cluster-advanced-settings/#image-registry"}),"mirroring mode")," within the cluster advanced settings. "),Object(a.b)("p",null,"Two mirroring modes are available when deploying a service from a container registry:"),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"}," Service (Default) ")),Object(a.b)("p",null,'Images within the mirroring registry are organized by "Qovery service", each service has its own repository (or namespace, naming depends on the cloud provider). This means that each service mirroring process is completely isolated from the others.'),Object(a.b)("p",null,"At the beginning of the deployment of the application A1, Qovery checks within mirroring registry at the repository of the application A1 if an image with the same image name and tag exists. "),Object(a.b)("p",null,"If the image already exists, the mirroring process is skipped and Qovery starts the deployment of that image on the Kubernetes cluster."),Object(a.b)("p",null,"Otherwise, the image is pulled from the source registry and pushed on the mirroring registry at the repository of the application A1, deleting any previous image."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/image-mirror-service.png",alt:"Mirroring image from registry - Service case"})),Object(a.b)("p",null,"Pro:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Images are automatically deleted when not needede anymore")),Object(a.b)("p",null,"Cons:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"If the same image is used across environments or service, Qovery will mirror multiple time the same image, reducing the deployment speed")),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"}," Cluster ")),Object(a.b)(o.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"This is not available on Scaleway.")),Object(a.b)("p",null,'Images within the mirroring registry are organized by "Qovery cluster", meaning that the application deployed on the same cluster are all mirrored on the same repository.'),Object(a.b)("p",null,"At the beginning of the deployment of the application A1, Qovery checks within mirroring registry at the repository of the cluster C1 if an image with the same image name and tag exists. "),Object(a.b)("p",null,"If the image already exists, the mirroring process is skipped and Qovery starts the deployment of that image on the Kubernetes cluster."),Object(a.b)("p",null,"Otherwise, the image is pulled from the source registry and pushed on the mirroring registry at the repository of the cluster C1."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/image-mirror-cluster.png",alt:"Mirroring image from registry - Cluster case"})),Object(a.b)("p",null,"Pro:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"If the same image is used across environments or service, this setup will avoid to mirror multiple time the same image, increasing the deployment speed.")),Object(a.b)("p",null,"Cons:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Qovery can't automatically delete the images mirrored on the mirroring registry. This will increase the cloud provider cost of your image registry since it will store more data. To reduce the amount data stored you can reduce the image TTL via the cluster advanced settings ",Object(a.b)("a",Object(i.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cluster-advanced-settings/#image-registry"}),"registry.image_retention_time"))),Object(a.b)("h3",{id:"why-image-mirroring-is-necessary"},"Why image mirroring is necessary"),Object(a.b)("p",null,"Image mirroring is a general best practice: you don't want your system to be strictly coupled on a third party."),Object(a.b)("p",null,"Let's say that you run an application on your production environment and Kubernetes needs to pull again the image to spawn a new instance for the application. In this case, you don't want to make this fail due to the unavailability of your source container registry. This is why we make sure that a copy is always available on the container registry next to the Kubernetes cluster."),Object(a.b)("h3",{id:"why-unique-image-tags-are-necessary"},"Why unique image tags are necessary"),Object(a.b)("p",null,"When working with containerized applications, it is crucial to employ unique image tags for precise version management. This practice ensures complete confidence in the version running within a container. Failing to use unique image tags can lead to adverse consequences due to the image caching mechanisms employed by both the Qovery mirroring system and Kubernetes:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Mirroring Registry: Qovery\u2019s mirroring system stores images in a registry. If an image tag remains the same between two versions, the new version will not be mirrored. Consequently, the new version will not be deployed, affecting the overall application."),Object(a.b)("li",{parentName:"ul"},"Kubernetes: Applications deployed by Qovery on Kubernetes adhere to the \u201cifNotPresent\u201d image pull policy. This policy means that if the image already exists on the Kubernetes node\u2019s local disk, Kubernetes will not attempt to pull it again. However, if the image tag remains unchanged, the new image version will not be fetched, resulting in your pods running the outdated application code.")),Object(a.b)("p",null,"In summary, maintaining unique image tags is a critical aspect of effective version control and ensuring that your applications run the intended versions without disruptions caused by caching mechanisms."))}m.isMDXComponent=!0},420:function(e,t,r){var i;!function(){"use strict";var r={}.hasOwnProperty;function n(){for(var e=[],t=0;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=n.a.createContext({}),u=function(e){var t=n.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s({},t,{},e)),r},m=function(e){var t=u(e.components);return n.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},g=Object(i.forwardRef)((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,o=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),m=u(r),g=i,h=m["".concat(o,".").concat(g)]||m[g]||p[g]||a;return r?n.a.createElement(h,s({ref:t},l,{components:r})):n.a.createElement(h,s({ref:t},l))}));function h(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,o=new Array(a);o[0]=g;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s.mdxType="string"==typeof e?e:i,o[1]=s;for(var l=2;l1?arguments[1]:void 0,r),c=o>2?arguments[2]:void 0,l=void 0===c?r:n(c,r);l>s;)t[s++]=e;return t}},425:function(e,t,r){var i=r(28).f,n=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in n||r(10)&&i(n,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,r){"use strict";r(425);var i=r(0),n=r.n(i),a=r(421);t.a=function(e){var t=e.children,r=e.name;return n.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},427:function(e,t,r){"use strict";var i=r(1),n=r(0),a=r.n(n),o=r(39),s=r(430),c=r(20),l=r.n(c);t.a=function(e){var t,r=e.to,c=e.href,u=r||c,m=Object(s.a)(u),p=Object(n.useRef)(!1),g=l.a.canUseIntersectionObserver;return Object(n.useEffect)((function(){return!g&&m&&window.docusaurus.prefetch(u),function(){g&&t&&t.disconnect()}}),[u,g,m]),u&&m?a.a.createElement(o.b,Object(i.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var r,i;g&&e&&m&&(r=e,i=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){r===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(r),t.disconnect(),i())}))}))).observe(r))},to:u})):a.a.createElement("a",Object(i.a)({},e,{href:u}))}},429:function(e,t,r){"use strict";var i=r(0),n=r.n(i),a=r(427),o=r(420),s=r.n(o);r(133);t.a=function(e){var t=e.children,r=e.className,i=e.badge,o=e.leftIcon,c=e.rightIcon,l=e.size,u=e.target,m=e.to,p=s()("jump-to","jump-to--"+l,r),g=n.a.createElement("div",{className:"jump-to--inner"},n.a.createElement("div",{className:"jump-to--inner-2"},o&&n.a.createElement("div",{className:"jump-to--left"},n.a.createElement("i",{className:"feather icon-"+o})),n.a.createElement("div",{className:"jump-to--main"},i?n.a.createElement("span",{className:"badge badge--primary badge--right"},i):"",t),n.a.createElement("div",{className:"jump-to--right"},n.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return u?n.a.createElement("a",{href:m,target:u,className:p},g):n.a.createElement(a.a,{to:m,className:p},g)}},430:function(e,t,r){"use strict";function i(e){return!1===/^(https?:|\/\/)/.test(e)}r.d(t,"a",(function(){return i}))}}]); \ No newline at end of file +/*! For license information please see 6308ca27.aa3f3d38.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[115],{266:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return s})),r.d(t,"metadata",(function(){return c})),r.d(t,"rightToc",(function(){return l})),r.d(t,"default",(function(){return m}));var i=r(1),n=r(9),a=(r(0),r(425)),o=(r(431),r(424)),s=(r(429),{last_modified_on:"2023-10-27",title:"Image Mirroring",description:"Learn how images are mirrored within your cloud account"}),c={id:"using-qovery/deployment/image-mirroring",title:"Image Mirroring",description:"Learn how images are mirrored within your cloud account",source:"@site/docs/using-qovery/deployment/image-mirroring.md",permalink:"/docs/using-qovery/deployment/image-mirroring",sidebar:"docs",previous:{title:"Deployment Strategies",permalink:"/docs/using-qovery/deployment/deployment-strategies"},next:{title:"Troubleshoot",permalink:"/docs/using-qovery/troubleshoot"}},l=[{value:"Application built via the Qovery pipeline",id:"application-built-via-the-qovery-pipeline",children:[]},{value:"Application deployed from a container registry",id:"application-deployed-from-a-container-registry",children:[{value:"Why image mirroring is necessary",id:"why-image-mirroring-is-necessary",children:[]},{value:"Why unique image tags are necessary",id:"why-unique-image-tags-are-necessary",children:[]}]}],u={rightToc:l};function m(e){var t=e.components,r=Object(n.a)(e,["components"]);return Object(a.b)("wrapper",Object(i.a)({},u,r,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"When a cluster is deployed on your cloud account, a dedicated image registry is created to serve as a mirroring system. "),Object(a.b)("p",null,"This ",Object(a.b)("inlineCode",{parentName:"p"},"mirroring registry")," is also available within the Qovery interface"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/mirror-registry.png",alt:"Mirroring Registry"})),Object(a.b)("h1",{id:"how-does-it-work"},"How does it work"),Object(a.b)("p",null,"Every time an application needs to be deployed on your cluster, the application image is mirrored on the mirroring registry."),Object(a.b)("h2",{id:"application-built-via-the-qovery-pipeline"},"Application built via the Qovery pipeline"),Object(a.b)("p",null,'Images within the mirroring registry are organized by "Qovery service", each service has its own repository (or namespace, naming depends on the cloud provider). This means that each service build and mirroring process is completely isolated from the others.'),Object(a.b)("p",null,"Before building the application A1, Qovery checks within mirroring registry at the repository of the application A1 if an image has already being built with the same version (commit id and environment variables). "),Object(a.b)("p",null,"If the image already exists, the built is skipped and Qovery starts the deployment of that image on the Kubernetes cluster."),Object(a.b)("p",null,"Otherwise, the image is built by the Qovery pipeline the resulting image is pushed on the mirroring registry at the repository of the application A1, deleting any previous image."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/build-mirror.png",alt:"Mirroring built image"})),Object(a.b)("p",null,"Given this isolation mechanism, if the same application is cloned (via the ",Object(a.b)("a",Object(i.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#clone-environment"}),"clone")," or ",Object(a.b)("a",Object(i.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#preview-environment"}),"preview environment")," feature), Qovery will re-build the application since the environment variables have changed (the ones at environment level)."),Object(a.b)("h2",{id:"application-deployed-from-a-container-registry"},"Application deployed from a container registry"),Object(a.b)("p",null,"The Qovery behaviour in this case will depend on the chosen ",Object(a.b)("a",Object(i.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cluster-advanced-settings/#image-registry"}),"mirroring mode")," within the cluster advanced settings. "),Object(a.b)("p",null,"Two mirroring modes are available when deploying a service from a container registry:"),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"}," Service (Default) ")),Object(a.b)("p",null,'Images within the mirroring registry are organized by "Qovery service", each service has its own repository (or namespace, naming depends on the cloud provider). This means that each service mirroring process is completely isolated from the others.'),Object(a.b)("p",null,"At the beginning of the deployment of the application A1, Qovery checks within mirroring registry at the repository of the application A1 if an image with the same image name and tag exists. "),Object(a.b)("p",null,"If the image already exists, the mirroring process is skipped and Qovery starts the deployment of that image on the Kubernetes cluster."),Object(a.b)("p",null,"Otherwise, the image is pulled from the source registry and pushed on the mirroring registry at the repository of the application A1, deleting any previous image."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/image-mirror-service.png",alt:"Mirroring image from registry - Service case"})),Object(a.b)("p",null,"Pro:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Images are automatically deleted when not needede anymore")),Object(a.b)("p",null,"Cons:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"If the same image is used across environments or service, Qovery will mirror multiple time the same image, reducing the deployment speed")),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"}," Cluster ")),Object(a.b)(o.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"This is not available on Scaleway.")),Object(a.b)("p",null,'Images within the mirroring registry are organized by "Qovery cluster", meaning that the application deployed on the same cluster are all mirrored on the same repository.'),Object(a.b)("p",null,"At the beginning of the deployment of the application A1, Qovery checks within mirroring registry at the repository of the cluster C1 if an image with the same image name and tag exists. "),Object(a.b)("p",null,"If the image already exists, the mirroring process is skipped and Qovery starts the deployment of that image on the Kubernetes cluster."),Object(a.b)("p",null,"Otherwise, the image is pulled from the source registry and pushed on the mirroring registry at the repository of the cluster C1."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/image-mirror-cluster.png",alt:"Mirroring image from registry - Cluster case"})),Object(a.b)("p",null,"Pro:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"If the same image is used across environments or service, this setup will avoid to mirror multiple time the same image, increasing the deployment speed.")),Object(a.b)("p",null,"Cons:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Qovery can't automatically delete the images mirrored on the mirroring registry. This will increase the cloud provider cost of your image registry since it will store more data. To reduce the amount data stored you can reduce the image TTL via the cluster advanced settings ",Object(a.b)("a",Object(i.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cluster-advanced-settings/#image-registry"}),"registry.image_retention_time"))),Object(a.b)("h3",{id:"why-image-mirroring-is-necessary"},"Why image mirroring is necessary"),Object(a.b)("p",null,"Image mirroring is a general best practice: you don't want your system to be strictly coupled on a third party."),Object(a.b)("p",null,"Let's say that you run an application on your production environment and Kubernetes needs to pull again the image to spawn a new instance for the application. In this case, you don't want to make this fail due to the unavailability of your source container registry. This is why we make sure that a copy is always available on the container registry next to the Kubernetes cluster."),Object(a.b)("h3",{id:"why-unique-image-tags-are-necessary"},"Why unique image tags are necessary"),Object(a.b)("p",null,"When working with containerized applications, it is crucial to employ unique image tags for precise version management. This practice ensures complete confidence in the version running within a container. Failing to use unique image tags can lead to adverse consequences due to the image caching mechanisms employed by both the Qovery mirroring system and Kubernetes:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Mirroring Registry: Qovery\u2019s mirroring system stores images in a registry. If an image tag remains the same between two versions, the new version will not be mirrored. Consequently, the new version will not be deployed, affecting the overall application."),Object(a.b)("li",{parentName:"ul"},"Kubernetes: Applications deployed by Qovery on Kubernetes adhere to the \u201cifNotPresent\u201d image pull policy. This policy means that if the image already exists on the Kubernetes node\u2019s local disk, Kubernetes will not attempt to pull it again. However, if the image tag remains unchanged, the new image version will not be fetched, resulting in your pods running the outdated application code.")),Object(a.b)("p",null,"In summary, maintaining unique image tags is a critical aspect of effective version control and ensuring that your applications run the intended versions without disruptions caused by caching mechanisms."))}m.isMDXComponent=!0},423:function(e,t,r){var i;!function(){"use strict";var r={}.hasOwnProperty;function n(){for(var e=[],t=0;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=n.a.createContext({}),u=function(e){var t=n.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s({},t,{},e)),r},m=function(e){var t=u(e.components);return n.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},g=Object(i.forwardRef)((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,o=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),m=u(r),g=i,h=m["".concat(o,".").concat(g)]||m[g]||p[g]||a;return r?n.a.createElement(h,s({ref:t},l,{components:r})):n.a.createElement(h,s({ref:t},l))}));function h(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,o=new Array(a);o[0]=g;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s.mdxType="string"==typeof e?e:i,o[1]=s;for(var l=2;l1?arguments[1]:void 0,r),c=o>2?arguments[2]:void 0,l=void 0===c?r:n(c,r);l>s;)t[s++]=e;return t}},428:function(e,t,r){var i=r(28).f,n=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in n||r(10)&&i(n,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,r){"use strict";r(428);var i=r(0),n=r.n(i),a=r(424);t.a=function(e){var t=e.children,r=e.name;return n.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},430:function(e,t,r){"use strict";var i=r(1),n=r(0),a=r.n(n),o=r(39),s=r(432),c=r(20),l=r.n(c);t.a=function(e){var t,r=e.to,c=e.href,u=r||c,m=Object(s.a)(u),p=Object(n.useRef)(!1),g=l.a.canUseIntersectionObserver;return Object(n.useEffect)((function(){return!g&&m&&window.docusaurus.prefetch(u),function(){g&&t&&t.disconnect()}}),[u,g,m]),u&&m?a.a.createElement(o.b,Object(i.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var r,i;g&&e&&m&&(r=e,i=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){r===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(r),t.disconnect(),i())}))}))).observe(r))},to:u})):a.a.createElement("a",Object(i.a)({},e,{href:u}))}},431:function(e,t,r){"use strict";var i=r(0),n=r.n(i),a=r(430),o=r(423),s=r.n(o);r(133);t.a=function(e){var t=e.children,r=e.className,i=e.badge,o=e.leftIcon,c=e.rightIcon,l=e.size,u=e.target,m=e.to,p=s()("jump-to","jump-to--"+l,r),g=n.a.createElement("div",{className:"jump-to--inner"},n.a.createElement("div",{className:"jump-to--inner-2"},o&&n.a.createElement("div",{className:"jump-to--left"},n.a.createElement("i",{className:"feather icon-"+o})),n.a.createElement("div",{className:"jump-to--main"},i?n.a.createElement("span",{className:"badge badge--primary badge--right"},i):"",t),n.a.createElement("div",{className:"jump-to--right"},n.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return u?n.a.createElement("a",{href:m,target:u,className:p},g):n.a.createElement(a.a,{to:m,className:p},g)}},432:function(e,t,r){"use strict";function i(e){return!1===/^(https?:|\/\/)/.test(e)}r.d(t,"a",(function(){return i}))}}]); \ No newline at end of file diff --git a/66bbed7b.198e1a0b.js.LICENSE.txt b/6308ca27.aa3f3d38.js.LICENSE.txt similarity index 100% rename from 66bbed7b.198e1a0b.js.LICENSE.txt rename to 6308ca27.aa3f3d38.js.LICENSE.txt diff --git a/63ea0c72.3e1d9df3.js b/63ea0c72.df3b603e.js similarity index 74% rename from 63ea0c72.3e1d9df3.js rename to 63ea0c72.df3b603e.js index 3e40bf85f9..3fad7f30b3 100644 --- a/63ea0c72.3e1d9df3.js +++ b/63ea0c72.df3b603e.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[114],{265:function(o){o.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"technology-terraform","name":"technology: terraform","count":1,"permalink":"/guides/tags/technology-terraform"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[116],{267:function(o){o.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"technology-terraform","name":"technology: terraform","count":1,"permalink":"/guides/tags/technology-terraform"}')}}]); \ No newline at end of file diff --git a/6504a542.d1ebc542.js b/6504a542.10583efa.js similarity index 91% rename from 6504a542.d1ebc542.js rename to 6504a542.10583efa.js index d5fd3f381e..611b566ebc 100644 --- a/6504a542.d1ebc542.js +++ b/6504a542.10583efa.js @@ -1,2 +1,2 @@ -/*! For license information please see 6504a542.d1ebc542.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[115],{266:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),a=(n(0),n(422)),i=(n(431),n(426)),c=(n(421),{last_modified_on:"2023-04-13",$schema:"/.meta/.schemas/guides.json",title:"Debugging",description:"How to debug your application",series_position:5,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),s={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Debugging",description:"How to debug your application",permalink:"/guides/getting-started/debugging",readingTime:"3 min read",seriesPosition:5,source:"@site/guides/getting-started/debugging.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Debugging",truncated:!1,prevItem:{title:"Environment variables",permalink:"/guides/getting-started/managing-environment-variables"},nextItem:{title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",permalink:"/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws"}},u=[{value:"Check the status of your app",id:"check-the-status-of-your-app",children:[]},{value:"Live Logs",id:"live-logs",children:[]},{value:"Deployment Logs",id:"deployment-logs",children:[]},{value:"Monitoring",id:"monitoring",children:[]},{value:"Alerting",id:"alerting",children:[]}],l={rightToc:u};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Your application is running, but something goes wrong? In this guide, you'll learn how to debug your application and solve your problem to\nmake it running smoothly."),Object(a.b)(i.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have already deployed an application with Qovery"))),Object(a.b)("p",null,"Your application is running, but for some reason, it is not working as expected. Here are a few tips to find out what's going on."),Object(a.b)("h2",{id:"check-the-status-of-your-app"},"Check the status of your app"),Object(a.b)("p",null,"Qovery expose in the interface the running status of your application which provides you some highlevel information of its healthiness. You can look ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/running-and-deployment-statuses/"}),"in this section")," to know more about the ",Object(a.b)("inlineCode",{parentName:"p"},"Running Status")),Object(a.b)("p",null,"If the service crashes, its ",Object(a.b)("inlineCode",{parentName:"p"},"Running Status")," will be displayed as a red dot. If that's the case, you can have a look at the logs to investigate the reason behind."),Object(a.b)("h2",{id:"live-logs"},"Live Logs"),Object(a.b)("p",null,"If you need to see the log output of your application while it's running, qovery expose them to you in real-time thanks to the Logs interface. You can have a look at ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#live-logs"}),"this section")," to know more."),Object(a.b)("p",null,"You can use this information to find out what causes your application to behave incorrectly."),Object(a.b)("h2",{id:"deployment-logs"},"Deployment Logs"),Object(a.b)("p",null,"If your application fails to start, you can check what's the cause in its deployment logs. You can have a look at ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#deployment-logs"}),"this section")," to have more information on the deployment logs and how to access them."),Object(a.b)("p",null,"This view provides insight into the build and deployment process. If anything goes wrong, you can see all the required information to fix the problem here."),Object(a.b)("p",null,"You can check the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/troubleshoot/"}),"Troubleshoot section")," to investigate any issue you might encounter during the deployment of your services."),Object(a.b)("h2",{id:"monitoring"},"Monitoring"),Object(a.b)("p",null,"If you need more information about the resources consumed by your application, Qovery provides basic metrics about your CPU, memory and storage usage."),Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Navigate to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(a.b)("li",null,Object(a.b)("p",null,"Choose your project, environment, and application.")),Object(a.b)("li",null,Object(a.b)("p",null,"In the main application view, you can see a table with the current application resource consumption."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/debugging/metrics.png",alt:"Metrics"})))),Object(a.b)("h2",{id:"alerting"},"Alerting"),Object(a.b)("p",null,"We highly recommend using tools like ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.datadoghq.com"}),"Datadog"),", ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://sentry.io/"}),"Sentry")," or ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://newrelic.com/"}),"NewRelic")," to manage your alerting.\nQovery will provide easy integrations in the coming release. Check out our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://roadmap.qovery.com/"}),"roadmap")),Object(a.b)("p",null,"Do you need any help? ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discord.qovery.com"}),"Reach us on Discord")))}p.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),l=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,g=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return n?o.a.createElement(g,c({ref:t},u,{components:n})):o.a.createElement(g,c({ref:t},u))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,u=void 0===s?n:o(s,n);u>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),p=l[0],b=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 6504a542.10583efa.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[117],{268:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),a=(n(0),n(425)),i=(n(434),n(429)),c=(n(424),{last_modified_on:"2023-04-13",$schema:"/.meta/.schemas/guides.json",title:"Debugging",description:"How to debug your application",series_position:5,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),s={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Debugging",description:"How to debug your application",permalink:"/guides/getting-started/debugging",readingTime:"3 min read",seriesPosition:5,source:"@site/guides/getting-started/debugging.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Debugging",truncated:!1,prevItem:{title:"Environment variables",permalink:"/guides/getting-started/managing-environment-variables"},nextItem:{title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",permalink:"/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws"}},u=[{value:"Check the status of your app",id:"check-the-status-of-your-app",children:[]},{value:"Live Logs",id:"live-logs",children:[]},{value:"Deployment Logs",id:"deployment-logs",children:[]},{value:"Monitoring",id:"monitoring",children:[]},{value:"Alerting",id:"alerting",children:[]}],l={rightToc:u};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Your application is running, but something goes wrong? In this guide, you'll learn how to debug your application and solve your problem to\nmake it running smoothly."),Object(a.b)(i.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have already deployed an application with Qovery"))),Object(a.b)("p",null,"Your application is running, but for some reason, it is not working as expected. Here are a few tips to find out what's going on."),Object(a.b)("h2",{id:"check-the-status-of-your-app"},"Check the status of your app"),Object(a.b)("p",null,"Qovery expose in the interface the running status of your application which provides you some highlevel information of its healthiness. You can look ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/running-and-deployment-statuses/"}),"in this section")," to know more about the ",Object(a.b)("inlineCode",{parentName:"p"},"Running Status")),Object(a.b)("p",null,"If the service crashes, its ",Object(a.b)("inlineCode",{parentName:"p"},"Running Status")," will be displayed as a red dot. If that's the case, you can have a look at the logs to investigate the reason behind."),Object(a.b)("h2",{id:"live-logs"},"Live Logs"),Object(a.b)("p",null,"If you need to see the log output of your application while it's running, qovery expose them to you in real-time thanks to the Logs interface. You can have a look at ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#live-logs"}),"this section")," to know more."),Object(a.b)("p",null,"You can use this information to find out what causes your application to behave incorrectly."),Object(a.b)("h2",{id:"deployment-logs"},"Deployment Logs"),Object(a.b)("p",null,"If your application fails to start, you can check what's the cause in its deployment logs. You can have a look at ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#deployment-logs"}),"this section")," to have more information on the deployment logs and how to access them."),Object(a.b)("p",null,"This view provides insight into the build and deployment process. If anything goes wrong, you can see all the required information to fix the problem here."),Object(a.b)("p",null,"You can check the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/troubleshoot/"}),"Troubleshoot section")," to investigate any issue you might encounter during the deployment of your services."),Object(a.b)("h2",{id:"monitoring"},"Monitoring"),Object(a.b)("p",null,"If you need more information about the resources consumed by your application, Qovery provides basic metrics about your CPU, memory and storage usage."),Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Navigate to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(a.b)("li",null,Object(a.b)("p",null,"Choose your project, environment, and application.")),Object(a.b)("li",null,Object(a.b)("p",null,"In the main application view, you can see a table with the current application resource consumption."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/debugging/metrics.png",alt:"Metrics"})))),Object(a.b)("h2",{id:"alerting"},"Alerting"),Object(a.b)("p",null,"We highly recommend using tools like ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.datadoghq.com"}),"Datadog"),", ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://sentry.io/"}),"Sentry")," or ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://newrelic.com/"}),"NewRelic")," to manage your alerting.\nQovery will provide easy integrations in the coming release. Check out our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://roadmap.qovery.com/"}),"roadmap")),Object(a.b)("p",null,"Do you need any help? ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discord.qovery.com"}),"Reach us on Discord")))}p.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),l=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,g=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return n?o.a.createElement(g,c({ref:t},u,{components:n})):o.a.createElement(g,c({ref:t},u))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,u=void 0===s?n:o(s,n);u>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),p=l[0],b=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/672ba3d6.edd98258.js.LICENSE.txt b/6504a542.10583efa.js.LICENSE.txt similarity index 100% rename from 672ba3d6.edd98258.js.LICENSE.txt rename to 6504a542.10583efa.js.LICENSE.txt diff --git a/dea3d534.694e9d54.js b/66bbed7b.709e2f79.js similarity index 94% rename from dea3d534.694e9d54.js rename to 66bbed7b.709e2f79.js index 4479623d6d..b7d50f6cee 100644 --- a/dea3d534.694e9d54.js +++ b/66bbed7b.709e2f79.js @@ -1,2 +1,2 @@ -/*! For license information please see dea3d534.694e9d54.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[233],{385:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return p})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var a=n(1),r=n(9),o=(n(0),n(422)),i=n(431),c=n(426),l=n(421),s={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Microservices",description:"How to deploy microservices with Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: guide","technology: qovery"]},p={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Microservices",description:"How to deploy microservices with Qovery",permalink:"/guides/advanced/microservices",readingTime:"6 min read",source:"@site/guides/advanced/microservices.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Microservices",truncated:!1,prevItem:{title:"Managing Environment Variables in React (create-react-app)",permalink:"/guides/tutorial/managing-env-variables-in-create-react-app"},nextItem:{title:"Migrate your application from Heroku to AWS",permalink:"/guides/tutorial/migrate-your-application-from-heroku-to-aws"}},u=[{value:"Deploy Application A",id:"deploy-application-a",children:[{value:"Exposing public API",id:"exposing-public-api",children:[]}]},{value:"Deploy Application B",id:"deploy-application-b",children:[]},{value:"Deploy Database",id:"deploy-database",children:[]},{value:"Use the database",id:"use-the-database",children:[]},{value:"Consume internal APIs",id:"consume-internal-apis",children:[]},{value:"Consume the public API in the frontend application",id:"consume-the-public-api-in-the-frontend-application",children:[]},{value:"Summary",id:"summary",children:[]},{value:"Q&A",id:"qa",children:[]}],b={rightToc:u};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)(l.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"This guide is a bit outdated. We are working on a new version of it. Stay tuned!")),Object(o.b)(c.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have already deployed an application with Qovery"),Object(o.b)("li",{parentName:"ul"},"You are familiar with the concept of Microservices"))),Object(o.b)("p",null,"In this guide, we'll deploy a set of microservices, a database and a frontend UI application that consumes our public API.\nOur backend microservices will communicate on a secure internal network, not accessible from the outside.\nOur front-end application will consume the API only from the publicly exposed application."),Object(o.b)("p",null,"The schema of what we want to achieve:"),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros.jpg",alt:"Microservices"})),Object(o.b)("p",null,"As you can see in the picture:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"we have two backend applications (",Object(o.b)("strong",{parentName:"li"},"App A")," and ",Object(o.b)("strong",{parentName:"li"},"App B"),")"),Object(o.b)("li",{parentName:"ul"},"one of them (",Object(o.b)("strong",{parentName:"li"},"App B"),") connected to a database"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"App A")," exposes a public API that is consumed by API clients (our frontend application run in users browsers)."),Object(o.b)("li",{parentName:"ul"},"additionally, we host our frontend application (",Object(o.b)("strong",{parentName:"li"},"UI"),") on Qovery so that users can access it directly in their browsers.")),Object(o.b)("p",null,"What differentiates Qovery from most other similar platforms is its first-class support of microservices. At Qovery, your project can be easily\ncomposed of multiple applications. It's up to you to decide how to build your system, but Qovery enables you to easily and safely communicate between your backend applications, databases, and frontend websites."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h2",{id:"deploy-application-a"},"Deploy Application A"),Object(o.b)(l.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This guide assumes you already know how to deploy applications. If you have any problems, refer to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"this video guide"),".")),Object(o.b)("p",null,"In the first step, deploy an application named ",Object(o.b)("strong",{parentName:"p"},"APP_A")," in your environment."),Object(o.b)("p",null,"Assumptions:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The app exposes REST API over HTTP on port 8080"),Object(o.b)("li",{parentName:"ul"},"The app name is ",Object(o.b)("strong",{parentName:"li"},"APP_A"))),Object(o.b)("p",null,"After the application is created, let's expose the API publicly - it will be used later on by our frontend application."),Object(o.b)("h3",{id:"exposing-public-api"},"Exposing public API"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate to ",Object(o.b)("strong",{parentName:"li"},"APP_A")," application settings"),Object(o.b)("li",{parentName:"ul"},"Select ",Object(o.b)("strong",{parentName:"li"},"Port")),Object(o.b)("li",{parentName:"ul"},"Add port 8080")),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros-1.png",alt:"Microservices"})),Object(o.b)("p",null,"This is it. By default, Qovery exposes your ports publicly over HTTPS on port 443, so the app should be publicly accessible and reachable later on by our frontend application.")),Object(o.b)("li",null,Object(o.b)("h2",{id:"deploy-application-b"},"Deploy Application B"),Object(o.b)("p",null,"In the second step, deploy an application named ",Object(o.b)("strong",{parentName:"p"},"APP_B")," in your environment."),Object(o.b)("p",null,"Assumptions:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The app exposes REST API over HTTP on port 8080"),Object(o.b)("li",{parentName:"ul"},"The app name is ",Object(o.b)("strong",{parentName:"li"},"APP_B")),Object(o.b)("li",{parentName:"ul"},"The app is ready to use a PostgreSQL client to connect to a PostgreSQL database")),Object(o.b)("p",null,"Steps to do:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate to ",Object(o.b)("strong",{parentName:"li"},"APP_B")," application settings"),Object(o.b)("li",{parentName:"ul"},"Select ",Object(o.b)("strong",{parentName:"li"},"Port")),Object(o.b)("li",{parentName:"ul"},"Add port 8080"),Object(o.b)("li",{parentName:"ul"},"Click ",Object(o.b)("strong",{parentName:"li"},"Advanced")," settings in the 8080 port"),Object(o.b)("li",{parentName:"ul"},"Remove the check from the ",Object(o.b)("strong",{parentName:"li"},"Publicly Accessible")," field")),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros-2.png",alt:"Microservices"})),Object(o.b)(l.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"It will make your ",Object(o.b)("strong",{parentName:"p"},"APP_B")," application not reachable publicly. It will be only reachable on the internal network by other microservices in your environment."))),Object(o.b)("li",null,Object(o.b)("h2",{id:"deploy-database"},"Deploy Database"),Object(o.b)("p",null,"In this step, we'll deploy a PostgreSQL database that we'll consume in ",Object(o.b)("strong",{parentName:"p"},"APP_B")," in the next step."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate to the environment in which you previously deployed your apps"),Object(o.b)("li",{parentName:"ul"},"Create a new PostgreSQL database named ",Object(o.b)("strong",{parentName:"li"},"MY_DB"))),Object(o.b)(l.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This guide assumes you already know how to deploy databases. If you have any problems, refer to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"this video guide"),"."))),Object(o.b)("li",null,Object(o.b)("h2",{id:"use-the-database"},"Use the database"),Object(o.b)("p",null,"In this step, we'll make use of our database in ",Object(o.b)("strong",{parentName:"p"},"APP_B")),Object(o.b)("p",null,"All you need to do to consume your database in ",Object(o.b)("strong",{parentName:"p"},"APP_B")," is to configure your PostgreSQL client to use ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," secrets injected by Qovery.\nYou can read more about this concept ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-a-database"}),"here"),"."),Object(o.b)("p",null,"If your ",Object(o.b)("strong",{parentName:"p"},"APP_B")," is a Node.js application, this examplary code snippet will work well:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"const { Client } = require('pg')\n\nconst client = new Client({\n host: process.env.QOVERY_DATABASE_MY_DB_HOST,\n port: process.env.QOVERY_DATABASE_MY_DB_PORT,\n user: process.env.QOVERY_DATABASE_MY_DB_USER,\n password: process.env.QOVERY_DATABASE_MY_DB_PASSWORD,\n})\n\nclient.connect(err => {\n if (err) {\n console.error('connection error', err.stack)\n } else {\n console.log('connected')\n }\n})\n")),Object(o.b)("p",null,"This is it! After deploying the database, application and executing the code snippet, you should see the message ",Object(o.b)("inlineCode",{parentName:"p"},"connected"),"."),Object(o.b)("p",null,"We made use of ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," variables injected by Qovery to make it easy to consume all the services within the environment.")),Object(o.b)("li",null,Object(o.b)("h2",{id:"consume-internal-apis"},"Consume internal APIs"),Object(o.b)("p",null,"In this step, we'll use the private API of our ",Object(o.b)("strong",{parentName:"p"},"APP_B")," in our ",Object(o.b)("strong",{parentName:"p"},"APP_A")," over a private network.\nWe have already configured everything to make it work. The only missing step is the configuration in ",Object(o.b)("strong",{parentName:"p"},"APP_A")," - it needs to know how to access our ",Object(o.b)("strong",{parentName:"p"},"APP_B"),"."),Object(o.b)("p",null,"In the example below, we'll use Node.js and ",Object(o.b)("inlineCode",{parentName:"p"},"axios")," to create an HTTP client able to consume the API of ",Object(o.b)("strong",{parentName:"p"},"APP_B"),":"),Object(o.b)("p",null,"Now, you can configure your HTTP client in the frontend application to target your backend API:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"const axios = require('axios');\nconst appBAddress = \"http://\" + process.env.QOVERY_APPLICATION_APP_B_HOST + \":\" + process.env.QOVERY_APPLICATION_APP_B_PORT\n\naxios.get(appBAddress + '/api/users')\n .then(response => {\n console.log(response.data);\n })\n .catch(error => {\n console.log(error);\n });\n")),Object(o.b)("p",null,"This is it! ",Object(o.b)("strong",{parentName:"p"},"Every request using the API client we have just configured will consume the API of "),"APP_B",Object(o.b)("strong",{parentName:"p"}," over the secure, internal network.")),Object(o.b)("p",null,"Once again, we used the ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," secrets. Read more about them ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-another-application"}),"here"))),Object(o.b)("li",null,Object(o.b)("h2",{id:"consume-the-public-api-in-the-frontend-application"},"Consume the public API in the frontend application"),Object(o.b)("p",null,"In this step, we'll deploy a frontend application and consume our public API exposed by ",Object(o.b)("strong",{parentName:"p"},"APP_A"),"."),Object(o.b)("p",null,"In the first step, create your frontend application."),Object(o.b)("p",null,"After the application is created, we can easily configure it to consume our public API. All we need to do is to make use of the ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," secrets. See how to achieve it in a Nuxt.js example below:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"export default {\n env: {\n apiUrl: process.env.QOVERY_APPLICATION_APP_A_URL\n }\n}\n")),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"import axios from 'axios'\n\nexport default axios.create({\n baseURL: process.env.apiUrl\n})\n")),Object(o.b)("p",null,"After providing the configuration from above, deploy your frontend application."),Object(o.b)("p",null,"Now our frontend application will be able to consume the API exposed by the publicly exposed ",Object(o.b)("strong",{parentName:"p"},"APP_A"),".")))),Object(o.b)("h2",{id:"summary"},"Summary"),Object(o.b)("p",null,"In this guide, we deployed two microservices that communicate over the internal network. We also deployed a frontend application that makes use of a public API exposed by one of our applications. At the same time, we deployed a database and connected it to the second of our backend microservices."),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}d.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),p=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=p(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=p(n),d=a,m=u["".concat(i,".").concat(d)]||u[d]||b[d]||o;return n?r.a.createElement(m,c({ref:t},s,{components:n})):r.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var a=n(432),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(n(a,e,i.length))})),i.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),p=Object(a.useState)(null),u=p[0],b=p[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 66bbed7b.709e2f79.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[118],{269:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return p})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var a=n(1),r=n(9),o=(n(0),n(425)),i=n(434),c=n(429),l=n(424),s={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Microservices",description:"How to deploy microservices with Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: guide","technology: qovery"]},p={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Microservices",description:"How to deploy microservices with Qovery",permalink:"/guides/advanced/microservices",readingTime:"6 min read",source:"@site/guides/advanced/microservices.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Microservices",truncated:!1,prevItem:{title:"Managing Environment Variables in React (create-react-app)",permalink:"/guides/tutorial/managing-env-variables-in-create-react-app"},nextItem:{title:"Migrate your application from Heroku to AWS",permalink:"/guides/tutorial/migrate-your-application-from-heroku-to-aws"}},u=[{value:"Deploy Application A",id:"deploy-application-a",children:[{value:"Exposing public API",id:"exposing-public-api",children:[]}]},{value:"Deploy Application B",id:"deploy-application-b",children:[]},{value:"Deploy Database",id:"deploy-database",children:[]},{value:"Use the database",id:"use-the-database",children:[]},{value:"Consume internal APIs",id:"consume-internal-apis",children:[]},{value:"Consume the public API in the frontend application",id:"consume-the-public-api-in-the-frontend-application",children:[]},{value:"Summary",id:"summary",children:[]},{value:"Q&A",id:"qa",children:[]}],b={rightToc:u};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)(l.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"This guide is a bit outdated. We are working on a new version of it. Stay tuned!")),Object(o.b)(c.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have already deployed an application with Qovery"),Object(o.b)("li",{parentName:"ul"},"You are familiar with the concept of Microservices"))),Object(o.b)("p",null,"In this guide, we'll deploy a set of microservices, a database and a frontend UI application that consumes our public API.\nOur backend microservices will communicate on a secure internal network, not accessible from the outside.\nOur front-end application will consume the API only from the publicly exposed application."),Object(o.b)("p",null,"The schema of what we want to achieve:"),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros.jpg",alt:"Microservices"})),Object(o.b)("p",null,"As you can see in the picture:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"we have two backend applications (",Object(o.b)("strong",{parentName:"li"},"App A")," and ",Object(o.b)("strong",{parentName:"li"},"App B"),")"),Object(o.b)("li",{parentName:"ul"},"one of them (",Object(o.b)("strong",{parentName:"li"},"App B"),") connected to a database"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"App A")," exposes a public API that is consumed by API clients (our frontend application run in users browsers)."),Object(o.b)("li",{parentName:"ul"},"additionally, we host our frontend application (",Object(o.b)("strong",{parentName:"li"},"UI"),") on Qovery so that users can access it directly in their browsers.")),Object(o.b)("p",null,"What differentiates Qovery from most other similar platforms is its first-class support of microservices. At Qovery, your project can be easily\ncomposed of multiple applications. It's up to you to decide how to build your system, but Qovery enables you to easily and safely communicate between your backend applications, databases, and frontend websites."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h2",{id:"deploy-application-a"},"Deploy Application A"),Object(o.b)(l.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This guide assumes you already know how to deploy applications. If you have any problems, refer to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"this video guide"),".")),Object(o.b)("p",null,"In the first step, deploy an application named ",Object(o.b)("strong",{parentName:"p"},"APP_A")," in your environment."),Object(o.b)("p",null,"Assumptions:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The app exposes REST API over HTTP on port 8080"),Object(o.b)("li",{parentName:"ul"},"The app name is ",Object(o.b)("strong",{parentName:"li"},"APP_A"))),Object(o.b)("p",null,"After the application is created, let's expose the API publicly - it will be used later on by our frontend application."),Object(o.b)("h3",{id:"exposing-public-api"},"Exposing public API"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate to ",Object(o.b)("strong",{parentName:"li"},"APP_A")," application settings"),Object(o.b)("li",{parentName:"ul"},"Select ",Object(o.b)("strong",{parentName:"li"},"Port")),Object(o.b)("li",{parentName:"ul"},"Add port 8080")),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros-1.png",alt:"Microservices"})),Object(o.b)("p",null,"This is it. By default, Qovery exposes your ports publicly over HTTPS on port 443, so the app should be publicly accessible and reachable later on by our frontend application.")),Object(o.b)("li",null,Object(o.b)("h2",{id:"deploy-application-b"},"Deploy Application B"),Object(o.b)("p",null,"In the second step, deploy an application named ",Object(o.b)("strong",{parentName:"p"},"APP_B")," in your environment."),Object(o.b)("p",null,"Assumptions:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The app exposes REST API over HTTP on port 8080"),Object(o.b)("li",{parentName:"ul"},"The app name is ",Object(o.b)("strong",{parentName:"li"},"APP_B")),Object(o.b)("li",{parentName:"ul"},"The app is ready to use a PostgreSQL client to connect to a PostgreSQL database")),Object(o.b)("p",null,"Steps to do:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate to ",Object(o.b)("strong",{parentName:"li"},"APP_B")," application settings"),Object(o.b)("li",{parentName:"ul"},"Select ",Object(o.b)("strong",{parentName:"li"},"Port")),Object(o.b)("li",{parentName:"ul"},"Add port 8080"),Object(o.b)("li",{parentName:"ul"},"Click ",Object(o.b)("strong",{parentName:"li"},"Advanced")," settings in the 8080 port"),Object(o.b)("li",{parentName:"ul"},"Remove the check from the ",Object(o.b)("strong",{parentName:"li"},"Publicly Accessible")," field")),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros-2.png",alt:"Microservices"})),Object(o.b)(l.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"It will make your ",Object(o.b)("strong",{parentName:"p"},"APP_B")," application not reachable publicly. It will be only reachable on the internal network by other microservices in your environment."))),Object(o.b)("li",null,Object(o.b)("h2",{id:"deploy-database"},"Deploy Database"),Object(o.b)("p",null,"In this step, we'll deploy a PostgreSQL database that we'll consume in ",Object(o.b)("strong",{parentName:"p"},"APP_B")," in the next step."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate to the environment in which you previously deployed your apps"),Object(o.b)("li",{parentName:"ul"},"Create a new PostgreSQL database named ",Object(o.b)("strong",{parentName:"li"},"MY_DB"))),Object(o.b)(l.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This guide assumes you already know how to deploy databases. If you have any problems, refer to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"this video guide"),"."))),Object(o.b)("li",null,Object(o.b)("h2",{id:"use-the-database"},"Use the database"),Object(o.b)("p",null,"In this step, we'll make use of our database in ",Object(o.b)("strong",{parentName:"p"},"APP_B")),Object(o.b)("p",null,"All you need to do to consume your database in ",Object(o.b)("strong",{parentName:"p"},"APP_B")," is to configure your PostgreSQL client to use ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," secrets injected by Qovery.\nYou can read more about this concept ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-a-database"}),"here"),"."),Object(o.b)("p",null,"If your ",Object(o.b)("strong",{parentName:"p"},"APP_B")," is a Node.js application, this examplary code snippet will work well:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"const { Client } = require('pg')\n\nconst client = new Client({\n host: process.env.QOVERY_DATABASE_MY_DB_HOST,\n port: process.env.QOVERY_DATABASE_MY_DB_PORT,\n user: process.env.QOVERY_DATABASE_MY_DB_USER,\n password: process.env.QOVERY_DATABASE_MY_DB_PASSWORD,\n})\n\nclient.connect(err => {\n if (err) {\n console.error('connection error', err.stack)\n } else {\n console.log('connected')\n }\n})\n")),Object(o.b)("p",null,"This is it! After deploying the database, application and executing the code snippet, you should see the message ",Object(o.b)("inlineCode",{parentName:"p"},"connected"),"."),Object(o.b)("p",null,"We made use of ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," variables injected by Qovery to make it easy to consume all the services within the environment.")),Object(o.b)("li",null,Object(o.b)("h2",{id:"consume-internal-apis"},"Consume internal APIs"),Object(o.b)("p",null,"In this step, we'll use the private API of our ",Object(o.b)("strong",{parentName:"p"},"APP_B")," in our ",Object(o.b)("strong",{parentName:"p"},"APP_A")," over a private network.\nWe have already configured everything to make it work. The only missing step is the configuration in ",Object(o.b)("strong",{parentName:"p"},"APP_A")," - it needs to know how to access our ",Object(o.b)("strong",{parentName:"p"},"APP_B"),"."),Object(o.b)("p",null,"In the example below, we'll use Node.js and ",Object(o.b)("inlineCode",{parentName:"p"},"axios")," to create an HTTP client able to consume the API of ",Object(o.b)("strong",{parentName:"p"},"APP_B"),":"),Object(o.b)("p",null,"Now, you can configure your HTTP client in the frontend application to target your backend API:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"const axios = require('axios');\nconst appBAddress = \"http://\" + process.env.QOVERY_APPLICATION_APP_B_HOST + \":\" + process.env.QOVERY_APPLICATION_APP_B_PORT\n\naxios.get(appBAddress + '/api/users')\n .then(response => {\n console.log(response.data);\n })\n .catch(error => {\n console.log(error);\n });\n")),Object(o.b)("p",null,"This is it! ",Object(o.b)("strong",{parentName:"p"},"Every request using the API client we have just configured will consume the API of "),"APP_B",Object(o.b)("strong",{parentName:"p"}," over the secure, internal network.")),Object(o.b)("p",null,"Once again, we used the ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," secrets. Read more about them ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-another-application"}),"here"))),Object(o.b)("li",null,Object(o.b)("h2",{id:"consume-the-public-api-in-the-frontend-application"},"Consume the public API in the frontend application"),Object(o.b)("p",null,"In this step, we'll deploy a frontend application and consume our public API exposed by ",Object(o.b)("strong",{parentName:"p"},"APP_A"),"."),Object(o.b)("p",null,"In the first step, create your frontend application."),Object(o.b)("p",null,"After the application is created, we can easily configure it to consume our public API. All we need to do is to make use of the ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," secrets. See how to achieve it in a Nuxt.js example below:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"export default {\n env: {\n apiUrl: process.env.QOVERY_APPLICATION_APP_A_URL\n }\n}\n")),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"import axios from 'axios'\n\nexport default axios.create({\n baseURL: process.env.apiUrl\n})\n")),Object(o.b)("p",null,"After providing the configuration from above, deploy your frontend application."),Object(o.b)("p",null,"Now our frontend application will be able to consume the API exposed by the publicly exposed ",Object(o.b)("strong",{parentName:"p"},"APP_A"),".")))),Object(o.b)("h2",{id:"summary"},"Summary"),Object(o.b)("p",null,"In this guide, we deployed two microservices that communicate over the internal network. We also deployed a frontend application that makes use of a public API exposed by one of our applications. At the same time, we deployed a database and connected it to the second of our backend microservices."),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}d.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),p=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=p(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=p(n),d=a,m=u["".concat(i,".").concat(d)]||u[d]||b[d]||o;return n?r.a.createElement(m,c({ref:t},s,{components:n})):r.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var a=n(435),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(n(a,e,i.length))})),i.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),p=Object(a.useState)(null),u=p[0],b=p[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/68b95634.9798d644.js.LICENSE.txt b/66bbed7b.709e2f79.js.LICENSE.txt similarity index 100% rename from 68b95634.9798d644.js.LICENSE.txt rename to 66bbed7b.709e2f79.js.LICENSE.txt diff --git a/672ba3d6.edd98258.js b/672ba3d6.9b98b029.js similarity index 93% rename from 672ba3d6.edd98258.js rename to 672ba3d6.9b98b029.js index 5cbf330b41..59a7c02614 100644 --- a/672ba3d6.edd98258.js +++ b/672ba3d6.9b98b029.js @@ -1,2 +1,2 @@ -/*! For license information please see 672ba3d6.edd98258.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[117],{268:function(e,t,a){"use strict";a.r(t);var n=a(0),r=a.n(n),o=a(447),c=a(442),i=a(559),l=a(433),s=Object(o.a)("h2");t.default=function(){var e=Object(l.a)().siteConfig;return(void 0===e?{}:e).customFields.metadata.team,r.a.createElement(c.a,{title:"Community",description:"Join the Qovery community. Connect with the core Qovery team and other Qovery users."},r.a.createElement("header",{className:"hero"},r.a.createElement("div",{className:"container container--fluid"},r.a.createElement("h1",null,"Qovery Community"),r.a.createElement(i.a,{buttonClass:"highlight",center:!0,size:"lg"}))),r.a.createElement("main",null,r.a.createElement("section",null,r.a.createElement("div",{className:"container"},r.a.createElement(s,{id:"connect"},"Connect"),r.a.createElement("div",{className:"row"},r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-message-circle"})),r.a.createElement("div",{className:"panel--title"},"Discord"),r.a.createElement("div",{className:"panel--description"},"Join our community on Discord"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://community.qovery.com",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-globe"})),r.a.createElement("div",{className:"panel--title"},"Forum"),r.a.createElement("div",{className:"panel--description"},"Join our community on Discourse"))))),r.a.createElement("div",{className:"container"},r.a.createElement("div",{className:"row"},r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://twitter.com/Qovery_",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-twitter",title:"Twitter"})),r.a.createElement("div",{className:"panel--title"},"@Qovery"),r.a.createElement("div",{className:"panel--description"},"Follow us in real-time"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://github.com/qovery",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-github"})),r.a.createElement("div",{className:"panel--title"},"Github qovery"),r.a.createElement("div",{className:"panel--description"},"Issues, code, and development"))))))))}},420:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t0&&r.a.createElement("div",{className:"row footer__links"},r.a.createElement("div",{className:"col col--5 footer__col"},r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement(u.a,{className:"navbar__logo",src:f,alt:"Qovery",width:"150",height:"auto"})),r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),r.a.createElement("div",null,r.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},r.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},r.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},r.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},r.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),l.map((function(e,t){return r.a.createElement("div",{key:t,className:"col footer__col"},null!=e.title?r.a.createElement("h4",{className:"footer__title"},e.title):null,null!=e.items&&Array.isArray(e.items)&&e.items.length>0?r.a.createElement("ul",{className:"footer__items"},e.items.map((function(e,t){return e.html?r.a.createElement("li",{key:t,className:"footer__item",dangerouslySetInnerHTML:{__html:e.html}}):r.a.createElement("li",{key:e.href||e.to,className:"footer__item"},r.a.createElement(q,e))}))):null)}))),(m||c)&&r.a.createElement("div",{className:"text--center"},m&&m.src&&r.a.createElement("div",{className:"margin-bottom--sm"},m.href?r.a.createElement("a",{href:m.href,target:"_blank",rel:"noopener noreferrer",className:M.a.footerLogoLink},r.a.createElement(z,{alt:m.alt,url:d})):r.a.createElement(z,{alt:m.alt,url:d})),r.a.createElement("small",null,c),r.a.createElement("br",null))))},F=a(459),J=a(460),P=a(3);a(138);t.a=function(e){var t=Object(h.a)().siteConfig,a=void 0===t?{}:t,n=a.favicon,i=(a.tagline,a.title),l=a.themeConfig.image,s=a.url,m=e.children,u=e.title,d=e.noFooter,f=e.description,p=e.image,g=e.keywords,v=(e.permalink,e.version),b=u?u+" | "+i:i,E=p||l,y=s+Object(_.a)(E),w=Object(_.a)(n),N=Object(P.h)(),k=N?"https://docs.qovery.com"+(N.pathname.endsWith("/")?N.pathname:N.pathname+"/"):null;return r.a.createElement(J.a,null,r.a.createElement(F.a,null,r.a.createElement(c.a,null,r.a.createElement("html",{lang:"en"}),r.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),b&&r.a.createElement("title",null,b),b&&r.a.createElement("meta",{property:"og:title",content:b}),n&&r.a.createElement("link",{rel:"shortcut icon",href:w}),f&&r.a.createElement("meta",{name:"description",content:f}),f&&r.a.createElement("meta",{property:"og:description",content:f}),v&&r.a.createElement("meta",{name:"docsearch:version",content:v}),g&&g.length&&r.a.createElement("meta",{name:"keywords",content:g.join(",")}),E&&r.a.createElement("meta",{property:"og:image",content:y}),E&&r.a.createElement("meta",{property:"twitter:image",content:y}),E&&r.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+b}),k&&r.a.createElement("meta",{property:"og:url",content:k}),r.a.createElement("meta",{name:"twitter:card",content:"summary"}),k&&r.a.createElement("link",{rel:"canonical",href:k})),r.a.createElement(o.a,null),r.a.createElement(D,null),r.a.createElement("div",{className:"main-wrapper"},m),!d&&r.a.createElement(Q,null)))}},447:function(e,t,a){"use strict";var n=a(9),r=a(0),o=a.n(r),c=a(420),i=a.n(c),l=a(433),s=(a(139),a(140)),m=a.n(s);t.a=function(e){return function(t){var a,r=t.id,c=Object(n.a)(t,["id"]),s=Object(l.a)().siteConfig,u=(s=void 0===s?{}:s).themeConfig,d=(u=void 0===u?{}:u).navbar,f=(d=void 0===d?{}:d).hideOnScroll,h=void 0!==f&&f;return r?o.a.createElement(e,c,o.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:i()("anchor",(a={},a[m.a.enhancedAnchor]=!h,a)),id:r}),o.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+r,title:"Direct link to heading"},"#"),c.children):o.a.createElement(e,c)}}},451:function(e,t,a){"use strict";var n=a(0),r=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=r},476:function(e,t){var a,n,r=e.exports={};function o(){throw new Error("setTimeout has not been defined")}function c(){throw new Error("clearTimeout has not been defined")}function i(e){if(a===setTimeout)return setTimeout(e,0);if((a===o||!a)&&setTimeout)return a=setTimeout,setTimeout(e,0);try{return a(e,0)}catch(t){try{return a.call(null,e,0)}catch(t){return a.call(this,e,0)}}}!function(){try{a="function"==typeof setTimeout?setTimeout:o}catch(e){a=o}try{n="function"==typeof clearTimeout?clearTimeout:c}catch(e){n=c}}();var l,s=[],m=!1,u=-1;function d(){m&&l&&(m=!1,l.length?s=l.concat(s):u=-1,s.length&&f())}function f(){if(!m){var e=i(d);m=!0;for(var t=s.length;t;){for(l=s,s=[];++u1)for(var a=1;a=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},t.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:function(){try{return window.localStorage}catch(e){}}(),t.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],t.formatters.j=function(e){try{return JSON.stringify(e)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}},t.enable(r())}).call(this,a(476))},553:function(e,t,a){var n;function r(e){function a(){if(a.enabled){var e=a,r=+new Date,o=r-(n||r);e.diff=o,e.prev=n,e.curr=r,n=r;for(var c=new Array(arguments.length),i=0;i0)return function(e){if((e=String(e)).length>100)return;var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(!t)return;var c=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*c;case"days":case"day":case"d":return c*o;case"hours":case"hour":case"hrs":case"hr":case"h":return c*r;case"minutes":case"minute":case"mins":case"min":case"m":return c*n;case"seconds":case"second":case"secs":case"sec":case"s":return c*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return c;default:return}}(e);if("number"===l&&!1===isNaN(e))return t.long?c(i=e,o,"day")||c(i,r,"hour")||c(i,n,"minute")||c(i,a,"second")||i+" ms":function(e){if(e>=o)return Math.round(e/o)+"d";if(e>=r)return Math.round(e/r)+"h";if(e>=n)return Math.round(e/n)+"m";if(e>=a)return Math.round(e/a)+"s";return e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},555:function(e,t,a){"use strict";var n=/^[-!#$%&'*+\/0-9=?A-Z^_a-z{|}~](\.?[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\.?[a-zA-Z0-9])*\.[a-zA-Z](-?[a-zA-Z0-9])+$/;t.validate=function(e){if(!e)return!1;if(e.length>254)return!1;if(!n.test(e))return!1;var t=e.split("@");return!(t[0].length>64)&&!t[1].split(".").some((function(e){return e.length>63}))}},559:function(e,t,a){"use strict";a(443),a(444);var n=a(0),r=a.n(n),o=a(420),c=a.n(o),i=(a(58),a(21),a(551)),l=a.n(i),s=a(555),m=function(e){return new Promise((function(t,a){return l()(e,{param:"c",timeout:3500},(function(e,n){e&&a(e),n&&t(n)}))}))},u=function(e){var t="";for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a)){var n="group["===a.substring(0,6)?a:a.toUpperCase();t=t.concat("&"+n+"="+e[a])}return t},d=function(e,t,a){var n=Object(s.validate)(e),r=encodeURIComponent(e);if(!n)return Promise.resolve({result:"error",msg:"The email you entered is not valid."});var o="https://qovery.us4.list-manage.com/subscribe/post-json?u=3c76e7a2087d5bc4020348c46&id=63bd993879";arguments.length<3&&"string"==typeof t?o=t:"string"==typeof a&&(o=a);var c="&EMAIL="+r+u(t),i=""+o+c;return m(i)};a(152),t.a=function(e){var t,a=e.block,o=e.buttonClass,i=e.center,l=e.description,s=e.subscriptionEnabled,m=e.size,u=e.width,f=Object(n.useState)(""),h=f[0],p=f[1],g=Object(n.useState)(!1),v=g[0],b=g[1],E=Object(n.useState)(!1),y=E[0],w=E[1],N=Object(n.useState)("Could not subscribe :("),k=N[0],_=N[1];return r.a.createElement("div",{className:c()("mailing-list",(t={"mailing-list--block":a,"mailing-list--center":i},t["mailing-list--"+m]=m,t))},!1!==l&&r.a.createElement("div",{className:"mailing-list--description"},l),s&&!v&&r.a.createElement("form",{onSubmit:function(e){return function(e){e.preventDefault(),d(h).then((function(e){"success"===e.result?(b(!0),y&&w(!1)):(w(!0),e.msg.includes(h+" is already subscribed")?_("This email is already subscribed to the newsletter"):_("Could not subscribe :("))})).catch((function(e){w(!0)}))}(e)},className:c()("mailing-list--form")},r.a.createElement("input",{onChange:function(e){return p(e.target.value)},className:c()("input","input--"+m),name:"email",placeholder:"you@email.com",type:"email",style:{width:u}}),r.a.createElement("button",{className:c()("button","button--"+(o||"primary"),"button--"+m),type:"submit"},"Subscribe")),y&&r.a.createElement("span",{className:"badge badge--secondary"},k),r.a.createElement("div",{style:{textAlign:"center"}},s&&v&&r.a.createElement("span",{className:"badge badge--primary"},"Subscribed!")))}}}]); \ No newline at end of file +/*! For license information please see 672ba3d6.9b98b029.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[119],{270:function(e,t,a){"use strict";a.r(t);var n=a(0),r=a.n(n),o=a(450),c=a(445),i=a(562),l=a(436),s=Object(o.a)("h2");t.default=function(){var e=Object(l.a)().siteConfig;return(void 0===e?{}:e).customFields.metadata.team,r.a.createElement(c.a,{title:"Community",description:"Join the Qovery community. Connect with the core Qovery team and other Qovery users."},r.a.createElement("header",{className:"hero"},r.a.createElement("div",{className:"container container--fluid"},r.a.createElement("h1",null,"Qovery Community"),r.a.createElement(i.a,{buttonClass:"highlight",center:!0,size:"lg"}))),r.a.createElement("main",null,r.a.createElement("section",null,r.a.createElement("div",{className:"container"},r.a.createElement(s,{id:"connect"},"Connect"),r.a.createElement("div",{className:"row"},r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-message-circle"})),r.a.createElement("div",{className:"panel--title"},"Discord"),r.a.createElement("div",{className:"panel--description"},"Join our community on Discord"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://community.qovery.com",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-globe"})),r.a.createElement("div",{className:"panel--title"},"Forum"),r.a.createElement("div",{className:"panel--description"},"Join our community on Discourse"))))),r.a.createElement("div",{className:"container"},r.a.createElement("div",{className:"row"},r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://twitter.com/Qovery_",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-twitter",title:"Twitter"})),r.a.createElement("div",{className:"panel--title"},"@Qovery"),r.a.createElement("div",{className:"panel--description"},"Follow us in real-time"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://github.com/qovery",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-github"})),r.a.createElement("div",{className:"panel--title"},"Github qovery"),r.a.createElement("div",{className:"panel--description"},"Issues, code, and development"))))))))}},423:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t0&&r.a.createElement("div",{className:"row footer__links"},r.a.createElement("div",{className:"col col--5 footer__col"},r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement(u.a,{className:"navbar__logo",src:f,alt:"Qovery",width:"150",height:"auto"})),r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),r.a.createElement("div",null,r.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},r.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},r.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},r.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},r.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),l.map((function(e,t){return r.a.createElement("div",{key:t,className:"col footer__col"},null!=e.title?r.a.createElement("h4",{className:"footer__title"},e.title):null,null!=e.items&&Array.isArray(e.items)&&e.items.length>0?r.a.createElement("ul",{className:"footer__items"},e.items.map((function(e,t){return e.html?r.a.createElement("li",{key:t,className:"footer__item",dangerouslySetInnerHTML:{__html:e.html}}):r.a.createElement("li",{key:e.href||e.to,className:"footer__item"},r.a.createElement(q,e))}))):null)}))),(m||c)&&r.a.createElement("div",{className:"text--center"},m&&m.src&&r.a.createElement("div",{className:"margin-bottom--sm"},m.href?r.a.createElement("a",{href:m.href,target:"_blank",rel:"noopener noreferrer",className:M.a.footerLogoLink},r.a.createElement(z,{alt:m.alt,url:d})):r.a.createElement(z,{alt:m.alt,url:d})),r.a.createElement("small",null,c),r.a.createElement("br",null))))},F=a(462),J=a(463),P=a(3);a(138);t.a=function(e){var t=Object(h.a)().siteConfig,a=void 0===t?{}:t,n=a.favicon,i=(a.tagline,a.title),l=a.themeConfig.image,s=a.url,m=e.children,u=e.title,d=e.noFooter,f=e.description,p=e.image,g=e.keywords,v=(e.permalink,e.version),b=u?u+" | "+i:i,E=p||l,y=s+Object(_.a)(E),w=Object(_.a)(n),N=Object(P.h)(),k=N?"https://docs.qovery.com"+(N.pathname.endsWith("/")?N.pathname:N.pathname+"/"):null;return r.a.createElement(J.a,null,r.a.createElement(F.a,null,r.a.createElement(c.a,null,r.a.createElement("html",{lang:"en"}),r.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),b&&r.a.createElement("title",null,b),b&&r.a.createElement("meta",{property:"og:title",content:b}),n&&r.a.createElement("link",{rel:"shortcut icon",href:w}),f&&r.a.createElement("meta",{name:"description",content:f}),f&&r.a.createElement("meta",{property:"og:description",content:f}),v&&r.a.createElement("meta",{name:"docsearch:version",content:v}),g&&g.length&&r.a.createElement("meta",{name:"keywords",content:g.join(",")}),E&&r.a.createElement("meta",{property:"og:image",content:y}),E&&r.a.createElement("meta",{property:"twitter:image",content:y}),E&&r.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+b}),k&&r.a.createElement("meta",{property:"og:url",content:k}),r.a.createElement("meta",{name:"twitter:card",content:"summary"}),k&&r.a.createElement("link",{rel:"canonical",href:k})),r.a.createElement(o.a,null),r.a.createElement(D,null),r.a.createElement("div",{className:"main-wrapper"},m),!d&&r.a.createElement(Q,null)))}},450:function(e,t,a){"use strict";var n=a(9),r=a(0),o=a.n(r),c=a(423),i=a.n(c),l=a(436),s=(a(139),a(140)),m=a.n(s);t.a=function(e){return function(t){var a,r=t.id,c=Object(n.a)(t,["id"]),s=Object(l.a)().siteConfig,u=(s=void 0===s?{}:s).themeConfig,d=(u=void 0===u?{}:u).navbar,f=(d=void 0===d?{}:d).hideOnScroll,h=void 0!==f&&f;return r?o.a.createElement(e,c,o.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:i()("anchor",(a={},a[m.a.enhancedAnchor]=!h,a)),id:r}),o.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+r,title:"Direct link to heading"},"#"),c.children):o.a.createElement(e,c)}}},454:function(e,t,a){"use strict";var n=a(0),r=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=r},479:function(e,t){var a,n,r=e.exports={};function o(){throw new Error("setTimeout has not been defined")}function c(){throw new Error("clearTimeout has not been defined")}function i(e){if(a===setTimeout)return setTimeout(e,0);if((a===o||!a)&&setTimeout)return a=setTimeout,setTimeout(e,0);try{return a(e,0)}catch(t){try{return a.call(null,e,0)}catch(t){return a.call(this,e,0)}}}!function(){try{a="function"==typeof setTimeout?setTimeout:o}catch(e){a=o}try{n="function"==typeof clearTimeout?clearTimeout:c}catch(e){n=c}}();var l,s=[],m=!1,u=-1;function d(){m&&l&&(m=!1,l.length?s=l.concat(s):u=-1,s.length&&f())}function f(){if(!m){var e=i(d);m=!0;for(var t=s.length;t;){for(l=s,s=[];++u1)for(var a=1;a=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},t.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:function(){try{return window.localStorage}catch(e){}}(),t.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],t.formatters.j=function(e){try{return JSON.stringify(e)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}},t.enable(r())}).call(this,a(479))},556:function(e,t,a){var n;function r(e){function a(){if(a.enabled){var e=a,r=+new Date,o=r-(n||r);e.diff=o,e.prev=n,e.curr=r,n=r;for(var c=new Array(arguments.length),i=0;i0)return function(e){if((e=String(e)).length>100)return;var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(!t)return;var c=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*c;case"days":case"day":case"d":return c*o;case"hours":case"hour":case"hrs":case"hr":case"h":return c*r;case"minutes":case"minute":case"mins":case"min":case"m":return c*n;case"seconds":case"second":case"secs":case"sec":case"s":return c*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return c;default:return}}(e);if("number"===l&&!1===isNaN(e))return t.long?c(i=e,o,"day")||c(i,r,"hour")||c(i,n,"minute")||c(i,a,"second")||i+" ms":function(e){if(e>=o)return Math.round(e/o)+"d";if(e>=r)return Math.round(e/r)+"h";if(e>=n)return Math.round(e/n)+"m";if(e>=a)return Math.round(e/a)+"s";return e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},558:function(e,t,a){"use strict";var n=/^[-!#$%&'*+\/0-9=?A-Z^_a-z{|}~](\.?[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\.?[a-zA-Z0-9])*\.[a-zA-Z](-?[a-zA-Z0-9])+$/;t.validate=function(e){if(!e)return!1;if(e.length>254)return!1;if(!n.test(e))return!1;var t=e.split("@");return!(t[0].length>64)&&!t[1].split(".").some((function(e){return e.length>63}))}},562:function(e,t,a){"use strict";a(446),a(447);var n=a(0),r=a.n(n),o=a(423),c=a.n(o),i=(a(58),a(21),a(554)),l=a.n(i),s=a(558),m=function(e){return new Promise((function(t,a){return l()(e,{param:"c",timeout:3500},(function(e,n){e&&a(e),n&&t(n)}))}))},u=function(e){var t="";for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a)){var n="group["===a.substring(0,6)?a:a.toUpperCase();t=t.concat("&"+n+"="+e[a])}return t},d=function(e,t,a){var n=Object(s.validate)(e),r=encodeURIComponent(e);if(!n)return Promise.resolve({result:"error",msg:"The email you entered is not valid."});var o="https://qovery.us4.list-manage.com/subscribe/post-json?u=3c76e7a2087d5bc4020348c46&id=63bd993879";arguments.length<3&&"string"==typeof t?o=t:"string"==typeof a&&(o=a);var c="&EMAIL="+r+u(t),i=""+o+c;return m(i)};a(152),t.a=function(e){var t,a=e.block,o=e.buttonClass,i=e.center,l=e.description,s=e.subscriptionEnabled,m=e.size,u=e.width,f=Object(n.useState)(""),h=f[0],p=f[1],g=Object(n.useState)(!1),v=g[0],b=g[1],E=Object(n.useState)(!1),y=E[0],w=E[1],N=Object(n.useState)("Could not subscribe :("),k=N[0],_=N[1];return r.a.createElement("div",{className:c()("mailing-list",(t={"mailing-list--block":a,"mailing-list--center":i},t["mailing-list--"+m]=m,t))},!1!==l&&r.a.createElement("div",{className:"mailing-list--description"},l),s&&!v&&r.a.createElement("form",{onSubmit:function(e){return function(e){e.preventDefault(),d(h).then((function(e){"success"===e.result?(b(!0),y&&w(!1)):(w(!0),e.msg.includes(h+" is already subscribed")?_("This email is already subscribed to the newsletter"):_("Could not subscribe :("))})).catch((function(e){w(!0)}))}(e)},className:c()("mailing-list--form")},r.a.createElement("input",{onChange:function(e){return p(e.target.value)},className:c()("input","input--"+m),name:"email",placeholder:"you@email.com",type:"email",style:{width:u}}),r.a.createElement("button",{className:c()("button","button--"+(o||"primary"),"button--"+m),type:"submit"},"Subscribe")),y&&r.a.createElement("span",{className:"badge badge--secondary"},k),r.a.createElement("div",{style:{textAlign:"center"}},s&&v&&r.a.createElement("span",{className:"badge badge--primary"},"Subscribed!")))}}}]); \ No newline at end of file diff --git a/68c0e7f9.3a1beb74.js.LICENSE.txt b/672ba3d6.9b98b029.js.LICENSE.txt similarity index 100% rename from 68c0e7f9.3a1beb74.js.LICENSE.txt rename to 672ba3d6.9b98b029.js.LICENSE.txt diff --git a/68b95634.9798d644.js b/68b95634.b0f34f1a.js similarity index 91% rename from 68b95634.9798d644.js rename to 68b95634.b0f34f1a.js index f2f3fd5ae4..52b3126cfc 100644 --- a/68b95634.9798d644.js +++ b/68b95634.b0f34f1a.js @@ -1,2 +1,2 @@ -/*! For license information please see 68b95634.9798d644.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[118],{269:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return c})),r.d(t,"rightToc",(function(){return l})),r.d(t,"default",(function(){return u}));var n=r(1),a=r(9),o=(r(0),r(422)),i=(r(437),r(431),r(426),r(421),r(550),{last_modified_on:"2023-11-24",title:"What is Qovery?",description:"High-level description of the Qovery goals and mission."}),c={id:"getting-started/what-is-qovery",title:"What is Qovery?",description:"High-level description of the Qovery goals and mission.",source:"@site/docs/getting-started/what-is-qovery.md",permalink:"/docs/getting-started/what-is-qovery",sidebar:"docs",previous:{title:"Getting started",permalink:"/docs/getting-started"},next:{title:"How Qovery Works",permalink:"/docs/getting-started/how-qovery-works"}},l=[{value:"Qovery For Platform Engineers",id:"qovery-for-platform-engineers",children:[{value:"How Qovery Works",id:"how-qovery-works",children:[]},{value:"Notable features for Platform Engineers",id:"notable-features-for-platform-engineers",children:[]}]},{value:"Qovery For Developers / Engineering Teams",id:"qovery-for-developers--engineering-teams",children:[{value:"Notable features for Developers",id:"notable-features-for-developers",children:[]}]},{value:"Integrates Qovery in your technical stack",id:"integrates-qovery-in-your-technical-stack",children:[]}],s={rightToc:l};function u(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery is the ",Object(o.b)("strong",{parentName:"p"},"Internal Developer Platform (IDP)")," that cuts noise for developers with paved paths to production. Testing, ephemeral environments, and drive action to improve software."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/developers-and-platform-engineer-with-qovery.jpg",alt:"Developers and a Platform Engineer using Qovery as an IDP"})),Object(o.b)("h2",{id:"qovery-for-platform-engineers"},"Qovery For Platform Engineers"),Object(o.b)("p",null,"By using Qovery, Platform Engineering teams can provide an outstanding platform to their developers in less than a hour. Then Platform Engineering teams can tailor the experience of Qovery and even build on top of it to fit their own golden path. They keep the control and can audit what developers do."),Object(o.b)("h3",{id:"how-qovery-works"},"How Qovery Works"),Object(o.b)("p",null,"Qovery runs on top of Kubernetes and provide a convenient layer with a set of features to build a platform that your developers love."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-qovery-works-2.jpg",alt:"Qovery - How it Works"})),Object(o.b)("h3",{id:"notable-features-for-platform-engineers"},"Notable features for Platform Engineers"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Templates"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/members-rbac/"}),"RBAC")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/audit-logs/"}),"Audit Logs")),Object(o.b)("li",{parentName:"ul"},"Cost Management"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/integration/continuous-integration/"}),"Integrates in your CI/CD")),Object(o.b)("li",{parentName:"ul"},"Bring Your Own Kubernetes"),Object(o.b)("li",{parentName:"ul"},"GitOps Support"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/interface/"}),"Open-Source Interfaces")," (perfect to build on top)",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/interface/web-interface/"}),"Web Console")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/"}),"CLI")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/interface/terraform-interface/"}),"Terraform Provider")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/interface/rest-api/"}),"Public API"))))),Object(o.b)("h2",{id:"qovery-for-developers--engineering-teams"},"Qovery For Developers / Engineering Teams"),Object(o.b)("p",null,"By using Qovery, developers are autonomous in deploying their applications, debugging, and scaling. They don't need any infrastructure knowledge. They can connect their git repository, pushing and deploying their apps."),Object(o.b)("p",null,"Qovery focus on providing an outstanding Developer Experience and never assume that developers know how underlying infrastructure work."),Object(o.b)("h3",{id:"notable-features-for-developers"},"Notable features for Developers"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Self-Service Platform"),Object(o.b)("li",{parentName:"ul"},"Git Push And Deploy"),Object(o.b)("li",{parentName:"ul"},"Live Application Logs"),Object(o.b)("li",{parentName:"ul"},"Easy Variables Management"),Object(o.b)("li",{parentName:"ul"},"Easy Domain Management"),Object(o.b)("li",{parentName:"ul"},"No Infra Knowledge Needed"),Object(o.b)("li",{parentName:"ul"},"Ephemeral Environments")),Object(o.b)("h2",{id:"integrates-qovery-in-your-technical-stack"},"Integrates Qovery in your technical stack"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Qovery is battery included! Get a State-of-the-Art Internal Developer Platform in 30 minutes."),Object(o.b)("li",{parentName:"ol"},"Qovery integrates perfectly well into an existing ecosystem.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/qovery-internal-developer-platform.jpg",alt:"Qovery - Internal Developer Platform landscape"})))}u.isMDXComponent=!0},420:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(r),b=n,d=p["".concat(i,".").concat(b)]||p[b]||f[b]||o;return r?a.a.createElement(d,c({ref:t},s,{components:r})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=b;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s1?arguments[1]:void 0,r),l=i>2?arguments[2]:void 0,s=void 0===l?r:a(l,r);s>c;)t[c++]=e;return t}},425:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,r){"use strict";r(425);var n=r(0),a=r.n(n),o=r(421);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},428:function(e,t,r){"use strict";var n=r(432),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(r(n,e,i.length))})),i.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(420),r(428)),i=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(n.useState)(null),p=u[0],f=u[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return f("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},550:function(e,t,r){"use strict";r(0)}}]); \ No newline at end of file +/*! For license information please see 68b95634.b0f34f1a.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[120],{271:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return c})),r.d(t,"rightToc",(function(){return l})),r.d(t,"default",(function(){return u}));var n=r(1),a=r(9),o=(r(0),r(425)),i=(r(440),r(434),r(429),r(424),r(553),{last_modified_on:"2023-11-24",title:"What is Qovery?",description:"High-level description of the Qovery goals and mission."}),c={id:"getting-started/what-is-qovery",title:"What is Qovery?",description:"High-level description of the Qovery goals and mission.",source:"@site/docs/getting-started/what-is-qovery.md",permalink:"/docs/getting-started/what-is-qovery",sidebar:"docs",previous:{title:"Getting started",permalink:"/docs/getting-started"},next:{title:"How Qovery Works",permalink:"/docs/getting-started/how-qovery-works"}},l=[{value:"Qovery For Platform Engineers",id:"qovery-for-platform-engineers",children:[{value:"How Qovery Works",id:"how-qovery-works",children:[]},{value:"Notable features for Platform Engineers",id:"notable-features-for-platform-engineers",children:[]}]},{value:"Qovery For Developers / Engineering Teams",id:"qovery-for-developers--engineering-teams",children:[{value:"Notable features for Developers",id:"notable-features-for-developers",children:[]}]},{value:"Integrates Qovery in your technical stack",id:"integrates-qovery-in-your-technical-stack",children:[]}],s={rightToc:l};function u(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery is the ",Object(o.b)("strong",{parentName:"p"},"Internal Developer Platform (IDP)")," that cuts noise for developers with paved paths to production. Testing, ephemeral environments, and drive action to improve software."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/developers-and-platform-engineer-with-qovery.jpg",alt:"Developers and a Platform Engineer using Qovery as an IDP"})),Object(o.b)("h2",{id:"qovery-for-platform-engineers"},"Qovery For Platform Engineers"),Object(o.b)("p",null,"By using Qovery, Platform Engineering teams can provide an outstanding platform to their developers in less than a hour. Then Platform Engineering teams can tailor the experience of Qovery and even build on top of it to fit their own golden path. They keep the control and can audit what developers do."),Object(o.b)("h3",{id:"how-qovery-works"},"How Qovery Works"),Object(o.b)("p",null,"Qovery runs on top of Kubernetes and provide a convenient layer with a set of features to build a platform that your developers love."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-qovery-works-2.jpg",alt:"Qovery - How it Works"})),Object(o.b)("h3",{id:"notable-features-for-platform-engineers"},"Notable features for Platform Engineers"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Templates"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/members-rbac/"}),"RBAC")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/audit-logs/"}),"Audit Logs")),Object(o.b)("li",{parentName:"ul"},"Cost Management"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/integration/continuous-integration/"}),"Integrates in your CI/CD")),Object(o.b)("li",{parentName:"ul"},"Bring Your Own Kubernetes"),Object(o.b)("li",{parentName:"ul"},"GitOps Support"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/interface/"}),"Open-Source Interfaces")," (perfect to build on top)",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/interface/web-interface/"}),"Web Console")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/"}),"CLI")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/interface/terraform-interface/"}),"Terraform Provider")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/interface/rest-api/"}),"Public API"))))),Object(o.b)("h2",{id:"qovery-for-developers--engineering-teams"},"Qovery For Developers / Engineering Teams"),Object(o.b)("p",null,"By using Qovery, developers are autonomous in deploying their applications, debugging, and scaling. They don't need any infrastructure knowledge. They can connect their git repository, pushing and deploying their apps."),Object(o.b)("p",null,"Qovery focus on providing an outstanding Developer Experience and never assume that developers know how underlying infrastructure work."),Object(o.b)("h3",{id:"notable-features-for-developers"},"Notable features for Developers"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Self-Service Platform"),Object(o.b)("li",{parentName:"ul"},"Git Push And Deploy"),Object(o.b)("li",{parentName:"ul"},"Live Application Logs"),Object(o.b)("li",{parentName:"ul"},"Easy Variables Management"),Object(o.b)("li",{parentName:"ul"},"Easy Domain Management"),Object(o.b)("li",{parentName:"ul"},"No Infra Knowledge Needed"),Object(o.b)("li",{parentName:"ul"},"Ephemeral Environments")),Object(o.b)("h2",{id:"integrates-qovery-in-your-technical-stack"},"Integrates Qovery in your technical stack"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Qovery is battery included! Get a State-of-the-Art Internal Developer Platform in 30 minutes."),Object(o.b)("li",{parentName:"ol"},"Qovery integrates perfectly well into an existing ecosystem.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/qovery-internal-developer-platform.jpg",alt:"Qovery - Internal Developer Platform landscape"})))}u.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(r),b=n,d=p["".concat(i,".").concat(b)]||p[b]||f[b]||o;return r?a.a.createElement(d,c({ref:t},s,{components:r})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=b;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s1?arguments[1]:void 0,r),l=i>2?arguments[2]:void 0,s=void 0===l?r:a(l,r);s>c;)t[c++]=e;return t}},428:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,r){"use strict";r(428);var n=r(0),a=r.n(n),o=r(424);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},433:function(e,t,r){"use strict";var n=r(435),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(r(n,e,i.length))})),i.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(423),r(433)),i=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(n.useState)(null),p=u[0],f=u[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return f("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},553:function(e,t,r){"use strict";r(0)}}]); \ No newline at end of file diff --git a/6b0e113a.9f61dcae.js.LICENSE.txt b/68b95634.b0f34f1a.js.LICENSE.txt similarity index 100% rename from 6b0e113a.9f61dcae.js.LICENSE.txt rename to 68b95634.b0f34f1a.js.LICENSE.txt diff --git a/68c0e7f9.3a1beb74.js b/68c0e7f9.93f9c90c.js similarity index 88% rename from 68c0e7f9.3a1beb74.js rename to 68c0e7f9.93f9c90c.js index 87ac637050..2a9ef0cc5e 100644 --- a/68c0e7f9.3a1beb74.js +++ b/68c0e7f9.93f9c90c.js @@ -1,2 +1,2 @@ -/*! For license information please see 68c0e7f9.3a1beb74.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[119],{270:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return f}));var r=n(1),o=n(9),a=(n(0),n(422)),i=(n(431),n(426),n(421)),c={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Production",description:"Learn how to run your Production with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Production",description:"Learn how to run your Production with Qovery",permalink:"/guides/advanced/production",readingTime:"1 min read",source:"@site/guides/advanced/production.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Production",truncated:!1,prevItem:{title:"Preview Environments",permalink:"/guides/advanced/use-preview-environments"},nextItem:{title:"Seed Database",permalink:"/guides/advanced/seed-database"}},s=[{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function f(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},"WIP"),Object(a.b)("h2",{id:"qa"},"Q&A"),Object(a.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}f.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},f=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),f=l(n),d=r,m=f["".concat(i,".").concat(d)]||f[d]||p[d]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:o(u,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),f=l[0],p=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!f&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 68c0e7f9.93f9c90c.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[121],{272:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return f}));var r=n(1),o=n(9),a=(n(0),n(425)),i=(n(434),n(429),n(424)),c={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Production",description:"Learn how to run your Production with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Production",description:"Learn how to run your Production with Qovery",permalink:"/guides/advanced/production",readingTime:"1 min read",source:"@site/guides/advanced/production.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Production",truncated:!1,prevItem:{title:"Preview Environments",permalink:"/guides/advanced/use-preview-environments"},nextItem:{title:"Seed Database",permalink:"/guides/advanced/seed-database"}},s=[{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function f(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},"WIP"),Object(a.b)("h2",{id:"qa"},"Q&A"),Object(a.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}f.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},f=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),f=l(n),d=r,m=f["".concat(i,".").concat(d)]||f[d]||p[d]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:o(u,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),f=l[0],p=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!f&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/6b7a52aa.3759f6f6.js.LICENSE.txt b/68c0e7f9.93f9c90c.js.LICENSE.txt similarity index 100% rename from 6b7a52aa.3759f6f6.js.LICENSE.txt rename to 68c0e7f9.93f9c90c.js.LICENSE.txt diff --git a/6b0e113a.9f61dcae.js b/6b0e113a.9f61dcae.js deleted file mode 100644 index 0ef0d10302..0000000000 --- a/6b0e113a.9f61dcae.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see 6b0e113a.9f61dcae.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[120],{271:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return p}));var r=n(1),i=n(9),a=(n(0),n(422)),o=n(421),c=(n(429),n(426),{last_modified_on:"2023-09-21",title:"Container Registry",description:"Learn how to manage the container registry allowed in your organization"}),s={id:"using-qovery/configuration/organization/container-registry",title:"Container Registry",description:"Learn how to manage the container registry allowed in your organization",source:"@site/docs/using-qovery/configuration/organization/container-registry.md",permalink:"/docs/using-qovery/configuration/organization/container-registry",sidebar:"docs",previous:{title:"Git Repository access",permalink:"/docs/using-qovery/configuration/organization/git-repository-access"},next:{title:"API Token",permalink:"/docs/using-qovery/configuration/organization/api-token"}},l=[{value:"Create a Container Registry",id:"create-a-container-registry",children:[]},{value:"Modify or Delete an existing registry",id:"modify-or-delete-an-existing-registry",children:[]}],u={rightToc:l};function p(e){var t=e.components,n=Object(i.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"This section allows you to define the list of container registries that can be used within your organization. Only images stored on those container registries are allowed to be deployed on your cluster."),Object(a.b)("p",null,"You can access this section by opening the Organization Settings -> Container Registries"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/organization/access_settings.png",alt:"How to access your organization settings"})),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/organization/container_1.png",alt:"Application"})),Object(a.b)(o.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,'When accessing the interface for the first time, you will see that a container registry already exist (called "registry-{$UIID}"). This container registry is created by Qovery on your infrastructure and is used to manage the deployment of your applications. You are free to use them to store your applications but you need to retrieve the credentials from your cloud provider console.')),Object(a.b)("h3",{id:"create-a-container-registry"},"Create a Container Registry"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/organization/container_creation.png",alt:"Application"})),Object(a.b)("p",null,'By clicking on "Add Registry" you will be able to create a new Container Registry by filling these information:'),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Registry Name"),Object(a.b)("li",{parentName:"ul"},"Description"),Object(a.b)("li",{parentName:"ul"},"Registry Url: the base url of the registry (example: ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://docker.io"}),"https://docker.io"),", ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://public.ecr.aws"}),"https://public.ecr.aws")," etc..)"),Object(a.b)("li",{parentName:"ul"},"Registry type: you can chose among DockerHub, Public ECR, ECR (AWS private CR), Scaleway CR (Scaleway private CR), Github Packages, Gitlab CR, Generic."),Object(a.b)("li",{parentName:"ul"},"Credentials: these depends on the chosen registry type. If a container registry is public, you don't need to fill this part. ")),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Important information"),":"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"If you select Docker Hub, we encourage you to set credentials to increase the limits on the pull rate. ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://www.docker.com/increase-rate-limits/"}),"See here")," for more details"),Object(a.b)("li",{parentName:"ul"},"If the registry you need is not in the list and it supports the docker login format you can use the \u201cGeneric\u201d registry.")),Object(a.b)("p",null,"Now that you have created the registry, you can start using it in order to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#deploying-from-a-container-registry"}),"create and deploy a service")," using the images stored within it."),Object(a.b)("h3",{id:"modify-or-delete-an-existing-registry"},"Modify or Delete an existing registry"),Object(a.b)("p",null,'You can modify an existing container registry by clicking on the "Wheel" button next to it\nYou can delete an existing container registry by clicking on the "Trash" button next to it'),Object(a.b)(o.a,{type:"alert",mdxType:"Alert"},Object(a.b)("p",null,"Before deleting it, make sure that there is no application within your organization using an image stored in this registry.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/organization/container_edit.png",alt:"Application"})))}p.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function i(){for(var e=[],t=0;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=i.a.createContext({}),u=function(e){var t=i.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return i.a.createElement(l.Provider,{value:t},e.children)},g={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,o=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),f=r,b=p["".concat(o,".").concat(f)]||p[f]||g[f]||a;return n?i.a.createElement(b,c({ref:t},l,{components:n})):i.a.createElement(b,c({ref:t},l))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,o=new Array(a);o[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,o[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=o>2?arguments[2]:void 0,l=void 0===s?n:i(s,n);l>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,i=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in i||n(10)&&r(i,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),i=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return i.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},i.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var r=n(1),i=n(0),a=n.n(i),o=n(39),c=n(430),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,p=Object(c.a)(u),g=Object(i.useRef)(!1),f=l.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!f&&p&&window.docusaurus.prefetch(u),function(){f&&t&&t.disconnect()}}),[u,f,p]),u&&p?a.a.createElement(o.b,Object(r.a)({},e,{onMouseEnter:function(){g.current||(window.docusaurus.preload(u),g.current=!0)},innerRef:function(e){var n,r;f&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:u})):a.a.createElement("a",Object(r.a)({},e,{href:u}))}},429:function(e,t,n){"use strict";var r=n(0),i=n.n(r),a=n(427),o=n(420),c=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,o=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,g=c()("jump-to","jump-to--"+l,n),f=i.a.createElement("div",{className:"jump-to--inner"},i.a.createElement("div",{className:"jump-to--inner-2"},o&&i.a.createElement("div",{className:"jump-to--left"},i.a.createElement("i",{className:"feather icon-"+o})),i.a.createElement("div",{className:"jump-to--main"},r?i.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),i.a.createElement("div",{className:"jump-to--right"},i.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?i.a.createElement("a",{href:p,target:u,className:g},f):i.a.createElement(a.a,{to:p,className:g},f)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/6b0e113a.ea2cf728.js b/6b0e113a.ea2cf728.js new file mode 100644 index 0000000000..ce6b29e086 --- /dev/null +++ b/6b0e113a.ea2cf728.js @@ -0,0 +1,2 @@ +/*! For license information please see 6b0e113a.ea2cf728.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[122],{273:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return p}));var r=n(1),i=n(9),a=(n(0),n(425)),o=n(424),c=(n(431),n(429),{last_modified_on:"2023-09-21",title:"Container Registry",description:"Learn how to manage the container registry allowed in your organization"}),s={id:"using-qovery/configuration/organization/container-registry",title:"Container Registry",description:"Learn how to manage the container registry allowed in your organization",source:"@site/docs/using-qovery/configuration/organization/container-registry.md",permalink:"/docs/using-qovery/configuration/organization/container-registry",sidebar:"docs",previous:{title:"Git Repository access",permalink:"/docs/using-qovery/configuration/organization/git-repository-access"},next:{title:"Helm Repository",permalink:"/docs/using-qovery/configuration/organization/helm-repository"}},l=[{value:"Create a Container Registry",id:"create-a-container-registry",children:[]},{value:"Modify or Delete an existing registry",id:"modify-or-delete-an-existing-registry",children:[]}],u={rightToc:l};function p(e){var t=e.components,n=Object(i.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"This section allows you to define the list of container registries that can be used within your organization. Only images stored on those container registries are allowed to be deployed on your cluster."),Object(a.b)("p",null,"You can access this section by opening the Organization Settings -> Container Registries"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/organization/access_settings.png",alt:"How to access your organization settings"})),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/organization/container_1.png",alt:"Application"})),Object(a.b)(o.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,'When accessing the interface for the first time, you will see that a container registry already exist (called "registry-{$UIID}"). This container registry is created by Qovery on your infrastructure and is used to manage the deployment of your applications. You are free to use them to store your applications but you need to retrieve the credentials from your cloud provider console.')),Object(a.b)("h3",{id:"create-a-container-registry"},"Create a Container Registry"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/organization/container_creation.png",alt:"Application"})),Object(a.b)("p",null,'By clicking on "Add Registry" you will be able to create a new Container Registry by filling these information:'),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Registry Name"),Object(a.b)("li",{parentName:"ul"},"Description"),Object(a.b)("li",{parentName:"ul"},"Registry Url: the base url of the registry (example: ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://docker.io"}),"https://docker.io"),", ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://public.ecr.aws"}),"https://public.ecr.aws")," etc..)"),Object(a.b)("li",{parentName:"ul"},"Registry type: you can chose among DockerHub, Public ECR, ECR (AWS private CR), Scaleway CR (Scaleway private CR), Github Packages, Gitlab CR, Generic."),Object(a.b)("li",{parentName:"ul"},"Credentials: these depends on the chosen registry type. If a container registry is public, you don't need to fill this part. ")),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Important information"),":"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"If you select Docker Hub, we encourage you to set credentials to increase the limits on the pull rate. ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://www.docker.com/increase-rate-limits/"}),"See here")," for more details"),Object(a.b)("li",{parentName:"ul"},"If the registry you need is not in the list and it supports the docker login format you can use the \u201cGeneric\u201d registry.")),Object(a.b)("p",null,"Now that you have created the registry, you can start using it in order to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#deploying-from-a-container-registry"}),"create and deploy a service")," using the images stored within it."),Object(a.b)("h3",{id:"modify-or-delete-an-existing-registry"},"Modify or Delete an existing registry"),Object(a.b)("p",null,'You can modify an existing container registry by clicking on the "Wheel" button next to it\nYou can delete an existing container registry by clicking on the "Trash" button next to it'),Object(a.b)(o.a,{type:"alert",mdxType:"Alert"},Object(a.b)("p",null,"Before deleting it, make sure that there is no application within your organization using an image stored in this registry.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/organization/container_edit.png",alt:"Application"})))}p.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function i(){for(var e=[],t=0;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=i.a.createContext({}),u=function(e){var t=i.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return i.a.createElement(l.Provider,{value:t},e.children)},g={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,o=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),f=r,b=p["".concat(o,".").concat(f)]||p[f]||g[f]||a;return n?i.a.createElement(b,c({ref:t},l,{components:n})):i.a.createElement(b,c({ref:t},l))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,o=new Array(a);o[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,o[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=o>2?arguments[2]:void 0,l=void 0===s?n:i(s,n);l>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,i=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in i||n(10)&&r(i,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),i=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return i.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},i.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var r=n(1),i=n(0),a=n.n(i),o=n(39),c=n(432),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,p=Object(c.a)(u),g=Object(i.useRef)(!1),f=l.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!f&&p&&window.docusaurus.prefetch(u),function(){f&&t&&t.disconnect()}}),[u,f,p]),u&&p?a.a.createElement(o.b,Object(r.a)({},e,{onMouseEnter:function(){g.current||(window.docusaurus.preload(u),g.current=!0)},innerRef:function(e){var n,r;f&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:u})):a.a.createElement("a",Object(r.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var r=n(0),i=n.n(r),a=n(430),o=n(423),c=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,o=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,g=c()("jump-to","jump-to--"+l,n),f=i.a.createElement("div",{className:"jump-to--inner"},i.a.createElement("div",{className:"jump-to--inner-2"},o&&i.a.createElement("div",{className:"jump-to--left"},i.a.createElement("i",{className:"feather icon-"+o})),i.a.createElement("div",{className:"jump-to--main"},r?i.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),i.a.createElement("div",{className:"jump-to--right"},i.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?i.a.createElement("a",{href:p,target:u,className:g},f):i.a.createElement(a.a,{to:p,className:g},f)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/6ebd4d49.0e8b4f4e.js.LICENSE.txt b/6b0e113a.ea2cf728.js.LICENSE.txt similarity index 100% rename from 6ebd4d49.0e8b4f4e.js.LICENSE.txt rename to 6b0e113a.ea2cf728.js.LICENSE.txt diff --git a/8d146bfd.11f1dd37.js b/6b7a52aa.261b2e2c.js similarity index 96% rename from 8d146bfd.11f1dd37.js rename to 6b7a52aa.261b2e2c.js index ab271002cd..92689af1e4 100644 --- a/8d146bfd.11f1dd37.js +++ b/6b7a52aa.261b2e2c.js @@ -1,2 +1,2 @@ -/*! For license information please see 8d146bfd.11f1dd37.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[138],{290:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return m}));var o=n(1),r=n(9),a=(n(0),n(422)),i=n(431),c=n(421),l=n(426),s={last_modified_on:"2023-08-14",$schema:"/.meta/.schemas/guides.json",title:"How To Use Lifecycle Job To Deploy Any Kind Of Resources",description:"Learn how to use Lifecycle Job to deploy any kind of resources with Qovery.",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},b={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How To Use Lifecycle Job To Deploy Any Kind Of Resources",description:"Learn how to use Lifecycle Job to deploy any kind of resources with Qovery.",permalink:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources",readingTime:"10 min read",source:"@site/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How To Use Lifecycle Job To Deploy Any Kind Of Resources",truncated:!1,prevItem:{title:"How to use Github Organizations with Qovery",permalink:"/guides/tutorial/github-organization-repository-access"},nextItem:{title:"How to write a Dockerfile",permalink:"/guides/tutorial/how-to-write-a-dockerfile"}},u=[{value:"How to use Lifecycle Job (example with Terraform)",id:"how-to-use-lifecycle-job-example-with-terraform",children:[{value:"Execution Flow",id:"execution-flow",children:[]},{value:"Create a Lifecycle Job",id:"create-a-lifecycle-job",children:[]},{value:"Make your Terraform deployment multi-environments ready",id:"make-your-terraform-deployment-multi-environments-ready",children:[]},{value:"Deploy AWS RDS MySQL instance",id:"deploy-aws-rds-mysql-instance",children:[]},{value:"Get the MySQL RDS credentials from the Lifecycle Job",id:"get-the-mysql-rds-credentials-from-the-lifecycle-job",children:[]}]},{value:"FAQ",id:"faq",children:[{value:"What happen if I delete my environment with your example?",id:"what-happen-if-i-delete-my-environment-with-your-example",children:[]},{value:"Can I use the Lifecycle Job to deploy my application?",id:"can-i-use-the-lifecycle-job-to-deploy-my-application",children:[]},{value:"What happen if I clone my Environment with the Lifecycle Job?",id:"what-happen-if-i-clone-my-environment-with-the-lifecycle-job",children:[]},{value:"What happen if I modify my Lifecycle Job after my Environment is deployed?",id:"what-happen-if-i-modify-my-lifecycle-job-after-my-environment-is-deployed",children:[]}]},{value:"Wrapping up",id:"wrapping-up",children:[]}],p={rightToc:u};function m(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"The ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"Lifecycle Job")," is a powerful feature that allows you to run any kind of commands before or after your environment is deployed. It can be used to run database migrations, create a new database, or even to run a script that will create a new user."),Object(a.b)("p",null,"Some use cases:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Run Terraform, Pulumi, or any other infrastructure as code tool to create resources."),Object(a.b)("li",{parentName:"ul"},"You want to deploy SQS, SNS, Lambdas, or any other AWS resources."),Object(a.b)("li",{parentName:"ul"},"You want to deploy MongoDB Atlas, Google BigQuery, or any other cloud services."),Object(a.b)("li",{parentName:"ul"},"Seed your database when your environment is created.")),Object(a.b)(c.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,"You can find some Lifecycle Jobs examples on our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples"}),"GitHub"),".")),Object(a.b)("p",null,"In a more general way, you can see the Lifecycle Job as a way to create and destroy resources when your environment is deployed or deleted. Possibilities are endless."),Object(a.b)("h2",{id:"how-to-use-lifecycle-job-example-with-terraform"},"How to use Lifecycle Job (example with Terraform)"),Object(a.b)("p",null,"In this example, we will use Terraform to create a new AWS RDS MySQL instance. I will use ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-rds-with-terraform"}),"this example")," to schematize the process of using the Lifecycle Job. \u26a0\ufe0f Note that you can use any other tool to create your resources. Lifecycle Job is not limited to Terraform. However, Terraform is a great way to show the power of the Lifecycle Job since it requires a lot of configuration and can be used to create a lot of different resources."),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"In our example, we use S3 as a Terraform backend. You can use any other backend you want. However, if you want to use S3, you need to create a new bucket and a new IAM user with the right permissions. You can find more information about this in the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://www.terraform.io/docs/language/settings/backends/s3.html"}),"Terraform documentation"),".")),Object(a.b)("h3",{id:"execution-flow"},"Execution Flow"),Object(a.b)("p",null,"Here is the execution flow when my Environment is deployed:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Qovery builds my Lifecycle Job (and my others services)."),Object(a.b)("li",{parentName:"ol"},"Qovery runs my Lifecycle Job ",Object(a.b)("strong",{parentName:"li"},"Start Event")," (and my others services)."),Object(a.b)("li",{parentName:"ol"},"My Lifecycle Job creates a new AWS RDS MySQL instance."),Object(a.b)("li",{parentName:"ol"},"My Lifecycle Job injects the database credentials into a ",Object(a.b)("inlineCode",{parentName:"li"},"/qovery-output/qovery-output.json")," file."),Object(a.b)("li",{parentName:"ol"},"Qovery reads the ",Object(a.b)("inlineCode",{parentName:"li"},"/qovery-output/qovery-output.json")," file and injects the database credentials into my Environment Variables."),Object(a.b)("li",{parentName:"ol"},"My others services can access my database.")),Object(a.b)("p",null,"When my Environment is deleted:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Qovery runs my Lifecycle Job ",Object(a.b)("strong",{parentName:"li"},"Deleted Event")),Object(a.b)("li",{parentName:"ol"},"My Lifecycle Job destroys the AWS RDS MySQL instance."),Object(a.b)("li",{parentName:"ol"},"Qovery destroys my Environment and release all the resources.")),Object(a.b)("h3",{id:"create-a-lifecycle-job"},"Create a Lifecycle Job"),Object(a.b)(l.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have a ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"https://start.qovery.com"}),"Qovery account")),Object(a.b)("li",{parentName:"ul"},"You have an existing project and an existing environment."))),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Fork ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples"}),"this repository"),".")),Object(a.b)("li",null,Object(a.b)("p",null,"Go inside your Environment, and add a ",Object(a.b)("strong",{parentName:"p"},"Lifecycle Job"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/1.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Give a name, description, pick your GitHub account, and select the repository of the Lifecycle Job. In our example, the root application path is ",Object(a.b)("inlineCode",{parentName:"p"},"/examples/aws-rds-with-terraform"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/2.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Since we are using Terraform, we want to make sure that our MySQL RDS instance is created when our Environment is deployed. So we select the ",Object(a.b)("strong",{parentName:"p"},"Start Event"),".\nWe also want to make sure that our MySQL RDS instance is destroyed when our Environment is deleted. So we select the ",Object(a.b)("strong",{parentName:"p"},"Deleted Event"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/3.png",alt:""})),Object(a.b)("p",null,"If you look at our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/blob/main/examples/aws-rds-with-terraform/Dockerfile"}),"Dockerfile")," in the repository, you will see that we are using the official Terraform image. I have also inserted by default the ",Object(a.b)("inlineCode",{parentName:"p"},'ENTRYPOINT ["/bin/sh"]')," to simplify the Qovery Lifecycle Job configuration."),Object(a.b)("p",null,"For the ",Object(a.b)("strong",{parentName:"p"},"Start Event"),", we want to run the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform apply -no-color -auto-approve")," command. We don't need to run the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform init")," command since it is already done in the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/blob/main/examples/aws-rds-with-terraform/Dockerfile#L14"}),"Dockerfile"),"."),Object(a.b)("p",null,"You will also notice that we are also using ",Object(a.b)("inlineCode",{parentName:"p"},"&& terraform output -json > /qovery-output/qovery-output.json")," to create a ",Object(a.b)("inlineCode",{parentName:"p"},"/qovery-output/qovery-output.json")," file. This file will be used by Qovery to inject the database credentials into our Environment Variables. We will cover this part later."),Object(a.b)("p",null,"For the ",Object(a.b)("strong",{parentName:"p"},"Deleted Event"),", we want to run the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform destroy -no-color -auto-approve")," command."),Object(a.b)("p",null,"So for the ",Object(a.b)("strong",{parentName:"p"},"Start Event"),", we have: ",Object(a.b)("inlineCode",{parentName:"p"},'["-c","terraform apply -no-color -auto-approve && terraform output -json > /qovery-output/qovery-output.json"]')," and for the ",Object(a.b)("strong",{parentName:"p"},"Deleted Event"),", we have: ",Object(a.b)("inlineCode",{parentName:"p"},'["-c","terraform destroy -no-color -auto-approve"]'),". Feel free to copy/paste these commands."),Object(a.b)(c.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Yes the commands contains a comma. It is not a typo. It is a JSON array. You need to use a comma to separate the elements of the array."))),Object(a.b)("li",null,Object(a.b)("p",null,"I recommend setting the ",Object(a.b)("strong",{parentName:"p"},"Timeout")," to 1800 seconds (30 minutes). It is the maximum time your Lifecycle Job can run. If your Lifecycle Job takes more than 30 minutes to run it will be stopped by Qovery. In our case, it should take less than 10 minutes to create the AWS RDS MySQL instance. But let's be safe."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/4.png",alt:""})),Object(a.b)("p",null,"Click ",Object(a.b)("strong",{parentName:"p"},"Continue"),".")),Object(a.b)("li",null,Object(a.b)("p",null,"Now we need to set the vCPU and RAM required to run our Job. We can allocate 0.5 CPU and 256 MB of RAM. It's more than enough."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/5.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"We need to set the Environment Variables required by our Lifecycle Job. In our case, we need to set the AWS credentials and some other environment variables. If you look at our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/blob/main/examples/aws-rds-with-terraform/Dockerfile#L3-L7"}),"Dockerfile"),", you will find the declaration of all those environment variables. You can copy/paste them."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-Dockerfile",metastring:'title="Dockerfile"',title:'"Dockerfile"'}),"...\nARG TF_VAR_terraform_backend_bucket\nARG TF_VAR_aws_region\nARG TF_VAR_aws_access_key_id\nARG TF_VAR_aws_secret_access_key\nARG TF_VAR_qovery_environment_id\n...\n")),Object(a.b)("p",null,"Those are the ones that we need to set."),Object(a.b)(c.a,{type:"warning",mdxType:"Alert"},Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"We do not set here the ",Object(a.b)("inlineCode",{parentName:"li"},"TF_VAR_qovery_environment_id")," since we will create it in the next step."),Object(a.b)("li",{parentName:"ol"},Object(a.b)("inlineCode",{parentName:"li"},"TF_VAR_terraform_backend_bucket")," is the name of the S3 bucket where Terraform will store the state of your infrastructure. You need to create this bucket on S3 before running the Lifecycle Job. You can use the same bucket for all your Lifecycle Jobs. It is not a problem. You will just need to make sure that the S3 object key is unique."))),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/6.png",alt:""})),Object(a.b)("p",null,"Click on ",Object(a.b)("strong",{parentName:"p"},"Continue"),".")),Object(a.b)("li",null,Object(a.b)("p",null,"Then click on ",Object(a.b)("strong",{parentName:"p"},"Create")," (and not ",Object(a.b)("strong",{parentName:"p"},"Create and Deploy"),")."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/7.png",alt:""}))),Object(a.b)("p",null,"Congrats, your Lifecycle Job is created. Now we just need to add the ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," environment variable before launching it."))),Object(a.b)("h3",{id:"make-your-terraform-deployment-multi-environments-ready"},"Make your Terraform deployment multi-environments ready"),Object(a.b)("p",null,"To support multiple environments, we need to make sure that the name of the S3 object key where Terraform will store the state of your infrastructure is unique. To do that, we will use the ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," environment variable. This environment variable is automatically created by Qovery and contains the ID of your Environment. We just need to create an environment variable alias."),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Go inside your ",Object(a.b)("strong",{parentName:"p"},"MySQL RDS")," service, click on the ",Object(a.b)("strong",{parentName:"p"},"Variables")," tab."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/8.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Search for ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable. Then click on ",Object(a.b)("strong",{parentName:"p"},"Creat alias")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/9.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Set the name of the environment variable to ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," with a ",Object(a.b)("strong",{parentName:"p"},"service")," scope and click on ",Object(a.b)("strong",{parentName:"p"},"Confirm"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/10.png",alt:""}))))),Object(a.b)("h3",{id:"deploy-aws-rds-mysql-instance"},"Deploy AWS RDS MySQL instance"),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Now you are ready to deploy your Lifecycle Job and see what happened."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/11.png",alt:""})),Object(a.b)("p",null,"The job execution will take approximately 3 to 10 minutes.")),Object(a.b)("li",null,Object(a.b)("p",null,"Follow the logs of the job execution by clicking on the ",Object(a.b)("strong",{parentName:"p"},"Logs")," button."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/12.png",alt:""})),Object(a.b)("p",null,"From the ",Object(a.b)("strong",{parentName:"p"},"Deployment logs")," tab you can see that your Lifecycle Job is built and that the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform init")," command is executed."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/13.png",alt:""})),Object(a.b)("p",null,"From the ",Object(a.b)("strong",{parentName:"p"},"MySQL RDS")," tab you can see that the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform apply -no-color -auto-approve")," command is executed. The creation of the AWS RDS MySQL instance is in progress."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/14.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Once the deployment is done, you should see that the AWS RDS MySQL instance is green and completed."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/15.png",alt:""}))))),Object(a.b)("h3",{id:"get-the-mysql-rds-credentials-from-the-lifecycle-job"},"Get the MySQL RDS credentials from the Lifecycle Job"),Object(a.b)("p",null,"Now that the AWS RDS MySQL instance is created, we need to get the credentials to connect to it. We have use the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform output -json > /qovery-output/qovery-output.json")," command to get the credentials. If you go back to the ",Object(a.b)("inlineCode",{parentName:"p"},"Variables")," tab of your MySQL RDS service, you will see that the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_OUTPUT_**")," environment variables are created."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/16.png",alt:""})),Object(a.b)("p",null,"By using ",Object(a.b)("inlineCode",{parentName:"p"},"terraform output -json > /qovery-output/qovery-output.json")," Qovery automatically create those environment variables for you. You can use them in your application to connect to the AWS RDS MySQL instance. ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/#job-output"}),"Learn more on how Lifecycle Job output...")),Object(a.b)(c.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,"Job output is a powerful feature that allows you to get the output of your Lifecycle Job and use it in your application. You can use it to get the credentials of your database, the URL of your S3 bucket, the URL of your CDN, etc...")),Object(a.b)("h2",{id:"faq"},"FAQ"),Object(a.b)("h3",{id:"what-happen-if-i-delete-my-environment-with-your-example"},"What happen if I delete my environment with your example?"),Object(a.b)("p",null,"If you delete your environment, the AWS RDS MySQL instance will be deleted too. You can see that in the ",Object(a.b)("strong",{parentName:"p"},"MySQL RDS")," service logs. You will see that the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform destroy -no-color -auto-approve")," command is executed."),Object(a.b)("h3",{id:"can-i-use-the-lifecycle-job-to-deploy-my-application"},"Can I use the Lifecycle Job to deploy my application?"),Object(a.b)("p",null,"Some users ask us if they can use the Lifecycle Job to deploy their application. The answer is yes!. The Lifecycle Job is designed to deploy all type of resources. However, we recommend using the official Qovery way to deploy applications. ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/"}),"Learn more on how to deploy your application...")),Object(a.b)("h3",{id:"what-happen-if-i-clone-my-environment-with-the-lifecycle-job"},"What happen if I clone my Environment with the Lifecycle Job?"),Object(a.b)("p",null,"If you clone an Environment with the Lifecycle Job, the Lifecycle Job will be cloned too. In our example we have set the ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," environment variable to the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable. So when you clone your Environment, the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable will be different. That's why you need to create a new alias environment variable for the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable. ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#clone-environment"}),"Learn more on how to clone an Environment...")),Object(a.b)("h3",{id:"what-happen-if-i-modify-my-lifecycle-job-after-my-environment-is-deployed"},"What happen if I modify my Lifecycle Job after my Environment is deployed?"),Object(a.b)("p",null,"If you modify your Lifecycle Job after your Environment is deployed, the Lifecycle Job will be redeployed. In our example, since the state of our AWS RDS MySQL instance is stored in the S3 bucket, the AWS RDS MySQL instance will not be recreated. However, if you modify the ",Object(a.b)("inlineCode",{parentName:"p"},"main.tf")," file, the AWS RDS MySQL instance will be updated."),Object(a.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(a.b)("p",null,"In this guide, we have seen how to use the Lifecycle Job to create an AWS RDS MySQL instance with Terraform. We have also seen how to get the credentials of the AWS RDS MySQL instance to connect to it from our application. To learn more about the Lifecycle Job, you can read the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"Lifecycle Job documentation"),". To get more examples, check out the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples"}),"Qovery Lifecycle Examples repository"),"."))}m.isMDXComponent=!0},420:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),b=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=b(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=b(n),m=o,y=u["".concat(i,".").concat(m)]||u[m]||p[m]||a;return n?r.a.createElement(y,c({ref:t},s,{components:n})):r.a.createElement(y,c({ref:t},s))}));function y(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var o=n(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var o=n(0),r=n.n(o),a=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var o=n(432),r=n(51);function a(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(r),a,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[a(t,e),"[",o,"]"].join(""):[a(t,e),"[",a(o,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return a(o,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(n(o,e,i.length))})),i.join("&")}return a(o,t)+"="+a(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),b=Object(o.useState)(null),u=b[0],p=b[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 6b7a52aa.261b2e2c.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[123],{274:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return m}));var o=n(1),r=n(9),a=(n(0),n(425)),i=n(434),c=n(424),l=n(429),s={last_modified_on:"2023-08-14",$schema:"/.meta/.schemas/guides.json",title:"How To Use Lifecycle Job To Deploy Any Kind Of Resources",description:"Learn how to use Lifecycle Job to deploy any kind of resources with Qovery.",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},b={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How To Use Lifecycle Job To Deploy Any Kind Of Resources",description:"Learn how to use Lifecycle Job to deploy any kind of resources with Qovery.",permalink:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources",readingTime:"10 min read",source:"@site/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How To Use Lifecycle Job To Deploy Any Kind Of Resources",truncated:!1,prevItem:{title:"How to use Github Organizations with Qovery",permalink:"/guides/tutorial/github-organization-repository-access"},nextItem:{title:"How to write a Dockerfile",permalink:"/guides/tutorial/how-to-write-a-dockerfile"}},u=[{value:"How to use Lifecycle Job (example with Terraform)",id:"how-to-use-lifecycle-job-example-with-terraform",children:[{value:"Execution Flow",id:"execution-flow",children:[]},{value:"Create a Lifecycle Job",id:"create-a-lifecycle-job",children:[]},{value:"Make your Terraform deployment multi-environments ready",id:"make-your-terraform-deployment-multi-environments-ready",children:[]},{value:"Deploy AWS RDS MySQL instance",id:"deploy-aws-rds-mysql-instance",children:[]},{value:"Get the MySQL RDS credentials from the Lifecycle Job",id:"get-the-mysql-rds-credentials-from-the-lifecycle-job",children:[]}]},{value:"FAQ",id:"faq",children:[{value:"What happen if I delete my environment with your example?",id:"what-happen-if-i-delete-my-environment-with-your-example",children:[]},{value:"Can I use the Lifecycle Job to deploy my application?",id:"can-i-use-the-lifecycle-job-to-deploy-my-application",children:[]},{value:"What happen if I clone my Environment with the Lifecycle Job?",id:"what-happen-if-i-clone-my-environment-with-the-lifecycle-job",children:[]},{value:"What happen if I modify my Lifecycle Job after my Environment is deployed?",id:"what-happen-if-i-modify-my-lifecycle-job-after-my-environment-is-deployed",children:[]}]},{value:"Wrapping up",id:"wrapping-up",children:[]}],p={rightToc:u};function m(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"The ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"Lifecycle Job")," is a powerful feature that allows you to run any kind of commands before or after your environment is deployed. It can be used to run database migrations, create a new database, or even to run a script that will create a new user."),Object(a.b)("p",null,"Some use cases:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Run Terraform, Pulumi, or any other infrastructure as code tool to create resources."),Object(a.b)("li",{parentName:"ul"},"You want to deploy SQS, SNS, Lambdas, or any other AWS resources."),Object(a.b)("li",{parentName:"ul"},"You want to deploy MongoDB Atlas, Google BigQuery, or any other cloud services."),Object(a.b)("li",{parentName:"ul"},"Seed your database when your environment is created.")),Object(a.b)(c.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,"You can find some Lifecycle Jobs examples on our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples"}),"GitHub"),".")),Object(a.b)("p",null,"In a more general way, you can see the Lifecycle Job as a way to create and destroy resources when your environment is deployed or deleted. Possibilities are endless."),Object(a.b)("h2",{id:"how-to-use-lifecycle-job-example-with-terraform"},"How to use Lifecycle Job (example with Terraform)"),Object(a.b)("p",null,"In this example, we will use Terraform to create a new AWS RDS MySQL instance. I will use ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-rds-with-terraform"}),"this example")," to schematize the process of using the Lifecycle Job. \u26a0\ufe0f Note that you can use any other tool to create your resources. Lifecycle Job is not limited to Terraform. However, Terraform is a great way to show the power of the Lifecycle Job since it requires a lot of configuration and can be used to create a lot of different resources."),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"In our example, we use S3 as a Terraform backend. You can use any other backend you want. However, if you want to use S3, you need to create a new bucket and a new IAM user with the right permissions. You can find more information about this in the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://www.terraform.io/docs/language/settings/backends/s3.html"}),"Terraform documentation"),".")),Object(a.b)("h3",{id:"execution-flow"},"Execution Flow"),Object(a.b)("p",null,"Here is the execution flow when my Environment is deployed:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Qovery builds my Lifecycle Job (and my others services)."),Object(a.b)("li",{parentName:"ol"},"Qovery runs my Lifecycle Job ",Object(a.b)("strong",{parentName:"li"},"Start Event")," (and my others services)."),Object(a.b)("li",{parentName:"ol"},"My Lifecycle Job creates a new AWS RDS MySQL instance."),Object(a.b)("li",{parentName:"ol"},"My Lifecycle Job injects the database credentials into a ",Object(a.b)("inlineCode",{parentName:"li"},"/qovery-output/qovery-output.json")," file."),Object(a.b)("li",{parentName:"ol"},"Qovery reads the ",Object(a.b)("inlineCode",{parentName:"li"},"/qovery-output/qovery-output.json")," file and injects the database credentials into my Environment Variables."),Object(a.b)("li",{parentName:"ol"},"My others services can access my database.")),Object(a.b)("p",null,"When my Environment is deleted:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Qovery runs my Lifecycle Job ",Object(a.b)("strong",{parentName:"li"},"Deleted Event")),Object(a.b)("li",{parentName:"ol"},"My Lifecycle Job destroys the AWS RDS MySQL instance."),Object(a.b)("li",{parentName:"ol"},"Qovery destroys my Environment and release all the resources.")),Object(a.b)("h3",{id:"create-a-lifecycle-job"},"Create a Lifecycle Job"),Object(a.b)(l.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have a ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"https://start.qovery.com"}),"Qovery account")),Object(a.b)("li",{parentName:"ul"},"You have an existing project and an existing environment."))),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Fork ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples"}),"this repository"),".")),Object(a.b)("li",null,Object(a.b)("p",null,"Go inside your Environment, and add a ",Object(a.b)("strong",{parentName:"p"},"Lifecycle Job"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/1.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Give a name, description, pick your GitHub account, and select the repository of the Lifecycle Job. In our example, the root application path is ",Object(a.b)("inlineCode",{parentName:"p"},"/examples/aws-rds-with-terraform"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/2.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Since we are using Terraform, we want to make sure that our MySQL RDS instance is created when our Environment is deployed. So we select the ",Object(a.b)("strong",{parentName:"p"},"Start Event"),".\nWe also want to make sure that our MySQL RDS instance is destroyed when our Environment is deleted. So we select the ",Object(a.b)("strong",{parentName:"p"},"Deleted Event"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/3.png",alt:""})),Object(a.b)("p",null,"If you look at our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/blob/main/examples/aws-rds-with-terraform/Dockerfile"}),"Dockerfile")," in the repository, you will see that we are using the official Terraform image. I have also inserted by default the ",Object(a.b)("inlineCode",{parentName:"p"},'ENTRYPOINT ["/bin/sh"]')," to simplify the Qovery Lifecycle Job configuration."),Object(a.b)("p",null,"For the ",Object(a.b)("strong",{parentName:"p"},"Start Event"),", we want to run the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform apply -no-color -auto-approve")," command. We don't need to run the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform init")," command since it is already done in the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/blob/main/examples/aws-rds-with-terraform/Dockerfile#L14"}),"Dockerfile"),"."),Object(a.b)("p",null,"You will also notice that we are also using ",Object(a.b)("inlineCode",{parentName:"p"},"&& terraform output -json > /qovery-output/qovery-output.json")," to create a ",Object(a.b)("inlineCode",{parentName:"p"},"/qovery-output/qovery-output.json")," file. This file will be used by Qovery to inject the database credentials into our Environment Variables. We will cover this part later."),Object(a.b)("p",null,"For the ",Object(a.b)("strong",{parentName:"p"},"Deleted Event"),", we want to run the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform destroy -no-color -auto-approve")," command."),Object(a.b)("p",null,"So for the ",Object(a.b)("strong",{parentName:"p"},"Start Event"),", we have: ",Object(a.b)("inlineCode",{parentName:"p"},'["-c","terraform apply -no-color -auto-approve && terraform output -json > /qovery-output/qovery-output.json"]')," and for the ",Object(a.b)("strong",{parentName:"p"},"Deleted Event"),", we have: ",Object(a.b)("inlineCode",{parentName:"p"},'["-c","terraform destroy -no-color -auto-approve"]'),". Feel free to copy/paste these commands."),Object(a.b)(c.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Yes the commands contains a comma. It is not a typo. It is a JSON array. You need to use a comma to separate the elements of the array."))),Object(a.b)("li",null,Object(a.b)("p",null,"I recommend setting the ",Object(a.b)("strong",{parentName:"p"},"Timeout")," to 1800 seconds (30 minutes). It is the maximum time your Lifecycle Job can run. If your Lifecycle Job takes more than 30 minutes to run it will be stopped by Qovery. In our case, it should take less than 10 minutes to create the AWS RDS MySQL instance. But let's be safe."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/4.png",alt:""})),Object(a.b)("p",null,"Click ",Object(a.b)("strong",{parentName:"p"},"Continue"),".")),Object(a.b)("li",null,Object(a.b)("p",null,"Now we need to set the vCPU and RAM required to run our Job. We can allocate 0.5 CPU and 256 MB of RAM. It's more than enough."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/5.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"We need to set the Environment Variables required by our Lifecycle Job. In our case, we need to set the AWS credentials and some other environment variables. If you look at our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/blob/main/examples/aws-rds-with-terraform/Dockerfile#L3-L7"}),"Dockerfile"),", you will find the declaration of all those environment variables. You can copy/paste them."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-Dockerfile",metastring:'title="Dockerfile"',title:'"Dockerfile"'}),"...\nARG TF_VAR_terraform_backend_bucket\nARG TF_VAR_aws_region\nARG TF_VAR_aws_access_key_id\nARG TF_VAR_aws_secret_access_key\nARG TF_VAR_qovery_environment_id\n...\n")),Object(a.b)("p",null,"Those are the ones that we need to set."),Object(a.b)(c.a,{type:"warning",mdxType:"Alert"},Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"We do not set here the ",Object(a.b)("inlineCode",{parentName:"li"},"TF_VAR_qovery_environment_id")," since we will create it in the next step."),Object(a.b)("li",{parentName:"ol"},Object(a.b)("inlineCode",{parentName:"li"},"TF_VAR_terraform_backend_bucket")," is the name of the S3 bucket where Terraform will store the state of your infrastructure. You need to create this bucket on S3 before running the Lifecycle Job. You can use the same bucket for all your Lifecycle Jobs. It is not a problem. You will just need to make sure that the S3 object key is unique."))),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/6.png",alt:""})),Object(a.b)("p",null,"Click on ",Object(a.b)("strong",{parentName:"p"},"Continue"),".")),Object(a.b)("li",null,Object(a.b)("p",null,"Then click on ",Object(a.b)("strong",{parentName:"p"},"Create")," (and not ",Object(a.b)("strong",{parentName:"p"},"Create and Deploy"),")."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/7.png",alt:""}))),Object(a.b)("p",null,"Congrats, your Lifecycle Job is created. Now we just need to add the ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," environment variable before launching it."))),Object(a.b)("h3",{id:"make-your-terraform-deployment-multi-environments-ready"},"Make your Terraform deployment multi-environments ready"),Object(a.b)("p",null,"To support multiple environments, we need to make sure that the name of the S3 object key where Terraform will store the state of your infrastructure is unique. To do that, we will use the ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," environment variable. This environment variable is automatically created by Qovery and contains the ID of your Environment. We just need to create an environment variable alias."),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Go inside your ",Object(a.b)("strong",{parentName:"p"},"MySQL RDS")," service, click on the ",Object(a.b)("strong",{parentName:"p"},"Variables")," tab."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/8.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Search for ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable. Then click on ",Object(a.b)("strong",{parentName:"p"},"Creat alias")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/9.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Set the name of the environment variable to ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," with a ",Object(a.b)("strong",{parentName:"p"},"service")," scope and click on ",Object(a.b)("strong",{parentName:"p"},"Confirm"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/10.png",alt:""}))))),Object(a.b)("h3",{id:"deploy-aws-rds-mysql-instance"},"Deploy AWS RDS MySQL instance"),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Now you are ready to deploy your Lifecycle Job and see what happened."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/11.png",alt:""})),Object(a.b)("p",null,"The job execution will take approximately 3 to 10 minutes.")),Object(a.b)("li",null,Object(a.b)("p",null,"Follow the logs of the job execution by clicking on the ",Object(a.b)("strong",{parentName:"p"},"Logs")," button."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/12.png",alt:""})),Object(a.b)("p",null,"From the ",Object(a.b)("strong",{parentName:"p"},"Deployment logs")," tab you can see that your Lifecycle Job is built and that the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform init")," command is executed."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/13.png",alt:""})),Object(a.b)("p",null,"From the ",Object(a.b)("strong",{parentName:"p"},"MySQL RDS")," tab you can see that the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform apply -no-color -auto-approve")," command is executed. The creation of the AWS RDS MySQL instance is in progress."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/14.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Once the deployment is done, you should see that the AWS RDS MySQL instance is green and completed."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/15.png",alt:""}))))),Object(a.b)("h3",{id:"get-the-mysql-rds-credentials-from-the-lifecycle-job"},"Get the MySQL RDS credentials from the Lifecycle Job"),Object(a.b)("p",null,"Now that the AWS RDS MySQL instance is created, we need to get the credentials to connect to it. We have use the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform output -json > /qovery-output/qovery-output.json")," command to get the credentials. If you go back to the ",Object(a.b)("inlineCode",{parentName:"p"},"Variables")," tab of your MySQL RDS service, you will see that the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_OUTPUT_**")," environment variables are created."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/16.png",alt:""})),Object(a.b)("p",null,"By using ",Object(a.b)("inlineCode",{parentName:"p"},"terraform output -json > /qovery-output/qovery-output.json")," Qovery automatically create those environment variables for you. You can use them in your application to connect to the AWS RDS MySQL instance. ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/#job-output"}),"Learn more on how Lifecycle Job output...")),Object(a.b)(c.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,"Job output is a powerful feature that allows you to get the output of your Lifecycle Job and use it in your application. You can use it to get the credentials of your database, the URL of your S3 bucket, the URL of your CDN, etc...")),Object(a.b)("h2",{id:"faq"},"FAQ"),Object(a.b)("h3",{id:"what-happen-if-i-delete-my-environment-with-your-example"},"What happen if I delete my environment with your example?"),Object(a.b)("p",null,"If you delete your environment, the AWS RDS MySQL instance will be deleted too. You can see that in the ",Object(a.b)("strong",{parentName:"p"},"MySQL RDS")," service logs. You will see that the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform destroy -no-color -auto-approve")," command is executed."),Object(a.b)("h3",{id:"can-i-use-the-lifecycle-job-to-deploy-my-application"},"Can I use the Lifecycle Job to deploy my application?"),Object(a.b)("p",null,"Some users ask us if they can use the Lifecycle Job to deploy their application. The answer is yes!. The Lifecycle Job is designed to deploy all type of resources. However, we recommend using the official Qovery way to deploy applications. ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/"}),"Learn more on how to deploy your application...")),Object(a.b)("h3",{id:"what-happen-if-i-clone-my-environment-with-the-lifecycle-job"},"What happen if I clone my Environment with the Lifecycle Job?"),Object(a.b)("p",null,"If you clone an Environment with the Lifecycle Job, the Lifecycle Job will be cloned too. In our example we have set the ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," environment variable to the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable. So when you clone your Environment, the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable will be different. That's why you need to create a new alias environment variable for the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable. ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#clone-environment"}),"Learn more on how to clone an Environment...")),Object(a.b)("h3",{id:"what-happen-if-i-modify-my-lifecycle-job-after-my-environment-is-deployed"},"What happen if I modify my Lifecycle Job after my Environment is deployed?"),Object(a.b)("p",null,"If you modify your Lifecycle Job after your Environment is deployed, the Lifecycle Job will be redeployed. In our example, since the state of our AWS RDS MySQL instance is stored in the S3 bucket, the AWS RDS MySQL instance will not be recreated. However, if you modify the ",Object(a.b)("inlineCode",{parentName:"p"},"main.tf")," file, the AWS RDS MySQL instance will be updated."),Object(a.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(a.b)("p",null,"In this guide, we have seen how to use the Lifecycle Job to create an AWS RDS MySQL instance with Terraform. We have also seen how to get the credentials of the AWS RDS MySQL instance to connect to it from our application. To learn more about the Lifecycle Job, you can read the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"Lifecycle Job documentation"),". To get more examples, check out the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples"}),"Qovery Lifecycle Examples repository"),"."))}m.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),b=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=b(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=b(n),m=o,y=u["".concat(i,".").concat(m)]||u[m]||p[m]||a;return n?r.a.createElement(y,c({ref:t},s,{components:n})):r.a.createElement(y,c({ref:t},s))}));function y(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var o=n(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var o=n(0),r=n.n(o),a=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var o=n(435),r=n(51);function a(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(r),a,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[a(t,e),"[",o,"]"].join(""):[a(t,e),"[",a(o,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return a(o,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(n(o,e,i.length))})),i.join("&")}return a(o,t)+"="+a(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),b=Object(o.useState)(null),u=b[0],p=b[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/7952d159.efc8de7a.js.LICENSE.txt b/6b7a52aa.261b2e2c.js.LICENSE.txt similarity index 100% rename from 7952d159.efc8de7a.js.LICENSE.txt rename to 6b7a52aa.261b2e2c.js.LICENSE.txt diff --git a/6ce627d6.09be1995.js b/6ce627d6.918e632b.js similarity index 97% rename from 6ce627d6.09be1995.js rename to 6ce627d6.918e632b.js index 1ef12b2991..27d523715f 100644 --- a/6ce627d6.09be1995.js +++ b/6ce627d6.918e632b.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[122],{273:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return u})),a.d(t,"metadata",(function(){return s})),a.d(t,"rightToc",(function(){return p})),a.d(t,"default",(function(){return m}));var o=a(1),n=a(9),r=(a(0),a(422)),l=a(421),i=a(441),c=a(434),b=a(426),u={last_modified_on:"2023-05-29",$schema:"/.meta/.schemas/guides.json",title:"Migrate your application from Heroku to AWS",description:"Guide on how to migrate all your applications from Heroku to AWS with your databases",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Migrate your application from Heroku to AWS",description:"Guide on how to migrate all your applications from Heroku to AWS with your databases",permalink:"/guides/tutorial/migrate-your-application-from-heroku-to-aws",readingTime:"13 min read",source:"@site/guides/tutorial/migrate-your-application-from-heroku-to-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Migrate your application from Heroku to AWS",truncated:!1,prevItem:{title:"Microservices",permalink:"/guides/advanced/microservices"},nextItem:{title:"Migration",permalink:"/guides/advanced/migration"}},p=[{value:"Migration Steps",id:"migration-steps",children:[]},{value:"1. Create your Dockerfile or Use Buildpacks",id:"1-create-your-dockerfile-or-use-buildpacks",children:[{value:"Choose your Dockerfile template",id:"choose-your-dockerfile-template",children:[]},{value:"Test your Dockerfile",id:"test-your-dockerfile",children:[]},{value:"Environment variables at the build time",id:"environment-variables-at-the-build-time",children:[]},{value:"Add your Dockerfile to Git",id:"add-your-dockerfile-to-git",children:[]},{value:"Loop",id:"loop",children:[]},{value:"Limitations",id:"limitations",children:[]}]},{value:"2. Create resources on Qovery",id:"2-create-resources-on-qovery",children:[{value:"Application",id:"application",children:[]},{value:"Database",id:"database",children:[]}]},{value:"3. Configure your Environment Variables and Secrets",id:"3-configure-your-environment-variables-and-secrets",children:[{value:"Connect your frontend app to your backend app",id:"connect-your-frontend-app-to-your-backend-app",children:[]},{value:"Connect your backend app to your database",id:"connect-your-backend-app-to-your-database",children:[]}]},{value:"4. Copy data from your Heroku databases to your AWS databases",id:"4-copy-data-from-your-heroku-databases-to-your-aws-databases",children:[]},{value:"5. Deploy your apps!",id:"5-deploy-your-apps",children:[]},{value:"FAQ by Heroku users",id:"faq-by-heroku-users",children:[{value:"How to create a custom domain?",id:"how-to-create-a-custom-domain",children:[]},{value:"How to monitor my apps?",id:"how-to-monitor-my-apps",children:[]},{value:"Do you have Heroku "Review App" equivalent?",id:"do-you-have-heroku-review-app-equivalent",children:[]},{value:"How to rollback?",id:"how-to-rollback",children:[]},{value:"How auto-scaling works?",id:"how-auto-scaling-works",children:[]},{value:"How to manage database migration?",id:"how-to-manage-database-migration",children:[]},{value:"Is it possible to get a shell / connect to my app?",id:"is-it-possible-to-get-a-shell--connect-to-my-app",children:[]},{value:"Can I use Terraform and Infrastructure as Code?",id:"can-i-use-terraform-and-infrastructure-as-code",children:[]},{value:"How can I connect my app to MongoDB Atlas?",id:"how-can-i-connect-my-app-to-mongodb-atlas",children:[]},{value:"How can I connect my app to an AWS service not managed by Qovery?",id:"how-can-i-connect-my-app-to-an-aws-service-not-managed-by-qovery",children:[]}]},{value:"Wrapping up",id:"wrapping-up",children:[]}],d={rightToc:p};function m(e){var t=e.components,a=Object(n.a)(e,["components"]);return Object(r.b)("wrapper",Object(o.a)({},d,a,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"This guide describes how to migrate your application running on Heroku to AWS with Qovery. It covers all required steps you need to take to deploy your application on AWS and transfer your data from Heroku Postgres to the database managed by AWS via Qovery."),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Please contact us via ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum")," if you experience any problem while migrating from Heroku to AWS with Qovery.")),Object(r.b)(b.a,{name:"guide",mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You are familiar with Heroku basics, have a Heroku account and access to Heroku CLI"),Object(r.b)("li",{parentName:"ul"},"You have ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"https://start.qovery.com"}),"sign in on Qovery")),Object(r.b)("li",{parentName:"ul"},"You have ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/cloud-provider/guide-amazon-web-services/"}),"set up your AWS account")," with Qovery"))),Object(r.b)("h2",{id:"migration-steps"},"Migration Steps"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#1-create-your-dockerfile-or-use-buildpacks"}),"Use Buildpacks or Create your Dockerfile")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#2-create-resources-on-qovery"}),"Create resources on Qovery")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#3-configure-your-environment-variables-and-secrets"}),"Configure Environment Variables and Secrets")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#4-copy-data-from-your-heroku-databases-to-your-aws-databases"}),"Copy data from your Heroku databases to your AWS databases")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#5-deploy-your-apps-"}),"Deploy your apps")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#faq-by-heroku-users"}),"FAQ by Heroku users"))),Object(r.b)("h2",{id:"1-create-your-dockerfile-or-use-buildpacks"},"1. Create your Dockerfile or Use Buildpacks"),Object(r.b)("p",null,"Qovery supports two ways to build and run your application coming from Heroku:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Buildpacks"),Object(r.b)("li",{parentName:"ol"},"Docker")),Object(r.b)("p",null,"Both options build a container image that is runnable by a container engine (E.g. Docker). Qovery runs containers on Kubernetes."),Object(r.b)("p",null,"Choose the option that better fits you:"),Object(r.b)(c.a,{centered:!0,className:"rounded",defaultValue:"buildpacks",placeholder:"Use Buildpacks or Create your Dockerfile",select:!1,size:null,values:[{group:"Platforms",label:"Use Buildpacks",value:"buildpacks"},{group:"Platforms",label:"Create your Dockerfile",value:"dockerfile"}],mdxType:"Tabs"},Object(r.b)(i.a,{value:"dockerfile",mdxType:"TabItem"},Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Are you familiar with Dockerfile? If not, I do recommend reading ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/how-to-write-a-dockerfile/"}),"this article"),".")),Object(r.b)("p",null,"Here we will create our Dockerfiles to build and run our applications. Qovery will handle the build and the run of your applications, but need to have at least a Dockerfile to do it."),Object(r.b)("h3",{id:"choose-your-dockerfile-template"},"Choose your Dockerfile template"),Object(r.b)("p",null,"To get started,"),Object(r.b)("h4",{id:"find-dockerfile-template"},"Find Dockerfile template"),Object(r.b)("p",null,"Pick one Dockerfile template according to the programming language or framework you are using for your app:"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Your framework or language is missing? Open a thread on ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum"),", and we will provide you one.")),Object(r.b)(c.a,{centered:!1,className:"square",defaultValue:"rails",select:!1,size:null,values:[{group:"Files",label:"Rails",value:"rails"},{group:"Files",label:"NodeJS",value:"nodejs"},{group:"Files",label:"React",value:"react"},{group:"Files",label:"VueJS",value:"vuejs"},{group:"Files",label:"NextJS",value:"nextjs"},{group:"Files",label:"Golang",value:"golang"},{group:"Files",label:"Flask",value:"flask"},{group:"Files",label:"Django",value:"django"},{group:"Files",label:"Laravel",value:"laravel"},{group:"Files",label:"Symfony",value:"symfony"},{group:"Files",label:"Spring",value:"spring"},{group:"Files",label:"Rust",value:"rust"}],mdxType:"Tabs"},Object(r.b)(i.a,{value:"rails",mdxType:"TabItem"},Object(r.b)("p",null,"Here is the Dockerfile for your Rails application listening on the PORT 3000"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Dockerfile"',title:'"Dockerfile"'}),'# syntax=docker/dockerfile:1\nFROM ruby:2.7\nRUN apt-get update -qq && apt-get install -y nodejs postgresql-client\nWORKDIR /myapp\nCOPY Gemfile Gemfile\nCOPY Gemfile.lock Gemfile.lock\nRUN bundle install\n\nCOPY . .\n\nEXPOSE 3000\n\n# Configure the main process to run when running the image\nCMD ["rails", "server", "-b", "0.0.0.0", "-p", "3000"]\n')),Object(r.b)("details",null,Object(r.b)("summary",null,"Dockerfile for Sidekiq"),Object(r.b)("p",null,"Here is the Dockerfile for your Rails app running as a worker mode with Sidekiq."),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"There is no listening port since it is consuming resources from a queuing system (E.g. Redis)")),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Dockerfile for Sidekiq"',title:'"Dockerfile',for:!0,'Sidekiq"':!0}),'# syntax=docker/dockerfile:1\nFROM ruby:2.7\nRUN apt-get update -qq && apt-get install -y nodejs postgresql-client # add mysql client if you need to\nWORKDIR /myapp\nCOPY Gemfile Gemfile\nCOPY Gemfile.lock Gemfile.lock\nRUN bundle install\n\nCOPY . .\n\nCMD ["bundle", "exec", "sidekiq"]\n')))),Object(r.b)(i.a,{value:"nodejs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"react",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"vuejs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"nextjs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"golang",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"flask",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"django",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"laravel",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"symfony",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"spring",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"rust",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n")))),Object(r.b)("h4",{id:"copy-template"},"Copy template"),Object(r.b)("p",null,"Copy your Dockerfile at the root of your project. By convention, you can name your file ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile"),". If you already have a Dockerfile, feel free to name it ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile.qovery"),". If you are using multiple Dockerfile for Qovery, feel free to give a name like ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile-sidekiq.qovery"),"."),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Read ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/t/904"}),"this forum post")," to know how to use the same Dockerfile with different CMD parameters.")),Object(r.b)("p",null,"For our example of migrating a Rails app and a Rails Sidekiq app, I will have at the root of my project a ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile.qovery")," and a ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile-sidekiq.qovery"),"."),Object(r.b)("h3",{id:"test-your-dockerfile"},"Test your Dockerfile"),Object(r.b)(b.a,{mdxType:"Assumptions"},Object(r.b)("p",null,"You need to ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.docker.com/get-docker/"}),"install Docker")," to test your Dockerfile")),Object(r.b)("p",null,"To test your Dockerfile we will locally our container. You just need to run the following commands:"),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Don't forget the ",Object(r.b)("inlineCode",{parentName:"p"},".")," (dot) at the end of the ",Object(r.b)("inlineCode",{parentName:"p"},"docker build")," command.")),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"docker build -f Dockerfile.qovery .\n")),Object(r.b)("p",null,"If everything goes well you should get the finale image ID at the end of the output."),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"[+] Building 19.0s (16/16) FINISHED\n => [internal] load build definition from Dockerfile 0.0s\n => => transferring dockerfile: 37B 0.0s\n => [internal] load .dockerignore 0.0s\n ...\n => [7/7] COPY . . 0.2s\n => exporting to image 0.0s\n => exporting layers 0.4s\n => writing image sha256:a0f90a6ec8bc4036a7b268479a0c0773ca324ba2de11fdef31309650743f4055 0.0s\n")),Object(r.b)("p",null,"To run your image you can run:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"docker run a0f90a6ec8bc4036a7b268479a0c0773ca324ba2de11fdef31309650743f4055\n")),Object(r.b)("p",null,"If your app required a database to starts, then it can be normal that it fails to start. Otherwise, if your app is supposed to start and does not, then you will need to fix the issue and rebuild your app with ",Object(r.b)("inlineCode",{parentName:"p"},"docker build -f Dockerfile.qovery .")),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"This step is one of the most complex, but once you successfully build your application with Docker, your app will run anywhere (not only on AWS with Qovery).")),Object(r.b)("p",null,"Any error while building your container image? 2 solutions:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},'Read the error message and try to understand from where the problem is coming from. You can "Google" the error if it is not related to your code.'),Object(r.b)("li",{parentName:"ol"},"Open a thread on ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"https://discuss.qovery.com/"}),"our forum")," if you don't find the answer there, we will be happy to assist you.")),Object(r.b)("h3",{id:"environment-variables-at-the-build-time"},"Environment variables at the build time"),Object(r.b)("p",null,"Does your app use some environment variables at the build time? Then you will need to modify your Dockerfile to includes the environment variables. Let's imagine your app uses the environment variable ",Object(r.b)("inlineCode",{parentName:"p"},"CONTENT_API_KEY"),", then you will need to add the following instructions in your Dockerfile:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Dockerfile with environment variables"',title:'"Dockerfile',with:!0,environment:!0,'variables"':!0}),"...\nARG CONTENT_API_KEY\nENV CONTENT_API_KEY $CONTENT_API_KEY\n...\n")),Object(r.b)("p",null,"The value of the ",Object(r.b)("inlineCode",{parentName:"p"},"CONTENT_API_KEY")," environment variable will be taken from the specified environment variables in Qovery."),Object(r.b)(l.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Qovery injects Environment Variables and Secrets at the build and run time of your app.")),Object(r.b)("h3",{id:"add-your-dockerfile-to-git"},"Add your Dockerfile to Git"),Object(r.b)("p",null,"Now, add your new Dockerfile to git with the following commands:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),'git add Dockerfile.qovery\ngit commit -m "Add Qovery Dockerfile"\ngit push origin\n')),Object(r.b)("h3",{id:"loop"},"Loop"),Object(r.b)("p",null,"If you have multiple applications to deploy, create a Dockerfile for each of them.")),Object(r.b)(i.a,{value:"buildpacks",mdxType:"TabItem"},Object(r.b)("p",null,Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://buildpacks.io/"}),"Buildpacks")," automatically detects the language and the framework your application is using. Buildpacks builds and runs your app. Here is the list of ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#option-1-buildpacks"}),"supported languages and frameworks"),"."),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"We do recommend using Docker to keep the full control of what's going on behind the scene. Buildpacks is a great technology but difficult to debug when something goes wrong. You can try deploying your apps on AWS with Qovery with Buildpacks, if you do not succeed, we do recommend switching for Docker.")),Object(r.b)("h3",{id:"limitations"},"Limitations"),Object(r.b)("p",null,"Here are some limitations due to our Buildpacks implementation:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Qovery Buildpacks does not support Procfile with multiple commands at the moment."),Object(r.b)("li",{parentName:"ul"},"Qovery does not support custom Buildpacks.")),Object(r.b)("p",null,"Those limitations will be solved in the coming months."))),Object(r.b)("h2",{id:"2-create-resources-on-qovery"},"2. Create resources on Qovery"),Object(r.b)("h3",{id:"application"},"Application"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Are you a new Qovery user? Watch ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"this tutorial")," to learn how to deploy your first app.")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/9246ae68c68f42debc3d5183d2b4f7f8",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Steps:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Connect to the ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"https://start.qovery.com"}),"Qovery console"),"."),Object(r.b)("li",{parentName:"ol"},"Create your ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization")," and your ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/project/"}),"Project"),"."),Object(r.b)("li",{parentName:"ol"},"Create an environment with the name ",Object(r.b)("inlineCode",{parentName:"li"},"production")," (it can be changed after)."),Object(r.b)("li",{parentName:"ol"},"Create an application and give it a name (you can give the name of your repo if you have no idea)"),Object(r.b)("li",{parentName:"ol"},"Select your app repository from your GitHub, GitLab or Bitbucket."),Object(r.b)("li",{parentName:"ol"},"Select the branch you want to deploy."),Object(r.b)("li",{parentName:"ol"},"Select the Build mode for ",Object(r.b)("inlineCode",{parentName:"li"},"Buildpacks")," or ",Object(r.b)("inlineCode",{parentName:"li"},"Dockerfile")," according to what you want."),Object(r.b)("li",{parentName:"ol"},"Specify the local listening port of your application."),Object(r.b)("li",{parentName:"ol"},'Click on "create"')),Object(r.b)("p",null,"Congrats! Your application is created \ud83c\udf89"),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,'Your application is created but not deployed yet! You can configure the vCPU, Memory, Environment Variables... before deploying it. If you want to deploy it before finishing the configuration you can click on "Actions" > "Deploy".')),Object(r.b)("p",null,"If you deploy an app from a mono-repository, we have a must-read guide for you ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/advanced/monorepository/"}),"here"),"."),Object(r.b)("h3",{id:"database"},"Database"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Are you a new Qovery user? Watch ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"this tutorial")," to learn how to deploy your database.")),Object(r.b)("p",null,"Here are the steps to deploy your database:"),Object(r.b)(b.a,{mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have created an application before"))),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/d7e10be0e5964f6799b158dc631bbbd1",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Steps:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Go to your ",Object(r.b)("inlineCode",{parentName:"li"},"production")," environment."),Object(r.b)("li",{parentName:"ol"},'Add your database by clicking on "Add" > "Database".'),Object(r.b)("li",{parentName:"ol"},"Select the database (PostgreSQL, MySQL, MongoDB, Redis..) and the version you want to deploy."),Object(r.b)("li",{parentName:"ol"},"Select ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/database/#general"}),"Managed or Container mode")," for your database."),Object(r.b)("li",{parentName:"ol"},"Select ",Object(r.b)("inlineCode",{parentName:"li"},"Public")," accessibility (set ",Object(r.b)("inlineCode",{parentName:"li"},"Private")," if you don't want to restore your data from an existing Heroku database).")),Object(r.b)("p",null,"Congrats! Your database is created as well \ud83c\udf89"),Object(r.b)("p",null,"If you use MongoDB Atlas, or an existing database on AWS that you want to connect to your application deployed by Qovery. Check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"our tutorial about VPC peering")," and how to securely connect to your existing database."),Object(r.b)("h2",{id:"3-configure-your-environment-variables-and-secrets"},"3. Configure your Environment Variables and Secrets"),Object(r.b)(l.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Qovery supports Doppler integration - it's the easiest way to migrate your Environment Variables and Secrets from Heroku to Qovery. ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/secret-manager/doppler/"}),"More info here"),".")),Object(r.b)("p",null,"Qovery makes the difference between an environment variable and a secret. Basically, a Secret is similar to an Environment Variable but the value is encrypted and can't be revealed. Both are injected as environment variables during the build and the run of your applications. ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"More info here")),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"I recommend reading our ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/managing-environment-variables/"}),"Getting Started with Environment Variables")," guide.")),Object(r.b)("p",null,"To extract your environment variables from Heroku, we recommend using the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://devcenter.heroku.com/articles/heroku-cli"}),"Heroku CLI")," and exporting all the environment variables and secrets in an .env (dot env) file. Qovery supports the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli/"}),"import of a dot env file")," via the Qovery web interface and the Qovery CLI."),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"If you use Buildpacks for one of your app AND you have indicated a local listening port of your application, you will need to add an environment variable ",Object(r.b)("inlineCode",{parentName:"p"},"PORT")," with the value of your port to make your application starting properly. Otherwise, Qovery will fail to deploy your app!")),Object(r.b)("p",null,Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://devcenter.heroku.com/articles/config-vars#view-current-config-var-values"}),"Export your environment variable via the Heroku CLI")," with the command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"# To install Heroku CLI: https://devcenter.heroku.com/articles/heroku-cli\nheroku config\n\nGREETINGS: hello world\nSTRIPE_API_KEY: xxx-yyy-zzz\nIS_PRODUCTION: true\n")),Object(r.b)("p",null,"Then you can create your environment variables via the web interface (watch the video below)"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/50899d7fa3d84a418f0db69f54f970d3",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Or via the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI"),":"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Import Heroku environment variables with the Qovery CLI"',title:'"Import',Heroku:!0,environment:!0,variables:!0,with:!0,the:!0,Qovery:!0,'CLI"':!0}),"# auth yourself\nqovery auth\n\n# selection the app where you want to import your environment variables\nqovery context set\n\n# import your Heroku environment variables\nheroku config --app --json | \\\n qovery env parse --heroku-json > heroku.env && \\\n qovery env import heroku.env && \\\n rm heroku.env\n\nQovery: dot env file to import: 'heroku.env'\n? Do you want to import Environment Variables or Secrets? Environment Variables\n? What environment variables do you want to import? [Use arrows to move, space to select, to all, to none, type to filter]\n [x] GREETINGS=hello world\n [ ] STRIPE_API_KEY=xxx-yyy-zzz\n> [x] IS_PRODUCTION=true\n\nQovery: \u2705 Environment Variables successfully imported!\n")),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Import sensitive data (E.g. API keys, credentials...) as ",Object(r.b)("inlineCode",{parentName:"p"},"Secret")," and not ",Object(r.b)("inlineCode",{parentName:"p"},"Environment Variable"),".")),Object(r.b)("h3",{id:"connect-your-frontend-app-to-your-backend-app"},"Connect your frontend app to your backend app"),Object(r.b)("p",null,"To connect your frontend app your backend app we will create an ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#alias-environment-variable"}),"environment variable alias"),"."),Object(r.b)("p",null,"Here is how to create a frontend app:"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/bafbbda93bd64d04afb3189bf4a1a201",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"And now how to connect your frontend app with your backend app:"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/f820925f2175465f9271b97ef414bb42",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"You can also take a look at ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/t/918"}),"this forum reply")," to learn how to do it."),Object(r.b)("h3",{id:"connect-your-backend-app-to-your-database"},"Connect your backend app to your database"),Object(r.b)("p",null,"Same as connecting your frontend app to your backend app, you can create an environment variable alias ",Object(r.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," for the ",Object(r.b)("em",{parentName:"p"},"built-in")," secret finishing with ",Object(r.b)("inlineCode",{parentName:"p"},"_DATABASE_URL_INTERNAL"),"."),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Create an alias on ",Object(r.b)("inlineCode",{parentName:"p"},"_DATABASE_URL_INTERNAL")," and not ",Object(r.b)("inlineCode",{parentName:"p"},"_DATABASE_URL"))),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/59f8368eb3c14796a807c7e39e9c0ab0",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"4-copy-data-from-your-heroku-databases-to-your-aws-databases"},"4. Copy data from your Heroku databases to your AWS databases"),Object(r.b)("p",null,Object(r.b)("em",{parentName:"p"},"Coming soon with ",Object(r.b)("a",Object(o.a)({parentName:"em"},{href:"https://www.replibyte.com"}),"Replibyte"))),Object(r.b)("h2",{id:"5-deploy-your-apps"},"5. Deploy your apps!"),Object(r.b)("p",null,"We are finally ready to deploy my applications on AWS!"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/0589d2f2aa4149edb605dc23f4efd23d",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Watch the final result \ud83d\ude0e"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/da31c21f9c104eae9270e4c4db59055e",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"faq-by-heroku-users"},"FAQ by Heroku users"),Object(r.b)("h3",{id:"how-to-create-a-custom-domain"},"How to create a custom domain?"),Object(r.b)("p",null,"Check out the documentation on ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/setting-custom-domain/"}),"how to configure your custom domain"),"."),Object(r.b)("h3",{id:"how-to-monitor-my-apps"},"How to monitor my apps?"),Object(r.b)("p",null,"We do recommend using ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://www.datadoghq.com"}),"Datadog")," or any other monitoring products for monitoring your apps deployed by Qovery. Check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/"}),"our tutorial on how to install Datadog"),"."),Object(r.b)("h3",{id:"do-you-have-heroku-review-app-equivalent"},'Do you have Heroku "Review App" equivalent?'),Object(r.b)("p",null,"Yes, it's what we call ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#preview-environment"}),"Preview Environment")),Object(r.b)("h3",{id:"how-to-rollback"},"How to rollback?"),Object(r.b)("p",null,"Check out the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deployment-actions/#deploy-other-version"}),"app rollback documentation")),Object(r.b)("h3",{id:"how-auto-scaling-works"},"How auto-scaling works?"),Object(r.b)("p",null,"Check out the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#auto-scaling"}),"app auto-scaling documentation")),Object(r.b)("h3",{id:"how-to-manage-database-migration"},"How to manage database migration?"),Object(r.b)("p",null,"Check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/t/951"}),"our forum reply")),Object(r.b)("h3",{id:"is-it-possible-to-get-a-shell--connect-to-my-app"},"Is it possible to get a shell / connect to my app?"),Object(r.b)("p",null,"Yes, with the Qovery CLI and the command ",Object(r.b)("inlineCode",{parentName:"p"},"qovery shell"),". ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#shell"}),"Check out the documentation"),"."),Object(r.b)("h3",{id:"can-i-use-terraform-and-infrastructure-as-code"},"Can I use Terraform and Infrastructure as Code?"),Object(r.b)("p",null,"Absolutely, we have a ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"Qovery Terraform provider")," available."),Object(r.b)("h3",{id:"how-can-i-connect-my-app-to-mongodb-atlas"},"How can I connect my app to MongoDB Atlas?"),Object(r.b)("p",null,"If you use MongoDB Atlas check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"our tutorial about VPC peering")," and how to securely connect to your existing MongoDB Atlas database."),Object(r.b)("h3",{id:"how-can-i-connect-my-app-to-an-aws-service-not-managed-by-qovery"},"How can I connect my app to an AWS service not managed by Qovery?"),Object(r.b)("p",null,"If you want to connect your app to an AWS service not managed by Qovery, check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"our tutorial about VPC peering")," and how to securely connect to this AWS service."),Object(r.b)("hr",null),Object(r.b)("p",null,"If you have a common question about Qovery, we have a more general ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/useful-resources/faq/"}),"FAQ section")," available."),Object(r.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(r.b)("p",null,"Congrats! You have migrated from Heroku to AWS. Feel free to check out our ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"forum")," and open a thread if you have any question."))}m.isMDXComponent=!0},421:function(e,t,a){"use strict";a(423);var o=a(0),n=a.n(o),r=a(420),l=a.n(r);a(132);t.a=function(e){var t=e.children,a=e.classNames,o=e.fill,r=e.icon,i=e.type,c=null;switch(i){case"danger":c="alert-triangle";break;case"success":c="check-circle";break;case"warning":c="alert-triangle";break;default:c="info"}return n.a.createElement("div",{className:l()(a,"alert","alert--"+i,{"alert--fill":o,"alert--icon":!1!==r}),role:"alert"},!1!==r&&n.a.createElement("i",{className:l()("feather","icon-"+(r||c))}),t)}},425:function(e,t,a){var o=a(28).f,n=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in n||a(10)&&o(n,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var o=a(0),n=a.n(o),r=a(421);t.a=function(e){var t=e.children,a=e.name;return n.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},434:function(e,t,a){"use strict";var o=a(1),n=(a(439),a(436),a(52),a(29),a(22),a(21),a(0)),r=a.n(n),l=a(446),i=a(420),c=a.n(i),b=a(428),u=a.n(b),s=a(445),p=37,d=39;function m(e){var t=e.block,a=e.centered,o=e.changeSelectedValue,n=e.className,l=e.handleKeydown,i=e.style,b=e.values,u=e.selectedValue,s=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:c()("tabs",n,{"tabs--block":t}),style:i},b.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":u===t,className:c()("tab-item",{"tab-item--active":u===t}),key:t,ref:function(e){return s.push(e)},onKeyDown:function(e){return l(s,e.target,e)},onFocus:function(){return o(t)},onClick:function(){return o(t)}},a)}))))}function h(e){var t=e.placeholder,a=e.selectedValue,o=e.changeSelectedValue,n=e.size,i=e.values,c=i;if(c[0].group){var b=_.groupBy(c,"group");c=Object.keys(b).map((function(e){return{label:e,options:b[e]}}))}return r.a.createElement(l.a,{className:"react-select-container react-select--"+n,classNamePrefix:"react-select",options:c,isClearable:a,placeholder:t,value:i.find((function(e){return e.value==a})),onChange:function(e){return o(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,a=e.defaultValue,l=e.groupId,i=e.label,c=e.placeholder,b=e.select,y=e.size,f=(e.style,e.values),O=e.urlKey,j=Object(s.a)(),g=j.tabGroupChoices,v=j.setTabGroupChoices,w=Object(n.useState)(a),k=w[0],N=w[1];if(null!=l){var T=g[l];null!=T&&T!==k&&N(T)}var C=function(e){N(e),null!=l&&v(l,e)},D=[],A=function(e,t,a){switch(a.keyCode){case d:!function(e,t){var a=e.indexOf(t)+1;e[a]?e[a].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var a=e.indexOf(t)-1;e[a]?e[a].focus():e[e.length-1].focus()}(e,t)}};return Object(n.useEffect)((function(){if("undefined"!=typeof window&&window.location&&O){var e=u.a.parse(window.location.search);e[O]&&N(e[O])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(y||"md")},i&&r.a.createElement("div",{className:"margin-vert--sm"},i),f.length>1&&(b?r.a.createElement(h,Object(o.a)({changeSelectedValue:C,handleKeydown:A,placeholder:c,selectedValue:k,size:y,tabRefs:D},e)):r.a.createElement(m,Object(o.a)({changeSelectedValue:C,handleKeydown:A,selectedValue:k,tabRefs:D},e)))),n.Children.toArray(t).filter((function(e){return e.props.value===k}))[0])}},441:function(e,t,a){"use strict";var o=a(0),n=a.n(o);t.a=function(e){return n.a.createElement(n.a.Fragment,null,e.children)}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[124],{275:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return u})),a.d(t,"metadata",(function(){return s})),a.d(t,"rightToc",(function(){return p})),a.d(t,"default",(function(){return m}));var o=a(1),n=a(9),r=(a(0),a(425)),l=a(424),i=a(444),c=a(437),b=a(429),u={last_modified_on:"2023-05-29",$schema:"/.meta/.schemas/guides.json",title:"Migrate your application from Heroku to AWS",description:"Guide on how to migrate all your applications from Heroku to AWS with your databases",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Migrate your application from Heroku to AWS",description:"Guide on how to migrate all your applications from Heroku to AWS with your databases",permalink:"/guides/tutorial/migrate-your-application-from-heroku-to-aws",readingTime:"13 min read",source:"@site/guides/tutorial/migrate-your-application-from-heroku-to-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Migrate your application from Heroku to AWS",truncated:!1,prevItem:{title:"Microservices",permalink:"/guides/advanced/microservices"},nextItem:{title:"Migration",permalink:"/guides/advanced/migration"}},p=[{value:"Migration Steps",id:"migration-steps",children:[]},{value:"1. Create your Dockerfile or Use Buildpacks",id:"1-create-your-dockerfile-or-use-buildpacks",children:[{value:"Choose your Dockerfile template",id:"choose-your-dockerfile-template",children:[]},{value:"Test your Dockerfile",id:"test-your-dockerfile",children:[]},{value:"Environment variables at the build time",id:"environment-variables-at-the-build-time",children:[]},{value:"Add your Dockerfile to Git",id:"add-your-dockerfile-to-git",children:[]},{value:"Loop",id:"loop",children:[]},{value:"Limitations",id:"limitations",children:[]}]},{value:"2. Create resources on Qovery",id:"2-create-resources-on-qovery",children:[{value:"Application",id:"application",children:[]},{value:"Database",id:"database",children:[]}]},{value:"3. Configure your Environment Variables and Secrets",id:"3-configure-your-environment-variables-and-secrets",children:[{value:"Connect your frontend app to your backend app",id:"connect-your-frontend-app-to-your-backend-app",children:[]},{value:"Connect your backend app to your database",id:"connect-your-backend-app-to-your-database",children:[]}]},{value:"4. Copy data from your Heroku databases to your AWS databases",id:"4-copy-data-from-your-heroku-databases-to-your-aws-databases",children:[]},{value:"5. Deploy your apps!",id:"5-deploy-your-apps",children:[]},{value:"FAQ by Heroku users",id:"faq-by-heroku-users",children:[{value:"How to create a custom domain?",id:"how-to-create-a-custom-domain",children:[]},{value:"How to monitor my apps?",id:"how-to-monitor-my-apps",children:[]},{value:"Do you have Heroku "Review App" equivalent?",id:"do-you-have-heroku-review-app-equivalent",children:[]},{value:"How to rollback?",id:"how-to-rollback",children:[]},{value:"How auto-scaling works?",id:"how-auto-scaling-works",children:[]},{value:"How to manage database migration?",id:"how-to-manage-database-migration",children:[]},{value:"Is it possible to get a shell / connect to my app?",id:"is-it-possible-to-get-a-shell--connect-to-my-app",children:[]},{value:"Can I use Terraform and Infrastructure as Code?",id:"can-i-use-terraform-and-infrastructure-as-code",children:[]},{value:"How can I connect my app to MongoDB Atlas?",id:"how-can-i-connect-my-app-to-mongodb-atlas",children:[]},{value:"How can I connect my app to an AWS service not managed by Qovery?",id:"how-can-i-connect-my-app-to-an-aws-service-not-managed-by-qovery",children:[]}]},{value:"Wrapping up",id:"wrapping-up",children:[]}],d={rightToc:p};function m(e){var t=e.components,a=Object(n.a)(e,["components"]);return Object(r.b)("wrapper",Object(o.a)({},d,a,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"This guide describes how to migrate your application running on Heroku to AWS with Qovery. It covers all required steps you need to take to deploy your application on AWS and transfer your data from Heroku Postgres to the database managed by AWS via Qovery."),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Please contact us via ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum")," if you experience any problem while migrating from Heroku to AWS with Qovery.")),Object(r.b)(b.a,{name:"guide",mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You are familiar with Heroku basics, have a Heroku account and access to Heroku CLI"),Object(r.b)("li",{parentName:"ul"},"You have ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"https://start.qovery.com"}),"sign in on Qovery")),Object(r.b)("li",{parentName:"ul"},"You have ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/cloud-provider/guide-amazon-web-services/"}),"set up your AWS account")," with Qovery"))),Object(r.b)("h2",{id:"migration-steps"},"Migration Steps"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#1-create-your-dockerfile-or-use-buildpacks"}),"Use Buildpacks or Create your Dockerfile")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#2-create-resources-on-qovery"}),"Create resources on Qovery")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#3-configure-your-environment-variables-and-secrets"}),"Configure Environment Variables and Secrets")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#4-copy-data-from-your-heroku-databases-to-your-aws-databases"}),"Copy data from your Heroku databases to your AWS databases")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#5-deploy-your-apps-"}),"Deploy your apps")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"#faq-by-heroku-users"}),"FAQ by Heroku users"))),Object(r.b)("h2",{id:"1-create-your-dockerfile-or-use-buildpacks"},"1. Create your Dockerfile or Use Buildpacks"),Object(r.b)("p",null,"Qovery supports two ways to build and run your application coming from Heroku:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Buildpacks"),Object(r.b)("li",{parentName:"ol"},"Docker")),Object(r.b)("p",null,"Both options build a container image that is runnable by a container engine (E.g. Docker). Qovery runs containers on Kubernetes."),Object(r.b)("p",null,"Choose the option that better fits you:"),Object(r.b)(c.a,{centered:!0,className:"rounded",defaultValue:"buildpacks",placeholder:"Use Buildpacks or Create your Dockerfile",select:!1,size:null,values:[{group:"Platforms",label:"Use Buildpacks",value:"buildpacks"},{group:"Platforms",label:"Create your Dockerfile",value:"dockerfile"}],mdxType:"Tabs"},Object(r.b)(i.a,{value:"dockerfile",mdxType:"TabItem"},Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},"Are you familiar with Dockerfile? If not, I do recommend reading ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/how-to-write-a-dockerfile/"}),"this article"),".")),Object(r.b)("p",null,"Here we will create our Dockerfiles to build and run our applications. Qovery will handle the build and the run of your applications, but need to have at least a Dockerfile to do it."),Object(r.b)("h3",{id:"choose-your-dockerfile-template"},"Choose your Dockerfile template"),Object(r.b)("p",null,"To get started,"),Object(r.b)("h4",{id:"find-dockerfile-template"},"Find Dockerfile template"),Object(r.b)("p",null,"Pick one Dockerfile template according to the programming language or framework you are using for your app:"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Your framework or language is missing? Open a thread on ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"our forum"),", and we will provide you one.")),Object(r.b)(c.a,{centered:!1,className:"square",defaultValue:"rails",select:!1,size:null,values:[{group:"Files",label:"Rails",value:"rails"},{group:"Files",label:"NodeJS",value:"nodejs"},{group:"Files",label:"React",value:"react"},{group:"Files",label:"VueJS",value:"vuejs"},{group:"Files",label:"NextJS",value:"nextjs"},{group:"Files",label:"Golang",value:"golang"},{group:"Files",label:"Flask",value:"flask"},{group:"Files",label:"Django",value:"django"},{group:"Files",label:"Laravel",value:"laravel"},{group:"Files",label:"Symfony",value:"symfony"},{group:"Files",label:"Spring",value:"spring"},{group:"Files",label:"Rust",value:"rust"}],mdxType:"Tabs"},Object(r.b)(i.a,{value:"rails",mdxType:"TabItem"},Object(r.b)("p",null,"Here is the Dockerfile for your Rails application listening on the PORT 3000"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Dockerfile"',title:'"Dockerfile"'}),'# syntax=docker/dockerfile:1\nFROM ruby:2.7\nRUN apt-get update -qq && apt-get install -y nodejs postgresql-client\nWORKDIR /myapp\nCOPY Gemfile Gemfile\nCOPY Gemfile.lock Gemfile.lock\nRUN bundle install\n\nCOPY . .\n\nEXPOSE 3000\n\n# Configure the main process to run when running the image\nCMD ["rails", "server", "-b", "0.0.0.0", "-p", "3000"]\n')),Object(r.b)("details",null,Object(r.b)("summary",null,"Dockerfile for Sidekiq"),Object(r.b)("p",null,"Here is the Dockerfile for your Rails app running as a worker mode with Sidekiq."),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"There is no listening port since it is consuming resources from a queuing system (E.g. Redis)")),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Dockerfile for Sidekiq"',title:'"Dockerfile',for:!0,'Sidekiq"':!0}),'# syntax=docker/dockerfile:1\nFROM ruby:2.7\nRUN apt-get update -qq && apt-get install -y nodejs postgresql-client # add mysql client if you need to\nWORKDIR /myapp\nCOPY Gemfile Gemfile\nCOPY Gemfile.lock Gemfile.lock\nRUN bundle install\n\nCOPY . .\n\nCMD ["bundle", "exec", "sidekiq"]\n')))),Object(r.b)(i.a,{value:"nodejs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"react",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"vuejs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"nextjs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"golang",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"flask",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"django",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"laravel",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"symfony",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"spring",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n"))),Object(r.b)(i.a,{value:"rust",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"\nTODO\n\n")))),Object(r.b)("h4",{id:"copy-template"},"Copy template"),Object(r.b)("p",null,"Copy your Dockerfile at the root of your project. By convention, you can name your file ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile"),". If you already have a Dockerfile, feel free to name it ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile.qovery"),". If you are using multiple Dockerfile for Qovery, feel free to give a name like ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile-sidekiq.qovery"),"."),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Read ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/t/904"}),"this forum post")," to know how to use the same Dockerfile with different CMD parameters.")),Object(r.b)("p",null,"For our example of migrating a Rails app and a Rails Sidekiq app, I will have at the root of my project a ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile.qovery")," and a ",Object(r.b)("inlineCode",{parentName:"p"},"Dockerfile-sidekiq.qovery"),"."),Object(r.b)("h3",{id:"test-your-dockerfile"},"Test your Dockerfile"),Object(r.b)(b.a,{mdxType:"Assumptions"},Object(r.b)("p",null,"You need to ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.docker.com/get-docker/"}),"install Docker")," to test your Dockerfile")),Object(r.b)("p",null,"To test your Dockerfile we will locally our container. You just need to run the following commands:"),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Don't forget the ",Object(r.b)("inlineCode",{parentName:"p"},".")," (dot) at the end of the ",Object(r.b)("inlineCode",{parentName:"p"},"docker build")," command.")),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"docker build -f Dockerfile.qovery .\n")),Object(r.b)("p",null,"If everything goes well you should get the finale image ID at the end of the output."),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"[+] Building 19.0s (16/16) FINISHED\n => [internal] load build definition from Dockerfile 0.0s\n => => transferring dockerfile: 37B 0.0s\n => [internal] load .dockerignore 0.0s\n ...\n => [7/7] COPY . . 0.2s\n => exporting to image 0.0s\n => exporting layers 0.4s\n => writing image sha256:a0f90a6ec8bc4036a7b268479a0c0773ca324ba2de11fdef31309650743f4055 0.0s\n")),Object(r.b)("p",null,"To run your image you can run:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"docker run a0f90a6ec8bc4036a7b268479a0c0773ca324ba2de11fdef31309650743f4055\n")),Object(r.b)("p",null,"If your app required a database to starts, then it can be normal that it fails to start. Otherwise, if your app is supposed to start and does not, then you will need to fix the issue and rebuild your app with ",Object(r.b)("inlineCode",{parentName:"p"},"docker build -f Dockerfile.qovery .")),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"This step is one of the most complex, but once you successfully build your application with Docker, your app will run anywhere (not only on AWS with Qovery).")),Object(r.b)("p",null,"Any error while building your container image? 2 solutions:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},'Read the error message and try to understand from where the problem is coming from. You can "Google" the error if it is not related to your code.'),Object(r.b)("li",{parentName:"ol"},"Open a thread on ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"https://discuss.qovery.com/"}),"our forum")," if you don't find the answer there, we will be happy to assist you.")),Object(r.b)("h3",{id:"environment-variables-at-the-build-time"},"Environment variables at the build time"),Object(r.b)("p",null,"Does your app use some environment variables at the build time? Then you will need to modify your Dockerfile to includes the environment variables. Let's imagine your app uses the environment variable ",Object(r.b)("inlineCode",{parentName:"p"},"CONTENT_API_KEY"),", then you will need to add the following instructions in your Dockerfile:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Dockerfile with environment variables"',title:'"Dockerfile',with:!0,environment:!0,'variables"':!0}),"...\nARG CONTENT_API_KEY\nENV CONTENT_API_KEY $CONTENT_API_KEY\n...\n")),Object(r.b)("p",null,"The value of the ",Object(r.b)("inlineCode",{parentName:"p"},"CONTENT_API_KEY")," environment variable will be taken from the specified environment variables in Qovery."),Object(r.b)(l.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Qovery injects Environment Variables and Secrets at the build and run time of your app.")),Object(r.b)("h3",{id:"add-your-dockerfile-to-git"},"Add your Dockerfile to Git"),Object(r.b)("p",null,"Now, add your new Dockerfile to git with the following commands:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),'git add Dockerfile.qovery\ngit commit -m "Add Qovery Dockerfile"\ngit push origin\n')),Object(r.b)("h3",{id:"loop"},"Loop"),Object(r.b)("p",null,"If you have multiple applications to deploy, create a Dockerfile for each of them.")),Object(r.b)(i.a,{value:"buildpacks",mdxType:"TabItem"},Object(r.b)("p",null,Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://buildpacks.io/"}),"Buildpacks")," automatically detects the language and the framework your application is using. Buildpacks builds and runs your app. Here is the list of ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#option-1-buildpacks"}),"supported languages and frameworks"),"."),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"We do recommend using Docker to keep the full control of what's going on behind the scene. Buildpacks is a great technology but difficult to debug when something goes wrong. You can try deploying your apps on AWS with Qovery with Buildpacks, if you do not succeed, we do recommend switching for Docker.")),Object(r.b)("h3",{id:"limitations"},"Limitations"),Object(r.b)("p",null,"Here are some limitations due to our Buildpacks implementation:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Qovery Buildpacks does not support Procfile with multiple commands at the moment."),Object(r.b)("li",{parentName:"ul"},"Qovery does not support custom Buildpacks.")),Object(r.b)("p",null,"Those limitations will be solved in the coming months."))),Object(r.b)("h2",{id:"2-create-resources-on-qovery"},"2. Create resources on Qovery"),Object(r.b)("h3",{id:"application"},"Application"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Are you a new Qovery user? Watch ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"this tutorial")," to learn how to deploy your first app.")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/9246ae68c68f42debc3d5183d2b4f7f8",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Steps:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Connect to the ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"https://start.qovery.com"}),"Qovery console"),"."),Object(r.b)("li",{parentName:"ol"},"Create your ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization")," and your ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/project/"}),"Project"),"."),Object(r.b)("li",{parentName:"ol"},"Create an environment with the name ",Object(r.b)("inlineCode",{parentName:"li"},"production")," (it can be changed after)."),Object(r.b)("li",{parentName:"ol"},"Create an application and give it a name (you can give the name of your repo if you have no idea)"),Object(r.b)("li",{parentName:"ol"},"Select your app repository from your GitHub, GitLab or Bitbucket."),Object(r.b)("li",{parentName:"ol"},"Select the branch you want to deploy."),Object(r.b)("li",{parentName:"ol"},"Select the Build mode for ",Object(r.b)("inlineCode",{parentName:"li"},"Buildpacks")," or ",Object(r.b)("inlineCode",{parentName:"li"},"Dockerfile")," according to what you want."),Object(r.b)("li",{parentName:"ol"},"Specify the local listening port of your application."),Object(r.b)("li",{parentName:"ol"},'Click on "create"')),Object(r.b)("p",null,"Congrats! Your application is created \ud83c\udf89"),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,'Your application is created but not deployed yet! You can configure the vCPU, Memory, Environment Variables... before deploying it. If you want to deploy it before finishing the configuration you can click on "Actions" > "Deploy".')),Object(r.b)("p",null,"If you deploy an app from a mono-repository, we have a must-read guide for you ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/advanced/monorepository/"}),"here"),"."),Object(r.b)("h3",{id:"database"},"Database"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Are you a new Qovery user? Watch ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"this tutorial")," to learn how to deploy your database.")),Object(r.b)("p",null,"Here are the steps to deploy your database:"),Object(r.b)(b.a,{mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have created an application before"))),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/d7e10be0e5964f6799b158dc631bbbd1",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Steps:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Go to your ",Object(r.b)("inlineCode",{parentName:"li"},"production")," environment."),Object(r.b)("li",{parentName:"ol"},'Add your database by clicking on "Add" > "Database".'),Object(r.b)("li",{parentName:"ol"},"Select the database (PostgreSQL, MySQL, MongoDB, Redis..) and the version you want to deploy."),Object(r.b)("li",{parentName:"ol"},"Select ",Object(r.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/database/#general"}),"Managed or Container mode")," for your database."),Object(r.b)("li",{parentName:"ol"},"Select ",Object(r.b)("inlineCode",{parentName:"li"},"Public")," accessibility (set ",Object(r.b)("inlineCode",{parentName:"li"},"Private")," if you don't want to restore your data from an existing Heroku database).")),Object(r.b)("p",null,"Congrats! Your database is created as well \ud83c\udf89"),Object(r.b)("p",null,"If you use MongoDB Atlas, or an existing database on AWS that you want to connect to your application deployed by Qovery. Check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"our tutorial about VPC peering")," and how to securely connect to your existing database."),Object(r.b)("h2",{id:"3-configure-your-environment-variables-and-secrets"},"3. Configure your Environment Variables and Secrets"),Object(r.b)(l.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Qovery supports Doppler integration - it's the easiest way to migrate your Environment Variables and Secrets from Heroku to Qovery. ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/secret-manager/doppler/"}),"More info here"),".")),Object(r.b)("p",null,"Qovery makes the difference between an environment variable and a secret. Basically, a Secret is similar to an Environment Variable but the value is encrypted and can't be revealed. Both are injected as environment variables during the build and the run of your applications. ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"More info here")),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"I recommend reading our ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/managing-environment-variables/"}),"Getting Started with Environment Variables")," guide.")),Object(r.b)("p",null,"To extract your environment variables from Heroku, we recommend using the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://devcenter.heroku.com/articles/heroku-cli"}),"Heroku CLI")," and exporting all the environment variables and secrets in an .env (dot env) file. Qovery supports the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli/"}),"import of a dot env file")," via the Qovery web interface and the Qovery CLI."),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"If you use Buildpacks for one of your app AND you have indicated a local listening port of your application, you will need to add an environment variable ",Object(r.b)("inlineCode",{parentName:"p"},"PORT")," with the value of your port to make your application starting properly. Otherwise, Qovery will fail to deploy your app!")),Object(r.b)("p",null,Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://devcenter.heroku.com/articles/config-vars#view-current-config-var-values"}),"Export your environment variable via the Heroku CLI")," with the command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell"}),"# To install Heroku CLI: https://devcenter.heroku.com/articles/heroku-cli\nheroku config\n\nGREETINGS: hello world\nSTRIPE_API_KEY: xxx-yyy-zzz\nIS_PRODUCTION: true\n")),Object(r.b)("p",null,"Then you can create your environment variables via the web interface (watch the video below)"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/50899d7fa3d84a418f0db69f54f970d3",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Or via the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI"),":"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Import Heroku environment variables with the Qovery CLI"',title:'"Import',Heroku:!0,environment:!0,variables:!0,with:!0,the:!0,Qovery:!0,'CLI"':!0}),"# auth yourself\nqovery auth\n\n# selection the app where you want to import your environment variables\nqovery context set\n\n# import your Heroku environment variables\nheroku config --app --json | \\\n qovery env parse --heroku-json > heroku.env && \\\n qovery env import heroku.env && \\\n rm heroku.env\n\nQovery: dot env file to import: 'heroku.env'\n? Do you want to import Environment Variables or Secrets? Environment Variables\n? What environment variables do you want to import? [Use arrows to move, space to select, to all, to none, type to filter]\n [x] GREETINGS=hello world\n [ ] STRIPE_API_KEY=xxx-yyy-zzz\n> [x] IS_PRODUCTION=true\n\nQovery: \u2705 Environment Variables successfully imported!\n")),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Import sensitive data (E.g. API keys, credentials...) as ",Object(r.b)("inlineCode",{parentName:"p"},"Secret")," and not ",Object(r.b)("inlineCode",{parentName:"p"},"Environment Variable"),".")),Object(r.b)("h3",{id:"connect-your-frontend-app-to-your-backend-app"},"Connect your frontend app to your backend app"),Object(r.b)("p",null,"To connect your frontend app your backend app we will create an ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#alias-environment-variable"}),"environment variable alias"),"."),Object(r.b)("p",null,"Here is how to create a frontend app:"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/bafbbda93bd64d04afb3189bf4a1a201",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"And now how to connect your frontend app with your backend app:"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/f820925f2175465f9271b97ef414bb42",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"You can also take a look at ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/t/918"}),"this forum reply")," to learn how to do it."),Object(r.b)("h3",{id:"connect-your-backend-app-to-your-database"},"Connect your backend app to your database"),Object(r.b)("p",null,"Same as connecting your frontend app to your backend app, you can create an environment variable alias ",Object(r.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," for the ",Object(r.b)("em",{parentName:"p"},"built-in")," secret finishing with ",Object(r.b)("inlineCode",{parentName:"p"},"_DATABASE_URL_INTERNAL"),"."),Object(r.b)(l.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Create an alias on ",Object(r.b)("inlineCode",{parentName:"p"},"_DATABASE_URL_INTERNAL")," and not ",Object(r.b)("inlineCode",{parentName:"p"},"_DATABASE_URL"))),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/59f8368eb3c14796a807c7e39e9c0ab0",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"4-copy-data-from-your-heroku-databases-to-your-aws-databases"},"4. Copy data from your Heroku databases to your AWS databases"),Object(r.b)("p",null,Object(r.b)("em",{parentName:"p"},"Coming soon with ",Object(r.b)("a",Object(o.a)({parentName:"em"},{href:"https://www.replibyte.com"}),"Replibyte"))),Object(r.b)("h2",{id:"5-deploy-your-apps"},"5. Deploy your apps!"),Object(r.b)("p",null,"We are finally ready to deploy my applications on AWS!"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/0589d2f2aa4149edb605dc23f4efd23d",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("p",null,"Watch the final result \ud83d\ude0e"),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/da31c21f9c104eae9270e4c4db59055e",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h2",{id:"faq-by-heroku-users"},"FAQ by Heroku users"),Object(r.b)("h3",{id:"how-to-create-a-custom-domain"},"How to create a custom domain?"),Object(r.b)("p",null,"Check out the documentation on ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/getting-started/setting-custom-domain/"}),"how to configure your custom domain"),"."),Object(r.b)("h3",{id:"how-to-monitor-my-apps"},"How to monitor my apps?"),Object(r.b)("p",null,"We do recommend using ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://www.datadoghq.com"}),"Datadog")," or any other monitoring products for monitoring your apps deployed by Qovery. Check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/"}),"our tutorial on how to install Datadog"),"."),Object(r.b)("h3",{id:"do-you-have-heroku-review-app-equivalent"},'Do you have Heroku "Review App" equivalent?'),Object(r.b)("p",null,"Yes, it's what we call ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#preview-environment"}),"Preview Environment")),Object(r.b)("h3",{id:"how-to-rollback"},"How to rollback?"),Object(r.b)("p",null,"Check out the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deployment-actions/#deploy-other-version"}),"app rollback documentation")),Object(r.b)("h3",{id:"how-auto-scaling-works"},"How auto-scaling works?"),Object(r.b)("p",null,"Check out the ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#auto-scaling"}),"app auto-scaling documentation")),Object(r.b)("h3",{id:"how-to-manage-database-migration"},"How to manage database migration?"),Object(r.b)("p",null,"Check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/t/951"}),"our forum reply")),Object(r.b)("h3",{id:"is-it-possible-to-get-a-shell--connect-to-my-app"},"Is it possible to get a shell / connect to my app?"),Object(r.b)("p",null,"Yes, with the Qovery CLI and the command ",Object(r.b)("inlineCode",{parentName:"p"},"qovery shell"),". ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#shell"}),"Check out the documentation"),"."),Object(r.b)("h3",{id:"can-i-use-terraform-and-infrastructure-as-code"},"Can I use Terraform and Infrastructure as Code?"),Object(r.b)("p",null,"Absolutely, we have a ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"Qovery Terraform provider")," available."),Object(r.b)("h3",{id:"how-can-i-connect-my-app-to-mongodb-atlas"},"How can I connect my app to MongoDB Atlas?"),Object(r.b)("p",null,"If you use MongoDB Atlas check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"our tutorial about VPC peering")," and how to securely connect to your existing MongoDB Atlas database."),Object(r.b)("h3",{id:"how-can-i-connect-my-app-to-an-aws-service-not-managed-by-qovery"},"How can I connect my app to an AWS service not managed by Qovery?"),Object(r.b)("p",null,"If you want to connect your app to an AWS service not managed by Qovery, check out ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"our tutorial about VPC peering")," and how to securely connect to this AWS service."),Object(r.b)("hr",null),Object(r.b)("p",null,"If you have a common question about Qovery, we have a more general ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/useful-resources/faq/"}),"FAQ section")," available."),Object(r.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(r.b)("p",null,"Congrats! You have migrated from Heroku to AWS. Feel free to check out our ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"forum")," and open a thread if you have any question."))}m.isMDXComponent=!0},424:function(e,t,a){"use strict";a(426);var o=a(0),n=a.n(o),r=a(423),l=a.n(r);a(132);t.a=function(e){var t=e.children,a=e.classNames,o=e.fill,r=e.icon,i=e.type,c=null;switch(i){case"danger":c="alert-triangle";break;case"success":c="check-circle";break;case"warning":c="alert-triangle";break;default:c="info"}return n.a.createElement("div",{className:l()(a,"alert","alert--"+i,{"alert--fill":o,"alert--icon":!1!==r}),role:"alert"},!1!==r&&n.a.createElement("i",{className:l()("feather","icon-"+(r||c))}),t)}},428:function(e,t,a){var o=a(28).f,n=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in n||a(10)&&o(n,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var o=a(0),n=a.n(o),r=a(424);t.a=function(e){var t=e.children,a=e.name;return n.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},437:function(e,t,a){"use strict";var o=a(1),n=(a(442),a(439),a(52),a(29),a(22),a(21),a(0)),r=a.n(n),l=a(449),i=a(423),c=a.n(i),b=a(433),u=a.n(b),s=a(448),p=37,d=39;function m(e){var t=e.block,a=e.centered,o=e.changeSelectedValue,n=e.className,l=e.handleKeydown,i=e.style,b=e.values,u=e.selectedValue,s=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:c()("tabs",n,{"tabs--block":t}),style:i},b.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":u===t,className:c()("tab-item",{"tab-item--active":u===t}),key:t,ref:function(e){return s.push(e)},onKeyDown:function(e){return l(s,e.target,e)},onFocus:function(){return o(t)},onClick:function(){return o(t)}},a)}))))}function h(e){var t=e.placeholder,a=e.selectedValue,o=e.changeSelectedValue,n=e.size,i=e.values,c=i;if(c[0].group){var b=_.groupBy(c,"group");c=Object.keys(b).map((function(e){return{label:e,options:b[e]}}))}return r.a.createElement(l.a,{className:"react-select-container react-select--"+n,classNamePrefix:"react-select",options:c,isClearable:a,placeholder:t,value:i.find((function(e){return e.value==a})),onChange:function(e){return o(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,a=e.defaultValue,l=e.groupId,i=e.label,c=e.placeholder,b=e.select,y=e.size,f=(e.style,e.values),O=e.urlKey,j=Object(s.a)(),g=j.tabGroupChoices,v=j.setTabGroupChoices,w=Object(n.useState)(a),k=w[0],N=w[1];if(null!=l){var T=g[l];null!=T&&T!==k&&N(T)}var C=function(e){N(e),null!=l&&v(l,e)},D=[],A=function(e,t,a){switch(a.keyCode){case d:!function(e,t){var a=e.indexOf(t)+1;e[a]?e[a].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var a=e.indexOf(t)-1;e[a]?e[a].focus():e[e.length-1].focus()}(e,t)}};return Object(n.useEffect)((function(){if("undefined"!=typeof window&&window.location&&O){var e=u.a.parse(window.location.search);e[O]&&N(e[O])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(y||"md")},i&&r.a.createElement("div",{className:"margin-vert--sm"},i),f.length>1&&(b?r.a.createElement(h,Object(o.a)({changeSelectedValue:C,handleKeydown:A,placeholder:c,selectedValue:k,size:y,tabRefs:D},e)):r.a.createElement(m,Object(o.a)({changeSelectedValue:C,handleKeydown:A,selectedValue:k,tabRefs:D},e)))),n.Children.toArray(t).filter((function(e){return e.props.value===k}))[0])}},444:function(e,t,a){"use strict";var o=a(0),n=a.n(o);t.a=function(e){return n.a.createElement(n.a.Fragment,null,e.children)}}}]); \ No newline at end of file diff --git a/6ebd4d49.0e8b4f4e.js b/6ebd4d49.388e1fe5.js similarity index 92% rename from 6ebd4d49.0e8b4f4e.js rename to 6ebd4d49.388e1fe5.js index d94df3ad2a..947eec2365 100644 --- a/6ebd4d49.0e8b4f4e.js +++ b/6ebd4d49.388e1fe5.js @@ -1,2 +1,2 @@ -/*! For license information please see 6ebd4d49.0e8b4f4e.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[123],{274:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var o=n(1),i=n(9),a=(n(0),n(422)),r=(n(429),n(421)),l=(n(426),{last_modified_on:"2023-11-29",title:"Logs",description:"Learn how to access the logs of your environment and services"}),c={id:"using-qovery/deployment/logs",title:"Logs",description:"Learn how to access the logs of your environment and services",source:"@site/docs/using-qovery/deployment/logs.md",permalink:"/docs/using-qovery/deployment/logs",sidebar:"docs",previous:{title:"Running and Deployment Statuses",permalink:"/docs/using-qovery/deployment/running-and-deployment-statuses"},next:{title:"Deployment Strategies",permalink:"/docs/using-qovery/deployment/deployment-strategies"}},s=[{value:"How to access the logs",id:"how-to-access-the-logs",children:[]},{value:"Navigation Panel",id:"navigation-panel",children:[]},{value:"Log section",id:"log-section",children:[{value:"Deployment Logs",id:"deployment-logs",children:[]},{value:"Live Logs",id:"live-logs",children:[]}]}],u={rightToc:s};function p(e){var t=e.components,n=Object(i.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"The Logs interface allows you to access:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("strong",{parentName:"li"},"The deployment logs"),": every time a deployment is triggered, Qovery provides you with the log of its execution and as well with any error that might occur."),Object(a.b)("li",{parentName:"ul"},Object(a.b)("strong",{parentName:"li"},"The live logs")," of your applications: Qovery allows you to retrieve the logs of your application in real-time, streamed directly from your remote application (no data is stored on Qovery side). The logs are accessible as long as the application is running and writing the logs in the ",Object(a.b)("inlineCode",{parentName:"li"},"stdout"),".")),Object(a.b)("h2",{id:"how-to-access-the-logs"},"How to access the logs"),Object(a.b)("p",null,"The ",Object(a.b)("inlineCode",{parentName:"p"},"Logs")," interface can be accessed from the console by clicking on the ",Object(a.b)("inlineCode",{parentName:"p"},"parchment")," icon available in the header or within the table"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/access_logs.png",alt:"Log access"})),Object(a.b)("p",null,"The interface is composed of two sections:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"A ",Object(a.b)("strong",{parentName:"li"},"navigation panel")," (on the left)"),Object(a.b)("li",{parentName:"ul"},"A ",Object(a.b)("strong",{parentName:"li"},"log section")," allowing you to switch between the deployment logs and the live logs of a service.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/logs_view.png",alt:"Log View"})),Object(a.b)("h2",{id:"navigation-panel"},"Navigation Panel"),Object(a.b)("p",null,"This section provides you with some information on the last ",Object(a.b)("inlineCode",{parentName:"p"},"Deployment")," that happened on the environment and a navigation system to access the logs of each service of your environment. "),Object(a.b)("p",null,"More in detail you will find here:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Deployment information (top section): this section shows you the status of the deployment execution and when it happened. If a deployment is ongoing, its status will be updated accordingly in this section. "),Object(a.b)("li",{parentName:"ul"},"Pipeline view: this section provides an overall view of the current configuration of the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deployment-pipeline/"}),"Deployment Pipeline")," and each service present within the environment. By default, only the services that have been deployed within the last deployment execution are displayed but you can still display all of them by un-ticking the option ",Object(a.b)("inlineCode",{parentName:"li"},"Last deployed only"),". ")),Object(a.b)("h2",{id:"log-section"},"Log section"),Object(a.b)("p",null,"This section allows you to access the ",Object(a.b)("inlineCode",{parentName:"p"},"Deployment Logs")," and the ",Object(a.b)("inlineCode",{parentName:"p"},"Live logs")," of each service."),Object(a.b)("h3",{id:"deployment-logs"},"Deployment Logs"),Object(a.b)("p",null,"This tab shows you the deployment logs for each service of the environment. By default, you get access to the logs of the last deployment execution but you can switch to the previous execution (See ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"#accessing-old-deployment-logs"}),"Accessing old deployment logs"),")."),Object(a.b)("p",null,"If the service is built via the Qovery CI pipeline, you will get access to the build logs."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/build_logs.png",alt:"Build Logs"})),Object(a.b)("p",null,"When the deployment on Kubernetes is executed, the system will provide you with the deployment status updates. In case of deployment issues, these updates will provide you with some information on the root cause."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/deployment_status_update.png",alt:"Deployment Status Update"})),Object(a.b)("p",null,"At the end of the deployment, a final message is emitted confirming if the deployment was successful or not and, in case of an issue, it provides you with some information on how to solve the issue. "),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/log_content.png",alt:"Log content"})),Object(a.b)("p",null,"You can use the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/troubleshoot/"}),"Troubleshoot section")," to investigate any issue you might encounter during the deployment of your services."),Object(a.b)("h4",{id:"accessing-old-deployment-logs"},"Accessing old deployment logs"),Object(a.b)("p",null,"You can access the logs of a past deployment execution in two ways:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"using the ",Object(a.b)("inlineCode",{parentName:"li"},"Deployment log switch")," on the logs view")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/deployment_switch.png",alt:"Deployment Log Switch"})),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"from the ",Object(a.b)("inlineCode",{parentName:"li"},"Deployment")," tab from the service or environment page and clicking on the ",Object(a.b)("inlineCode",{parentName:"li"},"parchment")," icon of a previous deployment")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/deployment_tab_switch.png",alt:"Deployment Tab Switch"})),Object(a.b)(r.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Qovery provides access to the logs of the last 20 deployments executed on your environment. If your service has been deployed more than 20 deployments ago, you won't be able to access its deployment logs.")),Object(a.b)("h3",{id:"live-logs"},"Live Logs"),Object(a.b)("p",null,"The live logs tab gives you a real-time view on the log generated by your application while running remotely on your cloud provider infrastructure. "),Object(a.b)("p",null,"Within this section you will find:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Timestamp: the timestamp of the message"),Object(a.b)("li",{parentName:"ul"},"Pod Name: the name of the kubernetes pod where your application is running (to distinguish the instance in case of the multi-instance app). If you want to follow a specific pod, you can filter the logs by clicking on the pod name"),Object(a.b)("li",{parentName:"ul"},"Version: the commit id or the image tag of the application running on this POD"),Object(a.b)("li",{parentName:"ul"},"Message: the log message")),Object(a.b)("p",null,"Past application logs are also preserved on your cluster via ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://grafana.com/oss/loki/"}),"Loki")," and can be accessed from the same log view within the qovery console. Please keep in mind that:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Loki is configured to preserve only the latest 1000 lines of log for each application and retain them for 12 weeks (configurable via the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cluster-advanced-settings/#logs"}),"cluster advanced settings"),")"),Object(a.b)("li",{parentName:"ul"},"This feature is not available on ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#why-do-i-need-a-cluster"}),"EC2 Clusters")," since we don't install Loki.")),Object(a.b)("p",null,"If you need to troubleshoot issues on the requests managed by your application, you can also access the Nginx logs in the same view (logs format is available in the helper). Note that this option is available only if the application is exposed publicly (See the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#ports"}),"Port Section"),")"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/live_logs.png",alt:"Log content"})))}p.isMDXComponent=!0},420:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function i(){for(var e=[],t=0;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=i.a.createContext({}),u=function(e){var t=i.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},p=function(e){var t=u(e.components);return i.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},m=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,r=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),p=u(n),m=o,d=p["".concat(r,".").concat(m)]||p[m]||b[m]||a;return n?i.a.createElement(d,l({ref:t},s,{components:n})):i.a.createElement(d,l({ref:t},s))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,r=new Array(a);r[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:o,r[1]=l;for(var s=2;s1?arguments[1]:void 0,n),c=r>2?arguments[2]:void 0,s=void 0===c?n:i(c,n);s>l;)t[l++]=e;return t}},425:function(e,t,n){var o=n(28).f,i=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in i||n(10)&&o(i,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var o=n(0),i=n.n(o),a=n(421);t.a=function(e){var t=e.children,n=e.name;return i.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},i.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var o=n(1),i=n(0),a=n.n(i),r=n(39),l=n(430),c=n(20),s=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,u=n||c,p=Object(l.a)(u),b=Object(i.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!m&&p&&window.docusaurus.prefetch(u),function(){m&&t&&t.disconnect()}}),[u,m,p]),u&&p?a.a.createElement(r.b,Object(o.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,o;m&&e&&p&&(n=e,o=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:u})):a.a.createElement("a",Object(o.a)({},e,{href:u}))}},429:function(e,t,n){"use strict";var o=n(0),i=n.n(o),a=n(427),r=n(420),l=n.n(r);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,r=e.leftIcon,c=e.rightIcon,s=e.size,u=e.target,p=e.to,b=l()("jump-to","jump-to--"+s,n),m=i.a.createElement("div",{className:"jump-to--inner"},i.a.createElement("div",{className:"jump-to--inner-2"},r&&i.a.createElement("div",{className:"jump-to--left"},i.a.createElement("i",{className:"feather icon-"+r})),i.a.createElement("div",{className:"jump-to--main"},o?i.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),i.a.createElement("div",{className:"jump-to--right"},i.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return u?i.a.createElement("a",{href:p,target:u,className:b},m):i.a.createElement(a.a,{to:p,className:b},m)}},430:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))}}]); \ No newline at end of file +/*! For license information please see 6ebd4d49.388e1fe5.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[125],{276:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var o=n(1),i=n(9),a=(n(0),n(425)),r=(n(431),n(424)),l=(n(429),{last_modified_on:"2023-11-29",title:"Logs",description:"Learn how to access the logs of your environment and services"}),c={id:"using-qovery/deployment/logs",title:"Logs",description:"Learn how to access the logs of your environment and services",source:"@site/docs/using-qovery/deployment/logs.md",permalink:"/docs/using-qovery/deployment/logs",sidebar:"docs",previous:{title:"Running and Deployment Statuses",permalink:"/docs/using-qovery/deployment/running-and-deployment-statuses"},next:{title:"Deployment Strategies",permalink:"/docs/using-qovery/deployment/deployment-strategies"}},s=[{value:"How to access the logs",id:"how-to-access-the-logs",children:[]},{value:"Navigation Panel",id:"navigation-panel",children:[]},{value:"Log section",id:"log-section",children:[{value:"Deployment Logs",id:"deployment-logs",children:[]},{value:"Live Logs",id:"live-logs",children:[]}]}],u={rightToc:s};function p(e){var t=e.components,n=Object(i.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"The Logs interface allows you to access:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("strong",{parentName:"li"},"The deployment logs"),": every time a deployment is triggered, Qovery provides you with the log of its execution and as well with any error that might occur."),Object(a.b)("li",{parentName:"ul"},Object(a.b)("strong",{parentName:"li"},"The live logs")," of your applications: Qovery allows you to retrieve the logs of your application in real-time, streamed directly from your remote application (no data is stored on Qovery side). The logs are accessible as long as the application is running and writing the logs in the ",Object(a.b)("inlineCode",{parentName:"li"},"stdout"),".")),Object(a.b)("h2",{id:"how-to-access-the-logs"},"How to access the logs"),Object(a.b)("p",null,"The ",Object(a.b)("inlineCode",{parentName:"p"},"Logs")," interface can be accessed from the console by clicking on the ",Object(a.b)("inlineCode",{parentName:"p"},"parchment")," icon available in the header or within the table"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/access_logs.png",alt:"Log access"})),Object(a.b)("p",null,"The interface is composed of two sections:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"A ",Object(a.b)("strong",{parentName:"li"},"navigation panel")," (on the left)"),Object(a.b)("li",{parentName:"ul"},"A ",Object(a.b)("strong",{parentName:"li"},"log section")," allowing you to switch between the deployment logs and the live logs of a service.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/logs_view.png",alt:"Log View"})),Object(a.b)("h2",{id:"navigation-panel"},"Navigation Panel"),Object(a.b)("p",null,"This section provides you with some information on the last ",Object(a.b)("inlineCode",{parentName:"p"},"Deployment")," that happened on the environment and a navigation system to access the logs of each service of your environment. "),Object(a.b)("p",null,"More in detail you will find here:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Deployment information (top section): this section shows you the status of the deployment execution and when it happened. If a deployment is ongoing, its status will be updated accordingly in this section. "),Object(a.b)("li",{parentName:"ul"},"Pipeline view: this section provides an overall view of the current configuration of the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deployment-pipeline/"}),"Deployment Pipeline")," and each service present within the environment. By default, only the services that have been deployed within the last deployment execution are displayed but you can still display all of them by un-ticking the option ",Object(a.b)("inlineCode",{parentName:"li"},"Last deployed only"),". ")),Object(a.b)("h2",{id:"log-section"},"Log section"),Object(a.b)("p",null,"This section allows you to access the ",Object(a.b)("inlineCode",{parentName:"p"},"Deployment Logs")," and the ",Object(a.b)("inlineCode",{parentName:"p"},"Live logs")," of each service."),Object(a.b)("h3",{id:"deployment-logs"},"Deployment Logs"),Object(a.b)("p",null,"This tab shows you the deployment logs for each service of the environment. By default, you get access to the logs of the last deployment execution but you can switch to the previous execution (See ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"#accessing-old-deployment-logs"}),"Accessing old deployment logs"),")."),Object(a.b)("p",null,"If the service is built via the Qovery CI pipeline, you will get access to the build logs."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/build_logs.png",alt:"Build Logs"})),Object(a.b)("p",null,"When the deployment on Kubernetes is executed, the system will provide you with the deployment status updates. In case of deployment issues, these updates will provide you with some information on the root cause."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/deployment_status_update.png",alt:"Deployment Status Update"})),Object(a.b)("p",null,"At the end of the deployment, a final message is emitted confirming if the deployment was successful or not and, in case of an issue, it provides you with some information on how to solve the issue. "),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/log_content.png",alt:"Log content"})),Object(a.b)("p",null,"You can use the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/troubleshoot/"}),"Troubleshoot section")," to investigate any issue you might encounter during the deployment of your services."),Object(a.b)("h4",{id:"accessing-old-deployment-logs"},"Accessing old deployment logs"),Object(a.b)("p",null,"You can access the logs of a past deployment execution in two ways:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"using the ",Object(a.b)("inlineCode",{parentName:"li"},"Deployment log switch")," on the logs view")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/deployment_switch.png",alt:"Deployment Log Switch"})),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"from the ",Object(a.b)("inlineCode",{parentName:"li"},"Deployment")," tab from the service or environment page and clicking on the ",Object(a.b)("inlineCode",{parentName:"li"},"parchment")," icon of a previous deployment")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/deployment_tab_switch.png",alt:"Deployment Tab Switch"})),Object(a.b)(r.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Qovery provides access to the logs of the last 20 deployments executed on your environment. If your service has been deployed more than 20 deployments ago, you won't be able to access its deployment logs.")),Object(a.b)("h3",{id:"live-logs"},"Live Logs"),Object(a.b)("p",null,"The live logs tab gives you a real-time view on the log generated by your application while running remotely on your cloud provider infrastructure. "),Object(a.b)("p",null,"Within this section you will find:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Timestamp: the timestamp of the message"),Object(a.b)("li",{parentName:"ul"},"Pod Name: the name of the kubernetes pod where your application is running (to distinguish the instance in case of the multi-instance app). If you want to follow a specific pod, you can filter the logs by clicking on the pod name"),Object(a.b)("li",{parentName:"ul"},"Version: the commit id or the image tag of the application running on this POD"),Object(a.b)("li",{parentName:"ul"},"Message: the log message")),Object(a.b)("p",null,"Past application logs are also preserved on your cluster via ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://grafana.com/oss/loki/"}),"Loki")," and can be accessed from the same log view within the qovery console. Please keep in mind that:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Loki is configured to preserve only the latest 1000 lines of log for each application and retain them for 12 weeks (configurable via the ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cluster-advanced-settings/#logs"}),"cluster advanced settings"),")"),Object(a.b)("li",{parentName:"ul"},"This feature is not available on ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#why-do-i-need-a-cluster"}),"EC2 Clusters")," since we don't install Loki.")),Object(a.b)("p",null,"If you need to troubleshoot issues on the requests managed by your application, you can also access the Nginx logs in the same view (logs format is available in the helper). Note that this option is available only if the application is exposed publicly (See the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#ports"}),"Port Section"),")"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/live_logs.png",alt:"Log content"})))}p.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function i(){for(var e=[],t=0;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=i.a.createContext({}),u=function(e){var t=i.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},p=function(e){var t=u(e.components);return i.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},m=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,r=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),p=u(n),m=o,d=p["".concat(r,".").concat(m)]||p[m]||b[m]||a;return n?i.a.createElement(d,l({ref:t},s,{components:n})):i.a.createElement(d,l({ref:t},s))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,r=new Array(a);r[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:o,r[1]=l;for(var s=2;s1?arguments[1]:void 0,n),c=r>2?arguments[2]:void 0,s=void 0===c?n:i(c,n);s>l;)t[l++]=e;return t}},428:function(e,t,n){var o=n(28).f,i=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in i||n(10)&&o(i,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var o=n(0),i=n.n(o),a=n(424);t.a=function(e){var t=e.children,n=e.name;return i.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},i.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var o=n(1),i=n(0),a=n.n(i),r=n(39),l=n(432),c=n(20),s=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,u=n||c,p=Object(l.a)(u),b=Object(i.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!m&&p&&window.docusaurus.prefetch(u),function(){m&&t&&t.disconnect()}}),[u,m,p]),u&&p?a.a.createElement(r.b,Object(o.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,o;m&&e&&p&&(n=e,o=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:u})):a.a.createElement("a",Object(o.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var o=n(0),i=n.n(o),a=n(430),r=n(423),l=n.n(r);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,r=e.leftIcon,c=e.rightIcon,s=e.size,u=e.target,p=e.to,b=l()("jump-to","jump-to--"+s,n),m=i.a.createElement("div",{className:"jump-to--inner"},i.a.createElement("div",{className:"jump-to--inner-2"},r&&i.a.createElement("div",{className:"jump-to--left"},i.a.createElement("i",{className:"feather icon-"+r})),i.a.createElement("div",{className:"jump-to--main"},o?i.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),i.a.createElement("div",{className:"jump-to--right"},i.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return u?i.a.createElement("a",{href:p,target:u,className:b},m):i.a.createElement(a.a,{to:p,className:b},m)}},432:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))}}]); \ No newline at end of file diff --git a/7aa59ca3.491bd2a3.js.LICENSE.txt b/6ebd4d49.388e1fe5.js.LICENSE.txt similarity index 100% rename from 7aa59ca3.491bd2a3.js.LICENSE.txt rename to 6ebd4d49.388e1fe5.js.LICENSE.txt diff --git a/7278678a.b4f2042e.js b/7278678a.45ad78dd.js similarity index 96% rename from 7278678a.b4f2042e.js rename to 7278678a.45ad78dd.js index 380d0a0d2b..8b3a0012f2 100644 --- a/7278678a.b4f2042e.js +++ b/7278678a.45ad78dd.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[124],{275:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return s}));var r=n(1),o=n(9),a=(n(0),n(422)),i={last_modified_on:"2020-04-23",title:"GDPR",description:"General Data Protection Regulation"},c={id:"security-and-compliance/gdpr",title:"GDPR",description:"General Data Protection Regulation",source:"@site/docs/security-and-compliance/gdpr.md",permalink:"/docs/security-and-compliance/gdpr",sidebar:"docs",previous:{title:"Encryption",permalink:"/docs/security-and-compliance/encryption"},next:{title:"SOC2",permalink:"/docs/security-and-compliance/soc2"}},l=[{value:"Data Protection by Design",id:"data-protection-by-design",children:[]},{value:"Data Protection Officer",id:"data-protection-officer",children:[]},{value:"Consent",id:"consent",children:[]},{value:"Enhanced Rights",id:"enhanced-rights",children:[]},{value:"Data Collection",id:"data-collection",children:[]},{value:"Data Retention",id:"data-retention",children:[]}],u={rightToc:l};function s(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Qovery has taken numerous steps to ensure GDPR compliance. As part of our measures, we have implemented the following:"),Object(a.b)("h2",{id:"data-protection-by-design"},"Data Protection by Design"),Object(a.b)("p",null,"We've implemented policies in the company to ensure all of our employees follow the necessary training and protocols around security. Besides, privacy protection is part of every project during instantiation."),Object(a.b)("h2",{id:"data-protection-officer"},"Data Protection Officer"),Object(a.b)("p",null,"Appointment of a Security Officer, who also holds the Data Protection Officer (DPO) role. If you have any concern, ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/contact"}),"contact us"),"."),Object(a.b)("h2",{id:"consent"},"Consent"),Object(a.b)("p",null,"We've confirmed that all of our customer communication, both business-related and marketing-related, is opt-in, and no information is shared with us without a customer's consent."),Object(a.b)("h2",{id:"enhanced-rights"},"Enhanced Rights"),Object(a.b)("p",null,"The GDPR provides rights to individuals, such as the right to portability, right of rectification, and the right to be forgotten. We've made sure we comply with these rights. Nearly all information can be edited through a user's account, and we can delete accounts upon request."),Object(a.b)("h2",{id:"data-collection"},"Data Collection"),Object(a.b)("p",null,"We've documented information about what data we collect."),Object(a.b)("h2",{id:"data-retention"},"Data Retention"),Object(a.b)("p",null,"We documented information about our data retention."))}s.isMDXComponent=!0},422:function(e,t,n){"use strict";n.d(t,"a",(function(){return p})),n.d(t,"b",(function(){return b}));var r=n(0),o=n.n(r);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),f=r,b=p["".concat(i,".").concat(f)]||p[f]||d[f]||a;return n?o.a.createElement(b,c({ref:t},u,{components:n})):o.a.createElement(b,c({ref:t},u))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=f;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),f=r,b=p["".concat(i,".").concat(f)]||p[f]||d[f]||a;return n?o.a.createElement(b,c({ref:t},u,{components:n})):o.a.createElement(b,c({ref:t},u))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=f;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u ALIAS -> ",Object(r.b)("inlineCode",{parentName:"li"},"BILLING_BACKEND")," with scope ",Object(r.b)("inlineCode",{parentName:"li"},"ENVIRONMENT")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"YYY_HOST_INTERNAL")," -> ALIAS -> ",Object(r.b)("inlineCode",{parentName:"li"},"MESSAGING_BACKEND")," with scope ",Object(r.b)("inlineCode",{parentName:"li"},"ENVIRONMENT")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"ZZZ_HOST_INTERNAL")," -> ALIAS -> ",Object(r.b)("inlineCode",{parentName:"li"},"CORE_BACKEND")," with scope ",Object(r.b)("inlineCode",{parentName:"li"},"ENVIRONMENT"))),Object(r.b)("h3",{id:"how-to-find-the-correct-environment-variable"},"How to find the correct environment variable"),Object(r.b)("p",null,"When you have multiple applications within the same environment, it is difficult to find the appropriate environment variable. A workaround is to:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Go to one of your application"),Object(r.b)("li",{parentName:"ol"},"Find the ID of your application in your URL ",Object(r.b)("inlineCode",{parentName:"li"},"https://console.qovery.com/platform/organization/xxx/projects/yyy/environments/zzz/applications/082e36c4-7fbb-42b2-9046-37ccce21616a/variables")),Object(r.b)("li",{parentName:"ol"},"Truncate your application ID and take the first segment. For ",Object(r.b)("inlineCode",{parentName:"li"},"082e36c4-7fbb-42b2-9046-37ccce21616a")," it is ",Object(r.b)("inlineCode",{parentName:"li"},"082e36c4")),Object(r.b)("li",{parentName:"ol"},"Add the letter z in front of id ",Object(r.b)("inlineCode",{parentName:"li"},"Z082e36c4"),"."),Object(r.b)("li",{parentName:"ol"},"All the environment variables containing ",Object(r.b)("inlineCode",{parentName:"li"},"Z082e36c4")," are attached to the corresponding app.")),Object(r.b)("h2",{id:"set-up-custom-domain"},"Set up custom domain"),Object(r.b)("p",null,"Add a custom domain to expose your API gateway with the domain of your choice. Check out ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#domains"}),"this documentation")," to set up your domain."),Object(r.b)("h2",{id:"deploy-api-gateway"},"Deploy API Gateway"),Object(r.b)("p",null,"Once everything is set up, you can deploy your application."))}b.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function i(){for(var e=[],t=0;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=i.a.createContext({}),p=function(e){var t=i.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=p(e.components);return i.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},m=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=p(n),m=a,d=u["".concat(o,".").concat(m)]||u[m]||b[m]||r;return n?i.a.createElement(d,c({ref:t},s,{components:n})):i.a.createElement(d,c({ref:t},s))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,o[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=o>2?arguments[2]:void 0,s=void 0===l?n:i(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var a=n(28).f,i=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in i||n(10)&&a(i,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),i=n.n(a),r=n(421);t.a=function(e){var t=e.children,n=e.name;return i.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},i.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),i=n(0),r=n.n(i),o=n(39),c=n(430),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,p=n||l,u=Object(c.a)(p),b=Object(i.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!m&&u&&window.docusaurus.prefetch(p),function(){m&&t&&t.disconnect()}}),[p,m,u]),p&&u?r.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(p),b.current=!0)},innerRef:function(e){var n,a;m&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:p})):r.a.createElement("a",Object(a.a)({},e,{href:p}))}},429:function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=n(427),o=n(420),c=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,o=e.leftIcon,l=e.rightIcon,s=e.size,p=e.target,u=e.to,b=c()("jump-to","jump-to--"+s,n),m=i.a.createElement("div",{className:"jump-to--inner"},i.a.createElement("div",{className:"jump-to--inner-2"},o&&i.a.createElement("div",{className:"jump-to--left"},i.a.createElement("i",{className:"feather icon-"+o})),i.a.createElement("div",{className:"jump-to--main"},a?i.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),i.a.createElement("div",{className:"jump-to--right"},i.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return p?i.a.createElement("a",{href:u,target:p,className:b},m):i.a.createElement(r.a,{to:u,className:b},m)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see 7952d159.397b9c13.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[127],{278:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return b}));var a=n(1),i=n(9),r=(n(0),n(425)),o=n(424),c=n(429),l=(n(431),{last_modified_on:"2023-05-29",$schema:"/.meta/.schemas/guides.json",title:"Use an API gateway in front of multiple services",description:"Learn how to use an API gateway in front of multiple services",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Use an API gateway in front of multiple services",description:"Learn how to use an API gateway in front of multiple services",permalink:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services",readingTime:"4 min read",source:"@site/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Use an API gateway in front of multiple services",truncated:!1,prevItem:{title:"URL Shortener API with Kotlin (Part 1/2)",permalink:"/guides/tutorial/url-shortener-api-with-kotlin"},nextItem:{title:"Use AWS IAM roles with Qovery",permalink:"/guides/tutorial/use-aws-iam-roles-with-qovery"}},p=[{value:"Clone API Gateway",id:"clone-api-gateway",children:[]},{value:"Edit configuration",id:"edit-configuration",children:[]},{value:"Create API Gateway app",id:"create-api-gateway-app",children:[]},{value:"Add environment variables",id:"add-environment-variables",children:[{value:"How to find the correct environment variable",id:"how-to-find-the-correct-environment-variable",children:[]}]},{value:"Set up custom domain",id:"set-up-custom-domain",children:[]},{value:"Deploy API Gateway",id:"deploy-api-gateway",children:[]}],u={rightToc:p};function b(e){var t=e.components,n=Object(i.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"In the future, Qovery will integrate an ",Object(r.b)("em",{parentName:"p"},"API gateway")," service. In the meantime, you can use this tutorial to use an API gateway in front of your apps.")),Object(r.b)("p",null,"Using an API gateway is perfect to expose a single web API domain without exposing the underlying implementation. Especially, when using a decoupled architecture with multiple services."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/apigateway/api-gateway.jpg",alt:"API Gateway architecture"})),Object(r.b)("p",null,"In this tutorial, you will learn how to connect an API gateway in front of 3 different applications (cf. schema above)."),Object(r.b)(c.a,{mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have created at least one application in Qovery"))),Object(r.b)("p",null,"Note: My tutorial required to have 3 applications - a ",Object(r.b)("em",{parentName:"p"},"billing API"),", ",Object(r.b)("em",{parentName:"p"},"core API")," and a ",Object(r.b)("em",{parentName:"p"},"messaging API"),". You don't necessarily need to have 3 applications to put an API gateway. Only one application is enough. Feel free to adapt the tutorial to your real need."),Object(r.b)("h2",{id:"clone-api-gateway"},"Clone API Gateway"),Object(r.b)("p",null,"I have prepared an API Gateway template project that you can find ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/nginx-gateway"}),"here"),". Fork it, and I will guide you to make the appropriate changes. Our API Gateway is based on NGINX - one of the most used web server out there. Written in C++, NGINX is lightweight and can handle thousands of requests per second without any issue."),Object(r.b)("p",null,"Repository to fork: ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/nginx-gateway"}),"https://github.com/Qovery/nginx-gateway")),Object(r.b)("h2",{id:"edit-configuration"},"Edit configuration"),Object(r.b)("p",null,"Once the repo forked, you will have access to ",Object(r.b)("inlineCode",{parentName:"p"},"nginx.conf.template")," and ",Object(r.b)("inlineCode",{parentName:"p"},"routes.conf.template")," - which are the two configuration files.\nThe ",Object(r.b)("inlineCode",{parentName:"p"},"nginx.conf.template")," is the configuration of the NGINX server. This is where you can tweak your server. We will not modify it since I have set up a good configuration for an API gateway. Feel free to dig into it and check out the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://nginx.org/en/docs/"}),"NGINX documentation")," to learn more."),Object(r.b)("p",null,"However, the ",Object(r.b)("inlineCode",{parentName:"p"},"routes.conf.template")," is the file that we need to modify to route the incoming traffic from ",Object(r.b)("inlineCode",{parentName:"p"},"api.foo.bar")," to the right service.\nOur route configuration file looks like this:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-text",metastring:'title="routes.conf.template"',title:'"routes.conf.template"'}),"location ~* ^/api/billing/?(.*)$ {\n proxy_pass http://$BILLING_BACKEND$request_uri;\n}\n\nlocation ~* ^/api/messaging/?(.*)$ {\n proxy_pass http://$MESSAGING_BACKEND$request_uri;\n}\n\nlocation ~* ^/api/(.*)$ {\n proxy_pass http://$CORE_BACKEND$request_uri;\n}\n\nlocation ~* ^/?(.*)$ {\n proxy_pass http://$CORE_BACKEND$request_uri;\n}\n")),Object(r.b)("p",null,"Here are the explanation of those rules:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"All the traffic matching the path ",Object(r.b)("inlineCode",{parentName:"li"},"/api/billing/*")," is redirect to the BILLING backend."),Object(r.b)("li",{parentName:"ol"},"All the traffic matching the path ",Object(r.b)("inlineCode",{parentName:"li"},"/api/messaging/*")," is redirect to the MESSAGING backend."),Object(r.b)("li",{parentName:"ol"},"All the traffic matching the path ",Object(r.b)("inlineCode",{parentName:"li"},"/api/*")," is redirect to the CORE backend."),Object(r.b)("li",{parentName:"ol"},"All the traffic by default is redirected to the CORE backend.")),Object(r.b)("p",null,"Notes:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"The rule definition order is from the first to the last to apply. If there is a conflicting rule, then the first matched applies."),Object(r.b)("li",{parentName:"ol"},"The internal network is in HTTP, that is why the value of the ",Object(r.b)("inlineCode",{parentName:"li"},"proxy_pass")," directive starts with ",Object(r.b)("inlineCode",{parentName:"li"},"http://"),"."),Object(r.b)("li",{parentName:"ol"},"The connections on ",Object(r.b)("inlineCode",{parentName:"li"},"api.foo.bar")," are in HTTPS."),Object(r.b)("li",{parentName:"ol"},"You can make complex rules like the one below:")),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-text",metastring:'title="more complex rule"',title:'"more',complex:!0,'rule"':!0}),"location ~* ^/api/v1/user/(.*)/app/(.*)/index/(.*)/search/?(.*)$ {\n proxy_pass http://$CORE_BACKEND/api/v1/user/$1/app/$2/index/$3/search/$4$is_args$args;\n}\n")),Object(r.b)("h2",{id:"create-api-gateway-app"},"Create API Gateway app"),Object(r.b)("p",null,"Commit and push your changes. Then go to the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web console"),", and add your API gateway inside the same environment of your applications."),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Build mode: Dockerfile"),Object(r.b)("li",{parentName:"ul"},"Port: 80")),Object(r.b)("h2",{id:"add-environment-variables"},"Add environment variables"),Object(r.b)("p",null,"For our gateway, we need to create 3 ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#alias-environment-variable"}),"environment variable aliases")," corresponding to the internal network names of our applications."),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"XXX_HOST_INTERNAL")," -> ALIAS -> ",Object(r.b)("inlineCode",{parentName:"li"},"BILLING_BACKEND")," with scope ",Object(r.b)("inlineCode",{parentName:"li"},"ENVIRONMENT")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"YYY_HOST_INTERNAL")," -> ALIAS -> ",Object(r.b)("inlineCode",{parentName:"li"},"MESSAGING_BACKEND")," with scope ",Object(r.b)("inlineCode",{parentName:"li"},"ENVIRONMENT")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"ZZZ_HOST_INTERNAL")," -> ALIAS -> ",Object(r.b)("inlineCode",{parentName:"li"},"CORE_BACKEND")," with scope ",Object(r.b)("inlineCode",{parentName:"li"},"ENVIRONMENT"))),Object(r.b)("h3",{id:"how-to-find-the-correct-environment-variable"},"How to find the correct environment variable"),Object(r.b)("p",null,"When you have multiple applications within the same environment, it is difficult to find the appropriate environment variable. A workaround is to:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Go to one of your application"),Object(r.b)("li",{parentName:"ol"},"Find the ID of your application in your URL ",Object(r.b)("inlineCode",{parentName:"li"},"https://console.qovery.com/platform/organization/xxx/projects/yyy/environments/zzz/applications/082e36c4-7fbb-42b2-9046-37ccce21616a/variables")),Object(r.b)("li",{parentName:"ol"},"Truncate your application ID and take the first segment. For ",Object(r.b)("inlineCode",{parentName:"li"},"082e36c4-7fbb-42b2-9046-37ccce21616a")," it is ",Object(r.b)("inlineCode",{parentName:"li"},"082e36c4")),Object(r.b)("li",{parentName:"ol"},"Add the letter z in front of id ",Object(r.b)("inlineCode",{parentName:"li"},"Z082e36c4"),"."),Object(r.b)("li",{parentName:"ol"},"All the environment variables containing ",Object(r.b)("inlineCode",{parentName:"li"},"Z082e36c4")," are attached to the corresponding app.")),Object(r.b)("h2",{id:"set-up-custom-domain"},"Set up custom domain"),Object(r.b)("p",null,"Add a custom domain to expose your API gateway with the domain of your choice. Check out ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#domains"}),"this documentation")," to set up your domain."),Object(r.b)("h2",{id:"deploy-api-gateway"},"Deploy API Gateway"),Object(r.b)("p",null,"Once everything is set up, you can deploy your application."))}b.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function i(){for(var e=[],t=0;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=i.a.createContext({}),p=function(e){var t=i.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=p(e.components);return i.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},m=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=p(n),m=a,d=u["".concat(o,".").concat(m)]||u[m]||b[m]||r;return n?i.a.createElement(d,c({ref:t},s,{components:n})):i.a.createElement(d,c({ref:t},s))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,o[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=o>2?arguments[2]:void 0,s=void 0===l?n:i(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var a=n(28).f,i=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in i||n(10)&&a(i,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),i=n.n(a),r=n(424);t.a=function(e){var t=e.children,n=e.name;return i.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},i.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),i=n(0),r=n.n(i),o=n(39),c=n(432),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,p=n||l,u=Object(c.a)(p),b=Object(i.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!m&&u&&window.docusaurus.prefetch(p),function(){m&&t&&t.disconnect()}}),[p,m,u]),p&&u?r.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(p),b.current=!0)},innerRef:function(e){var n,a;m&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:p})):r.a.createElement("a",Object(a.a)({},e,{href:p}))}},431:function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=n(430),o=n(423),c=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,o=e.leftIcon,l=e.rightIcon,s=e.size,p=e.target,u=e.to,b=c()("jump-to","jump-to--"+s,n),m=i.a.createElement("div",{className:"jump-to--inner"},i.a.createElement("div",{className:"jump-to--inner-2"},o&&i.a.createElement("div",{className:"jump-to--left"},i.a.createElement("i",{className:"feather icon-"+o})),i.a.createElement("div",{className:"jump-to--main"},a?i.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),i.a.createElement("div",{className:"jump-to--right"},i.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return p?i.a.createElement("a",{href:u,target:p,className:b},m):i.a.createElement(r.a,{to:u,className:b},m)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/7df50433.2cb08e4d.js.LICENSE.txt b/7952d159.397b9c13.js.LICENSE.txt similarity index 100% rename from 7df50433.2cb08e4d.js.LICENSE.txt rename to 7952d159.397b9c13.js.LICENSE.txt diff --git a/de0a75d9.2096bbbe.js b/7aa59ca3.81639c91.js similarity index 80% rename from de0a75d9.2096bbbe.js rename to 7aa59ca3.81639c91.js index 7a6c6ff502..60551cf89f 100644 --- a/de0a75d9.2096bbbe.js +++ b/7aa59ca3.81639c91.js @@ -1,2 +1,2 @@ -/*! For license information please see de0a75d9.2096bbbe.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[232],{384:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return d}));var o=n(1),a=n(9),r=(n(0),n(422)),c=n(431),i=n(421),l=n(426),u=(n(429),{last_modified_on:"2023-03-30",$schema:"/.meta/.schemas/guides.json",title:"How to connect to your EKS cluster with kubectl",description:"How to connect to your EKS cluster using kubectl",author_github:"https://github.com/l0ck3",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to connect to your EKS cluster with kubectl",description:"How to connect to your EKS cluster using kubectl",permalink:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl",readingTime:"5 min read",source:"@site/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to connect to your EKS cluster with kubectl",truncated:!1,prevItem:{title:"How to connect to a managed MongoDB instance on AWS",permalink:"/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws"},nextItem:{title:"How to create an RDS instance through the AWS console",permalink:"/guides/tutorial/how-to-create-an-rds-instance-through-aws-console"}},b=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],p={rightToc:b};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(r.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Qovery makes it easy to create an EKS cluster on your AWS account and manage the deployment of applications on it. But you still might want to execute operations on it via ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," like you would on any other Kubernetes cluster."),Object(r.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have an existing EKS cluster manages by Qovery"),Object(r.b)("li",{parentName:"ul"},"You have deployed an application on this cluster with Qovery"))),Object(r.b)(i.a,{type:"warning",mdxType:"Alert"},"Be aware that any operation you do manually on your cluster could conflict with Qovery. We would advise to not use this method for anything else than connecting to a container with `kubectl exec`"),Object(r.b)("h2",{id:"goal"},"Goal"),Object(r.b)("p",null,"This tutorial will show you how to access a Qovery managed cluster on AWS with ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," and shell into a running application container."),Object(r.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,Object(r.b)("h4",{id:"install-and-configure-your-toolchain"},"Install and configure your toolchain"),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"kubectl")),Object(r.b)("p",null,"To interact with your cluster, you will need ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," installed.\n",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://kubernetes.io/docs/tasks/tools/"}),"https://kubernetes.io/docs/tasks/tools/")),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"AWS CLI")),Object(r.b)("p",null,"The AWS CLI must be installed and configured on your machine.\n",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"}),"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"))),Object(r.b)("li",null,Object(r.b)("h4",{id:"add-your-iam-user-to-the-admin-group"},"Add your IAM user to the Admin group"),Object(r.b)("p",null,"Since ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," will use IAM to authenticate, you need to add your IAM user (the one the AWS CLI is authenticated with) to the ",Object(r.b)("inlineCode",{parentName:"p"},"Admins")," group you created when setting up Qovery."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/how-to-connect-to-your-eks-cluster-with-kubectl/1.png",alt:"AWS console - add admin user"}))),Object(r.b)("li",null,Object(r.b)("h4",{id:"download-the-kubeconfig-file"},"Download the Kubeconfig file"),Object(r.b)("p",null,"To connect to your EKS cluster you will need to set a context to ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl"),". This is done with a ",Object(r.b)("inlineCode",{parentName:"p"},"Kubeconfig")," file."),Object(r.b)("p",null,"When installing a new cluster, Qovery stores it in an S3 bucket on your account."),Object(r.b)("p",null,"Go to S3, find the Qovery bucket, and download the file. The bucket should be named something like ",Object(r.b)("inlineCode",{parentName:"p"},"qovery-kubeconfigs-.yaml"),"."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/how-to-connect-to-your-eks-cluster-with-kubectl/2.png",alt:"AWS console - get Kubeconfig"}))),Object(r.b)("li",null,Object(r.b)("h4",{id:"set-the-context-for-kubectl"},"Set the context for kubectl"),Object(r.b)("p",null,"To set the context for kubectl, run the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"export KUBECONFIG=\n")),Object(r.b)("p",null,"You can check that it works with a kubectl command. For example:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get nodes\n")),Object(r.b)("p",null,"You are good to go if you see an output like the following:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"NAME STATUS ROLES AGE VERSION\nzb81b1cd4-ub667 Ready 14d v1.19.15\nzb81b1cd4-ujkm8 Ready 24d v1.19.15\nzb81b1cd4-ujkmc Ready 24d v1.19.15\n"))),Object(r.b)("li",null,Object(r.b)("h4",{id:"get-your-application-namespace"},"Get your application namespace"),Object(r.b)("p",null,"When you deploy an application, Qovery will create a separate namespace for each environment on your Kubernetes cluster."),Object(r.b)("p",null,"You can get the list of the namespaces on your cluster using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get namespaces\n")),Object(r.b)("p",null,"You will get an output similar to this one:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"NAME STATUS AGE\ncert-manager Active 44d\ndefault Active 44d\nkube-node-lease Active 44d\nkube-public Active 44d\nkube-system Active 44d\nlogging Active 44d\nnginx-ingress Active 44d\nprometheus Active 44d\nqovery Active 44d\nz0121531e-zb2daee81 Active 35d\nz016bd165-zeb51c37e Active 31d\n")),Object(r.b)("p",null,"The Qovery application namespaces are the ones begining with ",Object(r.b)("inlineCode",{parentName:"p"},"z"),"."),Object(r.b)("p",null,"In case you have several environments running, to identify the right one:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Go to the Qovery console"),Object(r.b)("li",{parentName:"ul"},"Go to the right environment")),Object(r.b)("p",null,"In your URL bar you'll have something like:"),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"https://console.qovery.com/platform/organization//projects//environments//applications")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/how-to-connect-to-your-eks-cluster-with-kubectl/3.png",alt:"Qovery console - environment"})),Object(r.b)("p",null,"The environment namespace is defined the following way: ",Object(r.b)("inlineCode",{parentName:"p"},"z-z"),"."),Object(r.b)("p",null,"The short ID is the first section of the ID. For example, given the following ID: ",Object(r.b)("inlineCode",{parentName:"p"},"e0aabc0d-99cb-4867-ad39-332d6162c32c"),", the short ID will be ",Object(r.b)("inlineCode",{parentName:"p"},"e0aabc0d"),"."),Object(r.b)("p",null,"The following environment URL: ",Object(r.b)("inlineCode",{parentName:"p"},"https://console.qovery.com/platform/organization//projects/e0aabc0d-99cb-4867-ad39-332d6162c32c/environments/b91d2eb8-a850-49b5-8626-ade7afc4a28b/applications"),"\nwould translate to the following namespace: ",Object(r.b)("inlineCode",{parentName:"p"},"ze0aabc0d-zb91d2eb8"),".")),Object(r.b)("li",null,Object(r.b)("h4",{id:"identify-the-right-application-pods"},"Identify the right application pod(s)"),Object(r.b)("p",null,"To list the pods running in your environment namespace, run the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get pods --namespace \n")),Object(r.b)("p",null,"The output should be similar to this one:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"NAME READY STATUS RESTARTS AGE\napp-z2fc29b74-5db6745975-nrw8v 1/1 Running 0 29h\napp-zabbcf976-74f969f848-kzp87 1/1 Running 0 29h\n")),Object(r.b)("p",null,"The same principle goes for finding the right application pod. Go to the application page on the Qovery console."),Object(r.b)("p",null,"You'll get an URL looking like this:"),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"https://console.qovery.com/platform/organization//projects//environments//applications/abbcf976-27a1-4531-9cdd-e4d15d7b2c27/summary")),Object(r.b)("p",null,"Get the short ID of our application, in our case ",Object(r.b)("inlineCode",{parentName:"p"},"abbcf976")," which means the application pod name will start with ",Object(r.b)("inlineCode",{parentName:"p"},"app-zabbcf976"),"."),Object(r.b)("p",null,"In case you setup your app to run multiple replicas, it is possible that you see several pods begining with the same string. You can pick any of them."),Object(r.b)("p",null,"In our case the right pod corresponding to our application would be ",Object(r.b)("inlineCode",{parentName:"p"},"app-zabbcf976-74f969f848-kzp87"),".")),Object(r.b)("li",null,Object(r.b)("h4",{id:"shell-into-the-container"},"Shell into the container"),Object(r.b)("p",null,"To get a shell access to the container running inside the application pod, all you have to do is:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl exec -ti --namespace -- sh\n")),Object(r.b)("p",null,"This will open a shell inside of your application container. You can now execute any command you need.")))),Object(r.b)("h2",{id:"conclusion"},"Conclusion"),Object(r.b)("p",null,"Qovery helps you manage your Kubernetes cluster and deploy your applications on it while still giving you the power of a full access to your cluster."),Object(r.b)(i.a,{type:"note",mdxType:"Alert"},"Soon you will be able to achieve the same thing through the Qovery CLI."))}d.isMDXComponent=!0},420:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),b=s(n),d=o,m=b["".concat(c,".").concat(d)]||b[d]||p[d]||r;return n?a.a.createElement(m,i({ref:t},u,{components:n})):a.a.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,c=new Array(r);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var u=2;u1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>i;)t[i++]=e;return t}},425:function(e,t,n){var o=n(28).f,a=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in a||n(10)&&o(a,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var o=n(0),a=n.n(o),r=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var o=n(1),a=n(0),r=n.n(a),c=n(39),i=n(430),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,b=Object(i.a)(s),p=Object(a.useRef)(!1),d=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(s),function(){d&&t&&t.disconnect()}}),[s,d,b]),s&&b?r.a.createElement(c.b,Object(o.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,o;d&&e&&b&&(n=e,o=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:s})):r.a.createElement("a",Object(o.a)({},e,{href:s}))}},428:function(e,t,n){"use strict";var o=n(432),a=n(51);function r(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),r=t.length>0?t.join("="):void 0;r=void 0===r?null:decodeURIComponent(r),n(decodeURIComponent(a),r,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[r(t,e),"[",o,"]"].join(""):[r(t,e),"[",r(o,e),"]=",r(n,e)].join("")};case"bracket":return function(t,n){return null===n?r(t,e):[r(t,e),"[]=",r(n,e)].join("")};default:return function(t,n){return null===n?r(t,e):[r(t,e),"=",r(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var a=e[o];if(void 0===a)return"";if(null===a)return r(o,t);if(Array.isArray(a)){var c=[];return a.slice().forEach((function(e){void 0!==e&&c.push(n(o,e,c.length))})),c.join("&")}return r(o,t)+"="+r(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=n(427),c=n(420),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,c=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,b=e.to,p=i()("jump-to","jump-to--"+u,n),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},c&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+c})),a.a.createElement("div",{className:"jump-to--main"},o?a.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?a.a.createElement("a",{href:b,target:s,className:p},d):a.a.createElement(r.a,{to:b,className:p},d)}},430:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},431:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=(n(420),n(428)),c=n.n(r);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,r=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(o.useState)(null),b=s[0],p=s[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!r&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 7aa59ca3.81639c91.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[128],{279:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return d}));var o=n(1),a=n(9),r=(n(0),n(425)),c=n(434),i=n(424),l=n(429),u=(n(431),{last_modified_on:"2023-03-30",$schema:"/.meta/.schemas/guides.json",title:"How to connect to your EKS cluster with kubectl",description:"How to connect to your EKS cluster using kubectl",author_github:"https://github.com/l0ck3",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to connect to your EKS cluster with kubectl",description:"How to connect to your EKS cluster using kubectl",permalink:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl",readingTime:"5 min read",source:"@site/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to connect to your EKS cluster with kubectl",truncated:!1,prevItem:{title:"How to connect to a managed MongoDB instance on AWS",permalink:"/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws"},nextItem:{title:"How to create an RDS instance through the AWS console",permalink:"/guides/tutorial/how-to-create-an-rds-instance-through-aws-console"}},b=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],p={rightToc:b};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(r.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Qovery makes it easy to create an EKS cluster on your AWS account and manage the deployment of applications on it. But you still might want to execute operations on it via ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," like you would on any other Kubernetes cluster."),Object(r.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have an existing EKS cluster manages by Qovery"),Object(r.b)("li",{parentName:"ul"},"You have deployed an application on this cluster with Qovery"))),Object(r.b)(i.a,{type:"warning",mdxType:"Alert"},"Be aware that any operation you do manually on your cluster could conflict with Qovery. We would advise to not use this method for anything else than connecting to a container with `kubectl exec`"),Object(r.b)("h2",{id:"goal"},"Goal"),Object(r.b)("p",null,"This tutorial will show you how to access a Qovery managed cluster on AWS with ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," and shell into a running application container."),Object(r.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,Object(r.b)("h4",{id:"install-and-configure-your-toolchain"},"Install and configure your toolchain"),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"kubectl")),Object(r.b)("p",null,"To interact with your cluster, you will need ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," installed.\n",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://kubernetes.io/docs/tasks/tools/"}),"https://kubernetes.io/docs/tasks/tools/")),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"AWS CLI")),Object(r.b)("p",null,"The AWS CLI must be installed and configured on your machine.\n",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"}),"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"))),Object(r.b)("li",null,Object(r.b)("h4",{id:"add-your-iam-user-to-the-admin-group"},"Add your IAM user to the Admin group"),Object(r.b)("p",null,"Since ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," will use IAM to authenticate, you need to add your IAM user (the one the AWS CLI is authenticated with) to the ",Object(r.b)("inlineCode",{parentName:"p"},"Admins")," group you created when setting up Qovery."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/how-to-connect-to-your-eks-cluster-with-kubectl/1.png",alt:"AWS console - add admin user"}))),Object(r.b)("li",null,Object(r.b)("h4",{id:"download-the-kubeconfig-file"},"Download the Kubeconfig file"),Object(r.b)("p",null,"To connect to your EKS cluster you will need to set a context to ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl"),". This is done with a ",Object(r.b)("inlineCode",{parentName:"p"},"Kubeconfig")," file."),Object(r.b)("p",null,"When installing a new cluster, Qovery stores it in an S3 bucket on your account."),Object(r.b)("p",null,"Go to S3, find the Qovery bucket, and download the file. The bucket should be named something like ",Object(r.b)("inlineCode",{parentName:"p"},"qovery-kubeconfigs-.yaml"),"."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/how-to-connect-to-your-eks-cluster-with-kubectl/2.png",alt:"AWS console - get Kubeconfig"}))),Object(r.b)("li",null,Object(r.b)("h4",{id:"set-the-context-for-kubectl"},"Set the context for kubectl"),Object(r.b)("p",null,"To set the context for kubectl, run the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"export KUBECONFIG=\n")),Object(r.b)("p",null,"You can check that it works with a kubectl command. For example:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get nodes\n")),Object(r.b)("p",null,"You are good to go if you see an output like the following:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"NAME STATUS ROLES AGE VERSION\nzb81b1cd4-ub667 Ready 14d v1.19.15\nzb81b1cd4-ujkm8 Ready 24d v1.19.15\nzb81b1cd4-ujkmc Ready 24d v1.19.15\n"))),Object(r.b)("li",null,Object(r.b)("h4",{id:"get-your-application-namespace"},"Get your application namespace"),Object(r.b)("p",null,"When you deploy an application, Qovery will create a separate namespace for each environment on your Kubernetes cluster."),Object(r.b)("p",null,"You can get the list of the namespaces on your cluster using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get namespaces\n")),Object(r.b)("p",null,"You will get an output similar to this one:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"NAME STATUS AGE\ncert-manager Active 44d\ndefault Active 44d\nkube-node-lease Active 44d\nkube-public Active 44d\nkube-system Active 44d\nlogging Active 44d\nnginx-ingress Active 44d\nprometheus Active 44d\nqovery Active 44d\nz0121531e-zb2daee81 Active 35d\nz016bd165-zeb51c37e Active 31d\n")),Object(r.b)("p",null,"The Qovery application namespaces are the ones begining with ",Object(r.b)("inlineCode",{parentName:"p"},"z"),"."),Object(r.b)("p",null,"In case you have several environments running, to identify the right one:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Go to the Qovery console"),Object(r.b)("li",{parentName:"ul"},"Go to the right environment")),Object(r.b)("p",null,"In your URL bar you'll have something like:"),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"https://console.qovery.com/platform/organization//projects//environments//applications")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/how-to-connect-to-your-eks-cluster-with-kubectl/3.png",alt:"Qovery console - environment"})),Object(r.b)("p",null,"The environment namespace is defined the following way: ",Object(r.b)("inlineCode",{parentName:"p"},"z-z"),"."),Object(r.b)("p",null,"The short ID is the first section of the ID. For example, given the following ID: ",Object(r.b)("inlineCode",{parentName:"p"},"e0aabc0d-99cb-4867-ad39-332d6162c32c"),", the short ID will be ",Object(r.b)("inlineCode",{parentName:"p"},"e0aabc0d"),"."),Object(r.b)("p",null,"The following environment URL: ",Object(r.b)("inlineCode",{parentName:"p"},"https://console.qovery.com/platform/organization//projects/e0aabc0d-99cb-4867-ad39-332d6162c32c/environments/b91d2eb8-a850-49b5-8626-ade7afc4a28b/applications"),"\nwould translate to the following namespace: ",Object(r.b)("inlineCode",{parentName:"p"},"ze0aabc0d-zb91d2eb8"),".")),Object(r.b)("li",null,Object(r.b)("h4",{id:"identify-the-right-application-pods"},"Identify the right application pod(s)"),Object(r.b)("p",null,"To list the pods running in your environment namespace, run the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get pods --namespace \n")),Object(r.b)("p",null,"The output should be similar to this one:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"NAME READY STATUS RESTARTS AGE\napp-z2fc29b74-5db6745975-nrw8v 1/1 Running 0 29h\napp-zabbcf976-74f969f848-kzp87 1/1 Running 0 29h\n")),Object(r.b)("p",null,"The same principle goes for finding the right application pod. Go to the application page on the Qovery console."),Object(r.b)("p",null,"You'll get an URL looking like this:"),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"https://console.qovery.com/platform/organization//projects//environments//applications/abbcf976-27a1-4531-9cdd-e4d15d7b2c27/summary")),Object(r.b)("p",null,"Get the short ID of our application, in our case ",Object(r.b)("inlineCode",{parentName:"p"},"abbcf976")," which means the application pod name will start with ",Object(r.b)("inlineCode",{parentName:"p"},"app-zabbcf976"),"."),Object(r.b)("p",null,"In case you setup your app to run multiple replicas, it is possible that you see several pods begining with the same string. You can pick any of them."),Object(r.b)("p",null,"In our case the right pod corresponding to our application would be ",Object(r.b)("inlineCode",{parentName:"p"},"app-zabbcf976-74f969f848-kzp87"),".")),Object(r.b)("li",null,Object(r.b)("h4",{id:"shell-into-the-container"},"Shell into the container"),Object(r.b)("p",null,"To get a shell access to the container running inside the application pod, all you have to do is:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl exec -ti --namespace -- sh\n")),Object(r.b)("p",null,"This will open a shell inside of your application container. You can now execute any command you need.")))),Object(r.b)("h2",{id:"conclusion"},"Conclusion"),Object(r.b)("p",null,"Qovery helps you manage your Kubernetes cluster and deploy your applications on it while still giving you the power of a full access to your cluster."),Object(r.b)(i.a,{type:"note",mdxType:"Alert"},"Soon you will be able to achieve the same thing through the Qovery CLI."))}d.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),b=s(n),d=o,m=b["".concat(c,".").concat(d)]||b[d]||p[d]||r;return n?a.a.createElement(m,i({ref:t},u,{components:n})):a.a.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,c=new Array(r);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var u=2;u1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>i;)t[i++]=e;return t}},428:function(e,t,n){var o=n(28).f,a=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in a||n(10)&&o(a,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var o=n(0),a=n.n(o),r=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var o=n(1),a=n(0),r=n.n(a),c=n(39),i=n(432),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,b=Object(i.a)(s),p=Object(a.useRef)(!1),d=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(s),function(){d&&t&&t.disconnect()}}),[s,d,b]),s&&b?r.a.createElement(c.b,Object(o.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,o;d&&e&&b&&(n=e,o=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:s})):r.a.createElement("a",Object(o.a)({},e,{href:s}))}},431:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=n(430),c=n(423),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,c=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,b=e.to,p=i()("jump-to","jump-to--"+u,n),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},c&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+c})),a.a.createElement("div",{className:"jump-to--main"},o?a.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?a.a.createElement("a",{href:b,target:s,className:p},d):a.a.createElement(r.a,{to:b,className:p},d)}},432:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},433:function(e,t,n){"use strict";var o=n(435),a=n(51);function r(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),r=t.length>0?t.join("="):void 0;r=void 0===r?null:decodeURIComponent(r),n(decodeURIComponent(a),r,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[r(t,e),"[",o,"]"].join(""):[r(t,e),"[",r(o,e),"]=",r(n,e)].join("")};case"bracket":return function(t,n){return null===n?r(t,e):[r(t,e),"[]=",r(n,e)].join("")};default:return function(t,n){return null===n?r(t,e):[r(t,e),"=",r(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var a=e[o];if(void 0===a)return"";if(null===a)return r(o,t);if(Array.isArray(a)){var c=[];return a.slice().forEach((function(e){void 0!==e&&c.push(n(o,e,c.length))})),c.join("&")}return r(o,t)+"="+r(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=(n(423),n(433)),c=n.n(r);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,r=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(o.useState)(null),b=s[0],p=s[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!r&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/83a41d86.d6e153cb.js.LICENSE.txt b/7aa59ca3.81639c91.js.LICENSE.txt similarity index 100% rename from 83a41d86.d6e153cb.js.LICENSE.txt rename to 7aa59ca3.81639c91.js.LICENSE.txt diff --git a/7df50433.2cb08e4d.js b/7df50433.88abe9cc.js similarity index 96% rename from 7df50433.2cb08e4d.js rename to 7df50433.88abe9cc.js index a3cc698da5..bac7f04a7c 100644 --- a/7df50433.2cb08e4d.js +++ b/7df50433.88abe9cc.js @@ -1,2 +1,2 @@ -/*! For license information please see 7df50433.2cb08e4d.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[127],{278:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return p}));var a=n(1),o=n(9),r=(n(0),n(422)),i=n(431),c={last_modified_on:"2023-05-09",title:"Webhooks",description:"Learn how to use Qovery Webhooks"},l={id:"using-qovery/integration/webhook",title:"Webhooks",description:"Learn how to use Qovery Webhooks",source:"@site/docs/using-qovery/integration/webhook.md",permalink:"/docs/using-qovery/integration/webhook",sidebar:"docs",previous:{title:"AWS Secrets Manager",permalink:"/docs/using-qovery/integration/secret-manager/aws-secrets-manager"},next:{title:"API",permalink:"/docs/using-qovery/integration/api-integration"}},b=[{value:"Creating a Webhook",id:"creating-a-webhook",children:[]},{value:"Editing a Webhook",id:"editing-a-webhook",children:[]},{value:"Delete a Webhook",id:"delete-a-webhook",children:[]},{value:"Webhook payload",id:"webhook-payload",children:[{value:"Deployment payload",id:"deployment-payload",children:[]}]}],s={rightToc:b};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Qovery allows you to create webhooks at organization-level so that, when an event happens on an environment within your organization, you can get notified on external applications."),Object(r.b)("p",null,"This is useful for the following use cases:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"integrate Qovery with an exeternal tool that needs to be informed when the deployment status changes."),Object(r.b)("li",{parentName:"ul"},"share within a slack channel any deployment status change for your environments.")),Object(r.b)("p",null,"You can trigger webhooks when:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"A deployment has started in the environment."),Object(r.b)("li",{parentName:"ul"},"A deployment has been successful in the environment."),Object(r.b)("li",{parentName:"ul"},"A deployment has been cancelled in the environment."),Object(r.b)("li",{parentName:"ul"},"A deployment has failed in the environment.")),Object(r.b)("p",null,"Two types of webhooks can be created within Qovery:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"Standard"),": this type of webhook will send a payload to the defined url with a Qovery proprietary format (check out our ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"#webhook-payload"}),"Webhook payload")," documentation for more information on the payload format)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"Slack"),": this type of webhook will send pre-formatted messages using the Slack messaging syntax. Have a look at our ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/integration/slack/"}),"Slack integration")," for more information on the integration.")),Object(r.b)("h2",{id:"creating-a-webhook"},"Creating a Webhook"),Object(r.b)("p",null,"To create a webhook via the Qovery Console:"),Object(r.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,Object(r.b)("p",null,"Open the Organization settings and the Webhook section"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/integration/webhook/webhook_access.png",alt:"Access webhook section"}))),Object(r.b)("li",null,Object(r.b)("p",null,"Press the ",Object(r.b)("inlineCode",{parentName:"p"},"Add New")," button.")),Object(r.b)("li",null,Object(r.b)("p",null,"Enter the following parameters:"),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Parameter"),Object(r.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Usage"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},"URL")),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"The webhook URL provided by the external application you want to receive notifications on.")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},'"kind"')),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Specify which kind of webhook you want to create. At the moment, you can specify : ",Object(r.b)("inlineCode",{parentName:"td"},'"kind": "STANDARD"')," to create a generic webhook, or ",Object(r.b)("inlineCode",{parentName:"td"},'"kind": "SLACK"')," to create ",Object(r.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/integration/slack/"}),"a Slack webhook"),".")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},'"description"')),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("em",{parentName:"td"},"(Optional)")," Enter a self-explanatory description of what your webhook does. In the example, ",Object(r.b)("inlineCode",{parentName:"td"},'"description": "slack notifications"')," clearly states that the webhook triggers notifications on Slack.")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},'"secret"')),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("em",{parentName:"td"},"(Optional)")," Specify the secret to be used when calling the specified webhook URL")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},'"events"')),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"List all the events you want to be notified about.")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},'"environment_types_filter"')),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("em",{parentName:"td"},"(Optional)")," If you only want to get notified about events happening on one or several specific type(s) or environment(s), you can provide a list using the following possible values: ",Object(r.b)("inlineCode",{parentName:"td"},'"PRODUCTION"'),", ",Object(r.b)("inlineCode",{parentName:"td"},'"DEVELOPMENT"'),", ",Object(r.b)("inlineCode",{parentName:"td"},'"STAGING"')," and ",Object(r.b)("inlineCode",{parentName:"td"},'"PREVIEW"'),". ",Object(r.b)("br",null)," ",Object(r.b)("br",null)," Please note that ",Object(r.b)("inlineCode",{parentName:"td"},'"environment_types_filter"')," can be used together with ",Object(r.b)("inlineCode",{parentName:"td"},'"project_names_filter"'),".")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("inlineCode",{parentName:"td"},'"project_names_filter"')),Object(r.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(r.b)("em",{parentName:"td"},"(Optional)")," If you only want to get notified about events happening in one or several specific projects, you can provide a list of project names that will act as a filter. Notifications will then only be triggered for projects whose names match or, if you're using a wildcard, start with one of the values from your list. ",Object(r.b)("br",null)," ",Object(r.b)("br",null)," Please note that ",Object(r.b)("inlineCode",{parentName:"td"},'"project_names_filter"')," is not case-sensitive, accepts wildcards, and can be used together with ",Object(r.b)("inlineCode",{parentName:"td"},'"environment_types_filter"'),".")))),Object(r.b)("p",null,"And press the ",Object(r.b)("inlineCode",{parentName:"p"},"Create")," button.")))),Object(r.b)("h2",{id:"editing-a-webhook"},"Editing a Webhook"),Object(r.b)("p",null,"From the webhook page, press the ",Object(r.b)("inlineCode",{parentName:"p"},"Wheel")," button to edit the webhook."),Object(r.b)("p",null,"If you want to temporally disable the webhook, you can disable it by clicking on the ",Object(r.b)("inlineCode",{parentName:"p"},"Enable")," switch."),Object(r.b)("h2",{id:"delete-a-webhook"},"Delete a Webhook"),Object(r.b)("p",null,"From the webhook page, press the ",Object(r.b)("inlineCode",{parentName:"p"},"Bin")," button to delete the webhook. A confirmation modal will ask you to confirm the operation."),Object(r.b)("h2",{id:"webhook-payload"},"Webhook payload"),Object(r.b)("p",null,"Here is an example of a Qovery Webhook standard payload. The payload is sent as a ",Object(r.b)("inlineCode",{parentName:"p"},"POST")," request to the specified URL."),Object(r.b)("h3",{id:"deployment-payload"},"Deployment payload"),Object(r.b)("p",null,"This payload is sent when a deployment starts, is cancelled, is successful or fails."),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'{\n "created_at": "2020-10-04T14:00:00.000Z",\n "event_type": "DEPLOYMENT_STARTED|DEPLOYMENT_CANCELLED|DEPLOYMENT_SUCCESSFUL|DEPLOYMENT_FAILURE",\n "payload_type": "DEPLOYMENT", // no other option at the moment\n "payload_id": "5f7a5b0c-7b7d-4b0a-8b0a-5f7a5b0c7b7d",\n "payload": {\n "id": "5f7a5b0c-7b7d-4b0a-8b0a-5f7a5b0c7b7d",\n "current_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml\n "desired_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml\n "organization": {...}, // doc: https://api-doc.qovery.com/#tag/Organization-Main-Calls/operation/getOrganization\n "project": {...}, // doc: https://api-doc.qovery.com/#tag/Project-Main-Calls/operation/getProject\n "environment": {...}, // doc: https://api-doc.qovery.com/#tag/Environment-Main-Calls/operation/getEnvironment\n "applications": [\n {\n "current_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml\n "desired_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml\n "application": {...} // doc: https://api-doc.qovery.com/#tag/Application-Main-Calls/operation/getApplication\n }\n ],\n "databases": [\n {\n "current_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml\n "desired_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml\n "database": {...} // doc: https://api-doc.qovery.com/#tag/Database-Main-Calls/operation/getDatabase\n }\n ],\n "containers": [\n {\n "current_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml\n "desired_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml\n "container": {...} // doc: https://api-doc.qovery.com/#tag/Container-Main-Calls/operation/getContainer\n }\n ],\n "jobs": [\n {\n "current_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml\n "desired_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml\n "job": {...} // doc: https://api-doc.qovery.com/#tag/Job-Main-Calls/operation/getJob\n }\n ],\n "logs": [...] // doc: https://api-doc.qovery.com/#tag/Environment-Logs/operation/listEnvironmentLog\n }\n}\n')))}p.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var b=o.a.createContext({}),s=function(e){var t=o.a.useContext(b),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=s(e.components);return o.a.createElement(b.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,i=e.parentName,b=l(e,["components","mdxType","originalType","parentName"]),p=s(n),d=a,m=p["".concat(i,".").concat(d)]||p[d]||u[d]||r;return n?o.a.createElement(m,c({ref:t},b,{components:n})):o.a.createElement(m,c({ref:t},b))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var b=2;b=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var b=o.a.createContext({}),s=function(e){var t=o.a.useContext(b),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=s(e.components);return o.a.createElement(b.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,i=e.parentName,b=l(e,["components","mdxType","originalType","parentName"]),p=s(n),d=a,m=p["".concat(i,".").concat(d)]||p[d]||u[d]||r;return n?o.a.createElement(m,c({ref:t},b,{components:n})):o.a.createElement(m,c({ref:t},b))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var b=2;b=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=o.a.createContext({}),p=function(e){var t=o.a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},l=function(e){var t=p(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},y={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,a=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),l=p(r),f=n,g=l["".concat(a,".").concat(f)]||l[f]||y[f]||i;return r?o.a.createElement(g,c({ref:t},s,{components:r})):o.a.createElement(g,c({ref:t},s))}));function g(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,a=new Array(i);a[0]=f;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,a[1]=c;for(var s=2;s=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=o.a.createContext({}),p=function(e){var t=o.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},l=function(e){var t=p(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},y={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,a=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),l=p(r),f=n,g=l["".concat(a,".").concat(f)]||l[f]||y[f]||i;return r?o.a.createElement(g,c({ref:t},u,{components:r})):o.a.createElement(g,c({ref:t},u))}));function g(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,a=new Array(i);a[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,a[1]=c;for(var u=2;u"\n logGroupName: "/aws/eks/fluentbit-/logs"\n logRetentionDays: 7\n\nenv:\n - name: "AWS_ACCESS_KEY_ID"\n value: ""\n - name: "AWS_SECRET_ACCESS_KEY"\n value: ""\n\nfirehose:\n enabled: false\n\nkinesis:\n enabled: false\n\nelasticsearch:\n enabled: false\n')),Object(r.b)("p",null,"You can take a look at additional configuration options on the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://artifacthub.io/packages/helm/aws/aws-for-fluent-bit"}),"AWS provided chart")," "),Object(r.b)("p",null,"Then deploy fluent-bit with the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install aws-for-fluent-bit -f values.yaml --namespace fluent-bit --create-namespace eks/aws-for-fluent-bit --version 0.1.21\n")),Object(r.b)("p",null,"You should start seeing fluent-bit pods. Take a look at the logs to ensure there is no configuration issue."),Object(r.b)("h2",{id:"cloudwatch-usage"},"Cloudwatch usage"),Object(r.b)("p",null,"You can now use Cloudwatch to look at your logs. Connect to Cloudwatch, go into the ",Object(r.b)("inlineCode",{parentName:"p"},"Logs insight")," section, then you can perform queries:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-cloudwatch/cloudwatch-search.png",alt:"cloudwatch search"})),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Select the fluent-bit group of logs"),Object(r.b)("li",{parentName:"ol"},"Create a query (",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html"}),"syntax examples"),")"),Object(r.b)("li",{parentName:"ol"},"Run your query"),Object(r.b)("li",{parentName:"ol"},"See the result and expand to filter on other elements")))}p.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),u=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=a,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||r;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:o(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var a=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&a(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),o=n.n(a),r=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),o=n(0),r=n.n(o),i=n(39),c=n(430),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,p=Object(c.a)(u),b=Object(o.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?r.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,a;d&&e&&p&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):r.a.createElement("a",Object(a.a)({},e,{href:u}))}},429:function(e,t,n){"use strict";var a=n(0),o=n.n(a),r=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+s,n),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},a?o.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?o.a.createElement("a",{href:p,target:u,className:b},d):o.a.createElement(r.a,{to:p,className:b},d)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see 83a41d86.5edd2c35.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[131],{282:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var a=n(1),o=n(9),r=(n(0),n(425)),i=(n(431),n(424)),c=(n(429),{last_modified_on:"2022-11-16",$schema:"/.meta/.schemas/guides.json",title:"Integrate your application logs to Cloudwatch",description:"Add Kubernetes pod logs into Cloudwatch to perform full text search",author_github:"https://github.com/deimosfr",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Integrate your application logs to Cloudwatch",description:"Add Kubernetes pod logs into Cloudwatch to perform full text search",permalink:"/guides/tutorial/cloudwatch-integration",readingTime:"4 min read",source:"@site/guides/tutorial/cloudwatch-integration.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Integrate your application logs to Cloudwatch",truncated:!1,prevItem:{title:"Install Qovery your Google Cloud Platform account",permalink:"/guides/cloud-provider/guide-google-cloud-platform"},nextItem:{title:"Kubernetes observability and monitoring with Datadog",permalink:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog"}},s=[{value:"AWS permissions for Cloudwatch",id:"aws-permissions-for-cloudwatch",children:[]},{value:"Helm",id:"helm",children:[]},{value:"Cloudwatch usage",id:"cloudwatch-usage",children:[]}],u={rightToc:s};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Qovery provides by default an easy way to get access to your logs through the Console or the CLI. For statistics, debugging or security reasons, you may want to access all logs and perform a full-text search inside them."),Object(r.b)("p",null,"Qovery implementation is based on ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://grafana.com/oss/loki/"}),"Loki")," for performance and cost-effective reasons. However, Loki is not a full-text search engine. It is a log aggregation system. It is not designed to be queried directly."),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Why Qovery does not provides current Loki access?"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"As mentioned Loki is not a full-text search and results may not reflect what you are looking for."),Object(r.b)("li",{parentName:"ol"},"Loki is configured to answer usage from Qovery Console and CLI. Using it directly may impact Qovery Console and CLI performances or worst, lose logs and make it irresponsive."))),Object(r.b)("p",null,"Serveral solutions exists, with and without 3rd parties. We will cover here a solution without a third party. But if you're interrested, you can take a look at ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/"}),"Datadog integration"),"."),Object(r.b)("p",null,"Note: in this tutorial, we are using Fluent-bit with proposed solutions above. However, if none of those solutions suits your needs, feel free to look at supported solution on the official website."),Object(r.b)("h2",{id:"aws-permissions-for-cloudwatch"},"AWS permissions for Cloudwatch"),Object(r.b)("p",null,"We will create a dedicated service account (note: STS account can be used, but for simplicity reasons, we will use a dedicated service account)."),Object(r.b)("p",null,"On IAM create a policy with the following permissions, and name this policy ",Object(r.b)("inlineCode",{parentName:"p"},"fluent-bit-write-policy"),":"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-policy-content.png",alt:"policy content"})),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Sid": "CloudWatchLogs",\n "Effect": "Allow",\n "Action": [\n "logs:CreateLogGroup",\n "logs:CreateLogStream",\n "logs:PutRetentionPolicy",\n "logs:PutLogEvents"\n ],\n "Resource": "arn:aws:logs:*:*:*"\n }\n ]\n}\n')),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-policy-create.png",alt:"policy create"})),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can enforce this policy by cluster if you need, by updating the ",Object(r.b)("inlineCode",{parentName:"p"},"Resource")," content. But we want to keep it simple in this tutorial, so we will apply it to all clusters (so you can reuse the same service account if you want for other clusters).")),Object(r.b)("p",null,"Once done, let's create a user and attach the policy to it:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-user-create.png",alt:"User create"})),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-cloudwatch-permissions.png",alt:"User permissions"})),Object(r.b)("p",null,"Finish the user creation and keep credentials for the coming section."),Object(r.b)("h2",{id:"helm"},"Helm"),Object(r.b)("p",null,"Ensure you have the following elements before going ahead:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Helm should be installed on your machine. If you don't have it, you can follow the ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://helm.sh/docs/intro/install/"}),"official documentation"),"."),Object(r.b)("li",{parentName:"ol"},"You need Kubeconfig configuration file and permissions to access the cluster. You can use the same documentation as kubectl to ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"get the kubeconfig file"),".")),Object(r.b)("p",null,"We will use ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://artifacthub.io/packages/helm/aws/aws-for-fluent-bit"}),"AWS fluent-bit Helm Chart")," to setup logs streaming:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add eks https://aws.github.io/eks-charts\n")),Object(r.b)("p",null,"Create on your workstation a ",Object(r.b)("inlineCode",{parentName:"p"},"values.yaml")," file to setup your custom configuration and adapt required fields:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'cloudWatch:\n enabled: true\n region: ""\n logGroupName: "/aws/eks/fluentbit-/logs"\n logRetentionDays: 7\n\nenv:\n - name: "AWS_ACCESS_KEY_ID"\n value: ""\n - name: "AWS_SECRET_ACCESS_KEY"\n value: ""\n\nfirehose:\n enabled: false\n\nkinesis:\n enabled: false\n\nelasticsearch:\n enabled: false\n')),Object(r.b)("p",null,"You can take a look at additional configuration options on the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://artifacthub.io/packages/helm/aws/aws-for-fluent-bit"}),"AWS provided chart")," "),Object(r.b)("p",null,"Then deploy fluent-bit with the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install aws-for-fluent-bit -f values.yaml --namespace fluent-bit --create-namespace eks/aws-for-fluent-bit --version 0.1.21\n")),Object(r.b)("p",null,"You should start seeing fluent-bit pods. Take a look at the logs to ensure there is no configuration issue."),Object(r.b)("h2",{id:"cloudwatch-usage"},"Cloudwatch usage"),Object(r.b)("p",null,"You can now use Cloudwatch to look at your logs. Connect to Cloudwatch, go into the ",Object(r.b)("inlineCode",{parentName:"p"},"Logs insight")," section, then you can perform queries:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-cloudwatch/cloudwatch-search.png",alt:"cloudwatch search"})),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Select the fluent-bit group of logs"),Object(r.b)("li",{parentName:"ol"},"Create a query (",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html"}),"syntax examples"),")"),Object(r.b)("li",{parentName:"ol"},"Run your query"),Object(r.b)("li",{parentName:"ol"},"See the result and expand to filter on other elements")))}p.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),u=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=a,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||r;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:o(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var a=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&a(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),o=n.n(a),r=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),o=n(0),r=n.n(o),i=n(39),c=n(432),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,p=Object(c.a)(u),b=Object(o.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?r.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,a;d&&e&&p&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):r.a.createElement("a",Object(a.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var a=n(0),o=n.n(a),r=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+s,n),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},a?o.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?o.a.createElement("a",{href:p,target:u,className:b},d):o.a.createElement(r.a,{to:p,className:b},d)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/888595cd.6303bca8.js.LICENSE.txt b/83a41d86.5edd2c35.js.LICENSE.txt similarity index 100% rename from 888595cd.6303bca8.js.LICENSE.txt rename to 83a41d86.5edd2c35.js.LICENSE.txt diff --git a/83c60db1.ed1f72ca.js b/83c60db1.90a37d8c.js similarity index 75% rename from 83c60db1.ed1f72ca.js rename to 83c60db1.90a37d8c.js index 3e93ea5521..7c6845cf89 100644 --- a/83c60db1.ed1f72ca.js +++ b/83c60db1.90a37d8c.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[130],{281:function(a){a.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"cloud-provider-scaleway","name":"cloud_provider: scaleway","count":1,"permalink":"/guides/tags/cloud-provider-scaleway"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[132],{283:function(a){a.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"cloud-provider-scaleway","name":"cloud_provider: scaleway","count":1,"permalink":"/guides/tags/cloud-provider-scaleway"}')}}]); \ No newline at end of file diff --git a/83e9e333.fe1c4d8a.js b/83e9e333.6923a815.js similarity index 93% rename from 83e9e333.fe1c4d8a.js rename to 83e9e333.6923a815.js index 52b464dd17..c5bc42d1a9 100644 --- a/83e9e333.fe1c4d8a.js +++ b/83e9e333.6923a815.js @@ -1,2 +1,2 @@ -/*! For license information please see 83e9e333.fe1c4d8a.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[131],{282:function(e,a,t){"use strict";t.r(a);var n=t(0),r=t.n(n),l=t(442),c=(t(283),t(433));a.default=function(){var e=Object(c.a)().siteConfig;return(void 0===e?{}:e).customFields.metadata.team,r.a.createElement(l.a,{title:"Contact",description:"Contact the Qovery and Timber.io team"},r.a.createElement("header",{className:"hero"},r.a.createElement("div",{className:"container container--fluid"},r.a.createElement("h1",null,"Contact"),r.a.createElement("div",{className:"hero--subtitle"},"Qovery is a ",r.a.createElement("a",{href:"https://timber.io"},"Timber.io")," open-source product. You can contact the Qovery & Timber team using any of the options below."))),r.a.createElement("main",null,r.a.createElement("section",null,r.a.createElement("div",{className:"container"},r.a.createElement("div",{className:"row"},r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"mailto:hi@timber.io",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-mail"})),r.a.createElement("div",{className:"panel--title"},"hi@timber.io"),r.a.createElement("div",{className:"panel--description"},"Shoot us an email"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://twitter.com/qoverydotdev",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-twitter"})),r.a.createElement("div",{className:"panel--title"},"@qoverydotdev"),r.a.createElement("div",{className:"panel--description"},"Tweet at us"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-message-circle"})),r.a.createElement("div",{className:"panel--title"},"Chat"),r.a.createElement("div",{className:"panel--description"},"Join our chat"))))))))}},420:function(e,a,t){var n;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],a=0;a0&&r.a.createElement("div",{className:"row footer__links"},r.a.createElement("div",{className:"col col--5 footer__col"},r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement(d.a,{className:"navbar__logo",src:b,alt:"Qovery",width:"150",height:"auto"})),r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),r.a.createElement("div",null,r.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},r.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},r.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},r.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},r.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),o.map((function(e,a){return r.a.createElement("div",{key:a,className:"col footer__col"},null!=e.title?r.a.createElement("h4",{className:"footer__title"},e.title):null,null!=e.items&&Array.isArray(e.items)&&e.items.length>0?r.a.createElement("ul",{className:"footer__items"},e.items.map((function(e,a){return e.html?r.a.createElement("li",{key:a,className:"footer__item",dangerouslySetInnerHTML:{__html:e.html}}):r.a.createElement("li",{key:e.href||e.to,className:"footer__item"},r.a.createElement(Q,e))}))):null)}))),(m||c)&&r.a.createElement("div",{className:"text--center"},m&&m.src&&r.a.createElement("div",{className:"margin-bottom--sm"},m.href?r.a.createElement("a",{href:m.href,target:"_blank",rel:"noopener noreferrer",className:q.a.footerLogoLink},r.a.createElement(A,{alt:m.alt,url:u})):r.a.createElement(A,{alt:m.alt,url:u})),r.a.createElement("small",null,c),r.a.createElement("br",null))))},H=t(459),P=t(460),V=t(3);t(138);a.a=function(e){var a=Object(v.a)().siteConfig,t=void 0===a?{}:a,n=t.favicon,i=(t.tagline,t.title),o=t.themeConfig.image,s=t.url,m=e.children,d=e.title,u=e.noFooter,b=e.description,h=e.image,g=e.keywords,E=(e.permalink,e.version),f=d?d+" | "+i:i,p=h||o,N=s+Object(y.a)(p),_=Object(y.a)(n),k=Object(V.h)(),w=k?"https://docs.qovery.com"+(k.pathname.endsWith("/")?k.pathname:k.pathname+"/"):null;return r.a.createElement(P.a,null,r.a.createElement(H.a,null,r.a.createElement(c.a,null,r.a.createElement("html",{lang:"en"}),r.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),f&&r.a.createElement("title",null,f),f&&r.a.createElement("meta",{property:"og:title",content:f}),n&&r.a.createElement("link",{rel:"shortcut icon",href:_}),b&&r.a.createElement("meta",{name:"description",content:b}),b&&r.a.createElement("meta",{property:"og:description",content:b}),E&&r.a.createElement("meta",{name:"docsearch:version",content:E}),g&&g.length&&r.a.createElement("meta",{name:"keywords",content:g.join(",")}),p&&r.a.createElement("meta",{property:"og:image",content:N}),p&&r.a.createElement("meta",{property:"twitter:image",content:N}),p&&r.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+f}),w&&r.a.createElement("meta",{property:"og:url",content:w}),r.a.createElement("meta",{name:"twitter:card",content:"summary"}),w&&r.a.createElement("link",{rel:"canonical",href:w})),r.a.createElement(l.a,null),r.a.createElement(I,null),r.a.createElement("div",{className:"main-wrapper"},m),!u&&r.a.createElement(F,null)))}},451:function(e,a,t){"use strict";var n=t(0),r=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});a.a=r}}]); \ No newline at end of file +/*! For license information please see 83e9e333.6923a815.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[133],{284:function(e,a,t){"use strict";t.r(a);var n=t(0),r=t.n(n),l=t(445),c=(t(285),t(436));a.default=function(){var e=Object(c.a)().siteConfig;return(void 0===e?{}:e).customFields.metadata.team,r.a.createElement(l.a,{title:"Contact",description:"Contact the Qovery and Timber.io team"},r.a.createElement("header",{className:"hero"},r.a.createElement("div",{className:"container container--fluid"},r.a.createElement("h1",null,"Contact"),r.a.createElement("div",{className:"hero--subtitle"},"Qovery is a ",r.a.createElement("a",{href:"https://timber.io"},"Timber.io")," open-source product. You can contact the Qovery & Timber team using any of the options below."))),r.a.createElement("main",null,r.a.createElement("section",null,r.a.createElement("div",{className:"container"},r.a.createElement("div",{className:"row"},r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"mailto:hi@timber.io",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-mail"})),r.a.createElement("div",{className:"panel--title"},"hi@timber.io"),r.a.createElement("div",{className:"panel--description"},"Shoot us an email"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://twitter.com/qoverydotdev",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-twitter"})),r.a.createElement("div",{className:"panel--title"},"@qoverydotdev"),r.a.createElement("div",{className:"panel--description"},"Tweet at us"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-message-circle"})),r.a.createElement("div",{className:"panel--title"},"Chat"),r.a.createElement("div",{className:"panel--description"},"Join our chat"))))))))}},423:function(e,a,t){var n;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],a=0;a0&&r.a.createElement("div",{className:"row footer__links"},r.a.createElement("div",{className:"col col--5 footer__col"},r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement(d.a,{className:"navbar__logo",src:b,alt:"Qovery",width:"150",height:"auto"})),r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),r.a.createElement("div",null,r.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},r.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},r.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},r.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},r.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),o.map((function(e,a){return r.a.createElement("div",{key:a,className:"col footer__col"},null!=e.title?r.a.createElement("h4",{className:"footer__title"},e.title):null,null!=e.items&&Array.isArray(e.items)&&e.items.length>0?r.a.createElement("ul",{className:"footer__items"},e.items.map((function(e,a){return e.html?r.a.createElement("li",{key:a,className:"footer__item",dangerouslySetInnerHTML:{__html:e.html}}):r.a.createElement("li",{key:e.href||e.to,className:"footer__item"},r.a.createElement(Q,e))}))):null)}))),(m||c)&&r.a.createElement("div",{className:"text--center"},m&&m.src&&r.a.createElement("div",{className:"margin-bottom--sm"},m.href?r.a.createElement("a",{href:m.href,target:"_blank",rel:"noopener noreferrer",className:q.a.footerLogoLink},r.a.createElement(A,{alt:m.alt,url:u})):r.a.createElement(A,{alt:m.alt,url:u})),r.a.createElement("small",null,c),r.a.createElement("br",null))))},H=t(462),P=t(463),V=t(3);t(138);a.a=function(e){var a=Object(v.a)().siteConfig,t=void 0===a?{}:a,n=t.favicon,i=(t.tagline,t.title),o=t.themeConfig.image,s=t.url,m=e.children,d=e.title,u=e.noFooter,b=e.description,h=e.image,g=e.keywords,E=(e.permalink,e.version),f=d?d+" | "+i:i,p=h||o,N=s+Object(y.a)(p),_=Object(y.a)(n),k=Object(V.h)(),w=k?"https://docs.qovery.com"+(k.pathname.endsWith("/")?k.pathname:k.pathname+"/"):null;return r.a.createElement(P.a,null,r.a.createElement(H.a,null,r.a.createElement(c.a,null,r.a.createElement("html",{lang:"en"}),r.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),f&&r.a.createElement("title",null,f),f&&r.a.createElement("meta",{property:"og:title",content:f}),n&&r.a.createElement("link",{rel:"shortcut icon",href:_}),b&&r.a.createElement("meta",{name:"description",content:b}),b&&r.a.createElement("meta",{property:"og:description",content:b}),E&&r.a.createElement("meta",{name:"docsearch:version",content:E}),g&&g.length&&r.a.createElement("meta",{name:"keywords",content:g.join(",")}),p&&r.a.createElement("meta",{property:"og:image",content:N}),p&&r.a.createElement("meta",{property:"twitter:image",content:N}),p&&r.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+f}),w&&r.a.createElement("meta",{property:"og:url",content:w}),r.a.createElement("meta",{name:"twitter:card",content:"summary"}),w&&r.a.createElement("link",{rel:"canonical",href:w})),r.a.createElement(l.a,null),r.a.createElement(I,null),r.a.createElement("div",{className:"main-wrapper"},m),!u&&r.a.createElement(F,null)))}},454:function(e,a,t){"use strict";var n=t(0),r=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});a.a=r}}]); \ No newline at end of file diff --git a/89de14d0.f93cc991.js.LICENSE.txt b/83e9e333.6923a815.js.LICENSE.txt similarity index 100% rename from 89de14d0.f93cc991.js.LICENSE.txt rename to 83e9e333.6923a815.js.LICENSE.txt diff --git a/888595cd.6303bca8.js b/888595cd.4d31cec8.js similarity index 89% rename from 888595cd.6303bca8.js rename to 888595cd.4d31cec8.js index ca0a15733d..f4895e5b4f 100644 --- a/888595cd.6303bca8.js +++ b/888595cd.4d31cec8.js @@ -1,2 +1,2 @@ -/*! For license information please see 888595cd.6303bca8.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[132],{284:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return l})),r.d(t,"metadata",(function(){return u})),r.d(t,"rightToc",(function(){return s})),r.d(t,"default",(function(){return d}));var n=r(1),a=r(9),o=(r(0),r(422)),i=r(421),c=r(429),l={last_modified_on:"2023-05-20",title:"Secret Manager",description:"Learn how to configure your Secret Manager provider in Qovery",sidebar_label:"hidden",hide_pagination:!0},u={id:"using-qovery/integration/secret-manager",title:"Secret Manager",description:"Learn how to configure your Secret Manager provider in Qovery",source:"@site/docs/using-qovery/integration/secret-manager.md",permalink:"/docs/using-qovery/integration/secret-manager",sidebar_label:"hidden",sidebar:"docs",previous:{title:"New Relic",permalink:"/docs/using-qovery/integration/monitoring/new-relic"},next:{title:"Doppler",permalink:"/docs/using-qovery/integration/secret-manager/doppler"}},s=[{value:"FAQ",id:"faq",children:[{value:"I don't find my Secret Manager provider, what should I do?",id:"i-dont-find-my-secret-manager-provider-what-should-i-do",children:[]},{value:"By using the Qovery Lifecycle Jobs",id:"by-using-the-qovery-lifecycle-jobs",children:[]},{value:"By using kubectl",id:"by-using-kubectl",children:[]},{value:"Do you need help?",id:"do-you-need-help",children:[]}]}],p={rightToc:s};function d(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},p,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)(c.a,{to:"/docs/using-qovery/integration/secret-manager/doppler",mdxType:"Jump"},"Doppler"),Object(o.b)(c.a,{to:"/docs/using-qovery/integration/secret-manager/aws-secrets-manager",mdxType:"Jump"},"AWS Secrets Manager"),Object(o.b)("h2",{id:"faq"},"FAQ"),Object(o.b)("h3",{id:"i-dont-find-my-secret-manager-provider-what-should-i-do"},"I don't find my Secret Manager provider, what should I do?"),Object(o.b)("p",null,"Basically, Qovery relies on Kubernetes to run your apps. Meaning, Qovery will support your secret manager if their maintainers provide a ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://helm.sh"}),"Helm Chart"),"."),Object(o.b)("p",null,"If your secret manager provides a Helm Chart, then you can install it:"),Object(o.b)("h3",{id:"by-using-the-qovery-lifecycle-jobs"},"By using the Qovery Lifecycle Jobs"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Follow ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/guides/tutorial/how-to-deploy-helm-charts/"}),"this guide")," to deploy your Helm Chart with the Qovery Lifecycle Jobs.")),Object(o.b)("h3",{id:"by-using-kubectl"},"By using kubectl"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"Connect to your Qovery Kubernetes cluster"),"."),Object(o.b)("li",{parentName:"ol"},"Install the helm chart.")),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Helm is a Kubernetes package manager.")),Object(o.b)("h3",{id:"do-you-need-help"},"Do you need help?"),Object(o.b)("p",null,"Feel free to open a thread on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community Forum"),". We will be happy to help you."))}d.isMDXComponent=!0},420:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},f=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),f=n,b=p["".concat(i,".").concat(f)]||p[f]||d[f]||o;return r?a.a.createElement(b,c({ref:t},u,{components:r})):a.a.createElement(b,c({ref:t},u))}));function b(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=f;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var u=2;u1?arguments[1]:void 0,r),l=i>2?arguments[2]:void 0,u=void 0===l?r:a(l,r);u>c;)t[c++]=e;return t}},427:function(e,t,r){"use strict";var n=r(1),a=r(0),o=r.n(a),i=r(39),c=r(430),l=r(20),u=r.n(l);t.a=function(e){var t,r=e.to,l=e.href,s=r||l,p=Object(c.a)(s),d=Object(a.useRef)(!1),f=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!f&&p&&window.docusaurus.prefetch(s),function(){f&&t&&t.disconnect()}}),[s,f,p]),s&&p?o.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(s),d.current=!0)},innerRef:function(e){var r,n;f&&e&&p&&(r=e,n=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){r===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:s})):o.a.createElement("a",Object(n.a)({},e,{href:s}))}},429:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(427),i=r(420),c=r.n(i);r(133);t.a=function(e){var t=e.children,r=e.className,n=e.badge,i=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,p=e.to,d=c()("jump-to","jump-to--"+u,r),f=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},n?a.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?a.a.createElement("a",{href:p,target:s,className:d},f):a.a.createElement(o.a,{to:p,className:d},f)}},430:function(e,t,r){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}r.d(t,"a",(function(){return n}))}}]); \ No newline at end of file +/*! For license information please see 888595cd.4d31cec8.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[134],{286:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return l})),r.d(t,"metadata",(function(){return u})),r.d(t,"rightToc",(function(){return s})),r.d(t,"default",(function(){return d}));var n=r(1),a=r(9),o=(r(0),r(425)),i=r(424),c=r(431),l={last_modified_on:"2023-05-20",title:"Secret Manager",description:"Learn how to configure your Secret Manager provider in Qovery",sidebar_label:"hidden",hide_pagination:!0},u={id:"using-qovery/integration/secret-manager",title:"Secret Manager",description:"Learn how to configure your Secret Manager provider in Qovery",source:"@site/docs/using-qovery/integration/secret-manager.md",permalink:"/docs/using-qovery/integration/secret-manager",sidebar_label:"hidden",sidebar:"docs",previous:{title:"New Relic",permalink:"/docs/using-qovery/integration/monitoring/new-relic"},next:{title:"Doppler",permalink:"/docs/using-qovery/integration/secret-manager/doppler"}},s=[{value:"FAQ",id:"faq",children:[{value:"I don't find my Secret Manager provider, what should I do?",id:"i-dont-find-my-secret-manager-provider-what-should-i-do",children:[]},{value:"By using the Qovery Lifecycle Jobs",id:"by-using-the-qovery-lifecycle-jobs",children:[]},{value:"By using kubectl",id:"by-using-kubectl",children:[]},{value:"Do you need help?",id:"do-you-need-help",children:[]}]}],p={rightToc:s};function d(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},p,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)(c.a,{to:"/docs/using-qovery/integration/secret-manager/doppler",mdxType:"Jump"},"Doppler"),Object(o.b)(c.a,{to:"/docs/using-qovery/integration/secret-manager/aws-secrets-manager",mdxType:"Jump"},"AWS Secrets Manager"),Object(o.b)("h2",{id:"faq"},"FAQ"),Object(o.b)("h3",{id:"i-dont-find-my-secret-manager-provider-what-should-i-do"},"I don't find my Secret Manager provider, what should I do?"),Object(o.b)("p",null,"Basically, Qovery relies on Kubernetes to run your apps. Meaning, Qovery will support your secret manager if their maintainers provide a ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://helm.sh"}),"Helm Chart"),"."),Object(o.b)("p",null,"If your secret manager provides a Helm Chart, then you can install it:"),Object(o.b)("h3",{id:"by-using-the-qovery-lifecycle-jobs"},"By using the Qovery Lifecycle Jobs"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Follow ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/guides/tutorial/how-to-deploy-helm-charts/"}),"this guide")," to deploy your Helm Chart with the Qovery Lifecycle Jobs.")),Object(o.b)("h3",{id:"by-using-kubectl"},"By using kubectl"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"Connect to your Qovery Kubernetes cluster"),"."),Object(o.b)("li",{parentName:"ol"},"Install the helm chart.")),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Helm is a Kubernetes package manager.")),Object(o.b)("h3",{id:"do-you-need-help"},"Do you need help?"),Object(o.b)("p",null,"Feel free to open a thread on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community Forum"),". We will be happy to help you."))}d.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},f=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),f=n,b=p["".concat(i,".").concat(f)]||p[f]||d[f]||o;return r?a.a.createElement(b,c({ref:t},u,{components:r})):a.a.createElement(b,c({ref:t},u))}));function b(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=f;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var u=2;u1?arguments[1]:void 0,r),l=i>2?arguments[2]:void 0,u=void 0===l?r:a(l,r);u>c;)t[c++]=e;return t}},430:function(e,t,r){"use strict";var n=r(1),a=r(0),o=r.n(a),i=r(39),c=r(432),l=r(20),u=r.n(l);t.a=function(e){var t,r=e.to,l=e.href,s=r||l,p=Object(c.a)(s),d=Object(a.useRef)(!1),f=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!f&&p&&window.docusaurus.prefetch(s),function(){f&&t&&t.disconnect()}}),[s,f,p]),s&&p?o.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(s),d.current=!0)},innerRef:function(e){var r,n;f&&e&&p&&(r=e,n=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){r===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:s})):o.a.createElement("a",Object(n.a)({},e,{href:s}))}},431:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(430),i=r(423),c=r.n(i);r(133);t.a=function(e){var t=e.children,r=e.className,n=e.badge,i=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,p=e.to,d=c()("jump-to","jump-to--"+u,r),f=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},n?a.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?a.a.createElement("a",{href:p,target:s,className:d},f):a.a.createElement(o.a,{to:p,className:d},f)}},432:function(e,t,r){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}r.d(t,"a",(function(){return n}))}}]); \ No newline at end of file diff --git a/8ae34d0a.e9c2c699.js.LICENSE.txt b/888595cd.4d31cec8.js.LICENSE.txt similarity index 100% rename from 8ae34d0a.e9c2c699.js.LICENSE.txt rename to 888595cd.4d31cec8.js.LICENSE.txt diff --git a/89caf623.8fcc3930.js b/89caf623.099fa5f4.js similarity index 97% rename from 89caf623.8fcc3930.js rename to 89caf623.099fa5f4.js index 13be19c8a6..1afb4ac268 100644 --- a/89caf623.8fcc3930.js +++ b/89caf623.099fa5f4.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[133],{285:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return p})),a.d(t,"metadata",(function(){return d})),a.d(t,"rightToc",(function(){return m})),a.d(t,"default",(function(){return g}));var n=a(1),l=a(9),r=(a(0),a(422)),i=a(431),s=a(434),o=a(441),c=a(421),b=a(426),u=a(429),p={last_modified_on:"2023-04-24",$schema:"/.meta/.schemas/guides.json",title:"Create a blazingly fast REST API in Rust (Part 1/2)",description:"How to create a blazingly fast REST API in Rust, with zero-cost abstraction and very low overhead - Part 1/2",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","language: rust"],hide_pagination:!0},d={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Create a blazingly fast REST API in Rust (Part 1/2)",description:"How to create a blazingly fast REST API in Rust, with zero-cost abstraction and very low overhead - Part 1/2",permalink:"/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1",readingTime:"14 min read",source:"@site/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"language: rust",permalink:"/guides/tags/language-rust"}],title:"Create a blazingly fast REST API in Rust (Part 1/2)",truncated:!1,prevItem:{title:"Costs Control",permalink:"/guides/advanced/costs-control"},nextItem:{title:"Create a Playground Environment on AWS",permalink:"/guides/tutorial/create-a-playground-environment-on-aws"}},m=[{value:"Twitter clone",id:"twitter-clone",children:[{value:"API design",id:"api-design",children:[]}]},{value:"Implementation",id:"implementation",children:[{value:"Actix Web",id:"actix-web",children:[]},{value:"Let's code",id:"lets-code",children:[]},{value:"Validation",id:"validation",children:[]}]},{value:"PostgreSQL",id:"postgresql",children:[{value:"Diesel",id:"diesel",children:[]}]},{value:"Deployment",id:"deployment",children:[{value:"Install Qovery CLI",id:"install-qovery-cli",children:[]},{value:"Sign up",id:"sign-up",children:[]},{value:"Deploying the app",id:"deploying-the-app",children:[]},{value:"Create a new project",id:"create-a-new-project",children:[]},{value:"Create a new environment",id:"create-a-new-environment",children:[]},{value:"Create a new application",id:"create-a-new-application",children:[]},{value:"Deploy a database",id:"deploy-a-database",children:[]},{value:"Configure the connection to the database",id:"configure-the-connection-to-the-database",children:[]}]},{value:"Deploy your application",id:"deploy-your-application",children:[]},{value:"Live test",id:"live-test",children:[]},{value:"What's next",id:"whats-next",children:[]},{value:"Useful resources",id:"useful-resources",children:[]}],h={rightToc:m};function g(e){var t=e.components,a=Object(l.a)(e,["components"]);return Object(r.b)("wrapper",Object(n.a)({},h,a,{components:t,mdxType:"MDXLayout"}),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/rust-lang/www.rust-lang.org/issues/419#issuecomment-443418587"}),"Fast, reliable, productive - Pick three")," | Rust's slogan")),Object(r.b)("p",null,"Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety. Coupled with Actix, I should be able to build a fast REST API elegantly."),Object(r.b)("p",null,"The idea behind this article is to see how performant a Rust API can be. I am going to create an API that saves and reads data from/to a PostgreSQL database."),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,'Most of the Rust REST API tests across the web are "',Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://medium.com/sean3z/rest-api-node-vs-rust-c75aa8c96343"}),"Hello World"),"\" applications. They bench direct API I/O with no payload. It's very far from reality. In the part 2 of this article, I will bench our Rust application with an intensive payload.")),Object(r.b)("p",null,"This article is separate in two parts, in this first part you will learn how to:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Create a blazingly fast REST API in Rust"),Object(r.b)("li",{parentName:"ul"},"Connect it to a PostgreSQL database")),Object(r.b)("p",null,"In the second part, we will compare the performance of our application to a Go application."),Object(r.b)("h2",{id:"twitter-clone"},"Twitter clone"),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.twitter.com"}),"Twitter"),' is a "microblogging" system that allows people to send and receive short posts called tweets.')),Object(r.b)("p",null,"Let's create a small part of the Twitter API to be able to post, read, and like tweets. The goal is to be able to use our Twitter clone with a massive number of simultaneous fake users."),Object(r.b)(b.a,{mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have installed ",Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/rust-lang/cargo"}),"Cargo")," (Rust package manager)"))),Object(r.b)("h3",{id:"api-design"},"API design"),Object(r.b)("p",null,"Our REST API needs to have three endpoints :"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"/tweets"),Object(r.b)("ul",{parentName:"li"},Object(r.b)("li",{parentName:"ul"},"GET: list last 50 tweets"),Object(r.b)("li",{parentName:"ul"},"POST: create a new tweet"))),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"/tweets/:id"),Object(r.b)("ul",{parentName:"li"},Object(r.b)("li",{parentName:"ul"},"GET: find a tweet by its ID"),Object(r.b)("li",{parentName:"ul"},"DELETE: delete a tweet by its ID"))),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"/tweets/:id/likes"),Object(r.b)("ul",{parentName:"li"},Object(r.b)("li",{parentName:"ul"},"GET: list all likes attached to a tweet"),Object(r.b)("li",{parentName:"ul"},"POST: add +1 like to a tweet"),Object(r.b)("li",{parentName:"ul"},"DELETE: add -1 like to a tweet")))),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"For the sake of simplicity, I will not set up a user management service.")),Object(r.b)("h2",{id:"implementation"},"Implementation"),Object(r.b)("p",null,"Even though implementing an HTTP server could be fun, I choose to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://actix.rs/"}),"Actix"),", which is ranked as ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.techempower.com/benchmarks/#section=data-r18&hw=ph&test=fortune"}),"the most performant framework")," ever by ",Object(r.b)("em",{parentName:"p"},"Techempower"),"."),Object(r.b)("h3",{id:"actix-web"},"Actix Web"),Object(r.b)("p",null,"Actix is an actor framework prevalent in the Rust ecosystem. I am using it as an HTTP server to build our REST API."),Object(r.b)("h3",{id:"lets-code"},"Let's code"),Object(r.b)("p",null,"Three files structured our application."),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"main.rs")," to route HTTP requests to the right endpoint"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"tweet.rs")," to handle requests on /tweets"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"like.rs")," to handle requests on /tweets/:id/likes")),Object(r.b)(s.a,{centered:!1,className:"square",defaultValue:"main.rs",select:!1,size:null,values:[{group:"Files",label:"main.rs",value:"main.rs"},{group:"Files",label:"tweet.rs",value:"tweet.rs"},{group:"Files",label:"like.rs",value:"like.rs"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"main.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="main.rs"',title:'"main.rs"'}),'#[actix_rt::main]\nasync fn main() -> io::Result<()> {\n env::set_var("RUST_LOG", "actix_web=debug,actix_server=info");\n env_logger::init();\n\n HttpServer::new(|| {\n App::new()\n // enable logger - always register actix-web Logger middleware last\n .wrap(middleware::Logger::default())\n // register HTTP requests handlers\n .service(tweet::list)\n .service(tweet::get)\n .service(tweet::create)\n .service(tweet::delete)\n .service(like::list)\n .service(like::plus_one)\n .service(like::minus_one)\n })\n .bind("0.0.0.0:9090")?\n .run()\n .await\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/487198ee7b306f36dbab01f40a44345f85387db2/src/main.rs"}),"main.rs source code"))),Object(r.b)(o.a,{value:"tweet.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="tweet.rs"',title:'"tweet.rs"'}),'pub type Tweets = Response;\n\n#[derive(Debug, Deserialize, Serialize)]\npub struct Tweet {\n pub id: String,\n pub created_at: DateTime,\n pub message: String,\n pub likes: Vec,\n}\n\nimpl Tweet {\n pub fn new(message: String) -> Self {\n Self {\n id: Uuid::new_v4().to_string(),\n created_at: Utc::now(),\n message,\n likes: vec![],\n }\n }\n}\n\n#[derive(Debug, Deserialize, Serialize)]\npub struct TweetRequest {\n pub message: Option,\n}\n\nimpl TweetRequest {\n pub fn to_tweet(&self) -> Option {\n match &self.message {\n Some(message) => Some(Tweet::new(message.to_string())),\n None => None,\n }\n }\n}\n\n/// list 50 last tweets `/tweets`\n#[get("/tweets")]\npub async fn list() -> HttpResponse {\n // TODO find the last 50 tweets and return them\n\n let tweets = Tweets { results: vec![] };\n\n HttpResponse::Ok()\n .content_type(APPLICATION_JSON)\n .json(tweets)\n}\n\n/// create a tweet `/tweets`\n#[post("/tweets")]\npub async fn create(tweet_req: Json) -> HttpResponse {\n HttpResponse::Created()\n .content_type(APPLICATION_JSON)\n .json(tweet_req.to_tweet())\n}\n\n/// find a tweet by its id `/tweets/{id}`\n#[get("/tweets/{id}")]\npub async fn get(path: Path<(String,)>) -> HttpResponse {\n // TODO find tweet a tweet by ID and return it\n let found_tweet: Option = None;\n\n match found_tweet {\n Some(tweet) => HttpResponse::Ok()\n .content_type(APPLICATION_JSON)\n .json(tweet),\n None => HttpResponse::NoContent()\n .content_type(APPLICATION_JSON)\n .await\n .unwrap(),\n }\n}\n\n/// delete a tweet by its id `/tweets/{id}`\n#[delete("/tweets/{id}")]\npub async fn delete(path: Path<(String,)>) -> HttpResponse {\n // TODO delete tweet by ID\n // in any case return status 204\n\n HttpResponse::NoContent()\n .content_type(APPLICATION_JSON)\n .await\n .unwrap()\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/487198ee7b306f36dbab01f40a44345f85387db2/src/tweet.rs"}),"tweet.rs source code"))),Object(r.b)(o.a,{value:"like.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="like.rs"',title:'"like.rs"'}),'pub type Likes = Response;\n\n#[derive(Debug, Deserialize, Serialize)]\npub struct Like {\n pub id: String,\n pub created_at: DateTime,\n}\n\nimpl Like {\n pub fn new() -> Self {\n Self {\n id: Uuid::new_v4().to_string(),\n created_at: Utc::now(),\n }\n }\n}\n\n/// list last 50 likes from a tweet `/tweets/{id}/likes`\n#[get("/tweets/{id}/likes")]\npub async fn list(path: Path<(String,)>) -> HttpResponse {\n // TODO find likes by tweet ID and return them\n let likes = Likes { results: vec![] };\n\n HttpResponse::Ok()\n .content_type(APPLICATION_JSON)\n .json(likes)\n}\n\n/// add one like to a tweet `/tweets/{id}/likes`\n#[post("/tweets/{id}/likes")]\npub async fn plus_one(path: Path<(String,)>) -> HttpResponse {\n // TODO add one like to a tweet\n let like = Like::new();\n\n HttpResponse::Created()\n .content_type(APPLICATION_JSON)\n .json(like)\n}\n\n/// remove one like from a tweet `/tweets/{id}/likes`\n#[delete("/tweets/{id}/likes")]\npub async fn minus_one(path: Path<(String,)>) -> HttpResponse {\n // TODO remove one like to a tweet\n HttpResponse::NoContent()\n .content_type(APPLICATION_JSON)\n .await\n .unwrap()\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/487198ee7b306f36dbab01f40a44345f85387db2/src/like.rs"}),"like.rs source code")))),Object(r.b)("p",null,"With only these three files, our application is ready to receive HTTP requests. In a couple of lines, we have a fully operational application. Actix takes care of the low level boilerplate for us."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="Annotation"',title:'"Annotation"'}),'#[get("/tweets")]\n')),Object(r.b)("p",null,"Annotation is a very convenient way to bind a route to the right path."),Object(r.b)("h3",{id:"validation"},"Validation"),Object(r.b)("p",null,"Let's run our application:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="Run our application"',title:'"Run',our:!0,'application"':!0}),"# Go inside the root project directory\n$ cd twitter-clone-rust\n\n# Run the application\n$ cargo run\n")),Object(r.b)("p",null,"And validate that each endpoint with no errors:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="Curl commands to test our API"',title:'"Curl',commands:!0,to:!0,test:!0,our:!0,'API"':!0}),'# list tweets\ncurl http://localhost:9090/tweets\n\n# get a tweet (return status code: 204 because there is no tweet)\ncurl http://localhost:9090/tweets/abc\n\n# create a tweet\ncurl -X POST -d \'{"message": "This is a tweet"}\' -H "Content-type: application/json" http://localhost:9090/tweets\n\n# delete a tweet (return status code: 204 in any case)\ncurl -X DELETE http://localhost:9090/tweets/abc\n\n# list likes from a tweet\ncurl http://localhost:9090/tweets/abc/likes\n\n# add one like to a tweet\ncurl -X POST http://localhost:9090/tweets/abc/likes\n\n# remove one like to a tweet\ncurl -X DELETE http://localhost:9090/tweets/abc/likes\n')),Object(r.b)("p",null,"At this stage, our application works without any database. Let's go more in-depth and connect it to PostgreSQL."),Object(r.b)("h2",{id:"postgresql"},"PostgreSQL"),Object(r.b)("h3",{id:"diesel"},"Diesel"),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://diesel.rs/"}),"Diesel")," is the most popular ORM in Rust to connect to a ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.postgresql.org"}),"PostgreSQL")," database. Combined with Actix, it's a perfect fit to persist in our data. Let's see how we can make that happen. However, Diesel does not support ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/tokio-rs/tokio"}),"tokio")," (the asynchronous engine behind Actix), so we have to run it in separate threads using the web::block function, which offloads blocking code (like Diesel's) to do not block the server's thread."),Object(r.b)(c.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Read the Diesel ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"http://diesel.rs/guides/getting-started/"}),"Getting started")," to generate tables configurations.")),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="schema.rs"',title:'"schema.rs"'}),"table! {\n likes (id) {\n id -> Uuid,\n created_at -> Timestamp,\n tweet_id -> Uuid,\n }\n}\n\ntable! {\n tweets (id) {\n id -> Uuid,\n created_at -> Timestamp,\n message -> Text,\n }\n}\n\njoinable!(likes -> tweets (tweet_id));\n\nallow_tables_to_appear_in_same_query!(\n likes,\n tweets,\n);\n")),Object(r.b)("p",null,"Diesel uses a macro ",Object(r.b)("inlineCode",{parentName:"p"},"table!...")," and an internal DSL to declare the structure of our tables. There is no magic here. The code is compiled and statically linked at the compilation."),Object(r.b)(s.a,{centered:!1,className:"square",defaultValue:"main.rs",select:!1,size:null,values:[{group:"Files",label:"main.rs",value:"main.rs"},{group:"Files",label:"tweet.rs",value:"tweet.rs"},{group:"Files",label:"like.rs",value:"like.rs"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"main.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="main.rs" {6-11,15-16}',title:'"main.rs"',"{6-11,15-16}":!0}),'#[actix_rt::main]\nasync fn main() -> io::Result<()> {\n env::set_var("RUST_LOG", "actix_web=debug,actix_server=info");\n env_logger::init();\n\n // set up database connection pool\n let database_url = env::var("DATABASE_URL").expect("DATABASE_URL");\n let manager = ConnectionManager::::new(database_url);\n let pool = r2d2::Pool::builder()\n .build(manager)\n .expect("Failed to create pool");\n\n HttpServer::new(move || {\n App::new()\n // Set up DB pool to be used with web::Data extractor\n .data(pool.clone())\n // enable logger - always register actix-web Logger middleware last\n .wrap(middleware::Logger::default())\n // register HTTP requests handlers\n .service(tweet::list)\n .service(tweet::get)\n .service(tweet::create)\n .service(tweet::delete)\n .service(like::list)\n .service(like::plus_one)\n .service(like::minus_one)\n })\n .bind("0.0.0.0:9090")?\n .run()\n .await\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/master/src/main.rs"}),"main.rs source code"))),Object(r.b)(o.a,{value:"tweet.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="tweet.rs"',title:'"tweet.rs"'}),"//...\nfn list_tweets(total_tweets: i64, conn: &DBPooledConnection) -> Result {\n use crate::schema::tweets::dsl::*;\n\n let _tweets = match tweets\n .order(created_at.desc())\n .limit(total_tweets)\n .load::(conn)\n {\n Ok(tws) => tws,\n Err(_) => vec![],\n };\n\n Ok(Tweets {\n results: _tweets\n .into_iter()\n .map(|t| t.to_tweet())\n .collect::>(),\n })\n}\n\nfn find_tweet(_id: Uuid, conn: &DBPooledConnection) -> Result {\n use crate::schema::tweets::dsl::*;\n\n let res = tweets.filter(id.eq(_id)).load::(conn);\n match res {\n Ok(tweets_db) => match tweets_db.first() {\n Some(tweet_db) => Ok(tweet_db.to_tweet()),\n _ => Err(Error::NotFound),\n },\n Err(err) => Err(err),\n }\n}\n\nfn create_tweet(tweet: Tweet, conn: &DBPooledConnection) -> Result {\n use crate::schema::tweets::dsl::*;\n\n let tweet_db = tweet.to_tweet_db();\n let _ = diesel::insert_into(tweets).values(&tweet_db).execute(conn);\n\n Ok(tweet_db.to_tweet())\n}\n\nfn delete_tweet(_id: Uuid, conn: &DBPooledConnection) -> Result<(), Error> {\n use crate::schema::tweets::dsl::*;\n\n let res = diesel::delete(tweets.filter(id.eq(_id))).execute(conn);\n match res {\n Ok(_) => Ok(()),\n Err(err) => Err(err),\n }\n}\n//...\n")),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/master/src/tweet.rs"}),"tweet.rs source code"))),Object(r.b)(o.a,{value:"like.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="like.rs"',title:'"like.rs"'}),"//...\npub fn list_likes(_tweet_id: Uuid, conn: &DBPooledConnection) -> Result {\n use crate::schema::likes::dsl::*;\n\n let _likes: Vec = match likes\n .filter(tweet_id.eq(_tweet_id))\n .order(created_at.desc())\n .load::(conn)\n {\n Ok(lks) => lks,\n Err(_) => vec![],\n };\n\n Ok(Likes {\n results: _likes\n .into_iter()\n .map(|l| l.to_like())\n .collect::>(),\n })\n}\n\npub fn create_like(_tweet_id: Uuid, conn: &DBPooledConnection) -> Result {\n use crate::schema::likes::dsl::*;\n\n let like = Like::new();\n let _ = diesel::insert_into(likes)\n .values(like.to_like_db(_tweet_id))\n .execute(conn);\n\n Ok(like)\n}\n\npub fn delete_like(_tweet_id: Uuid, conn: &DBPooledConnection) -> Result<(), Error> {\n use crate::schema::likes::dsl::*;\n\n let _likes = list_likes(_tweet_id, conn);\n\n let like = match &_likes {\n Ok(_likes) if !_likes.results.is_empty() => _likes.results.first(),\n _ => None,\n };\n\n if like.is_none() {\n return Ok(());\n }\n\n let like_id = Uuid::from_str(like.unwrap().id.as_str()).unwrap();\n\n let res = diesel::delete(likes.filter(id.eq(like_id))).execute(conn);\n match res {\n Ok(_) => Ok(()),\n Err(err) => Err(err),\n }\n}\n//...\n")),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/master/src/like.rs"}),"like.rs source code")))),Object(r.b)("h2",{id:"deployment"},"Deployment"),Object(r.b)("p",null,"Qovery is going to help you to deploy your application in a few seconds. Let's deploy our Twitter Clone now."),Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"web",placeholder:"Select your interface",select:!1,size:null,values:[{group:"Interfaces",label:"Web",value:"web"},{group:"Interfaces",label:"CLI",value:"cli"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"web",mdxType:"TabItem"},Object(r.b)("li",null,Object(r.b)("p",null,"Sign in to the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web interface"),"."),Object(r.b)("p",{align:"center"},Object(r.b)("a",{href:"https://onboarding.qovery.com/"},Object(r.b)("img",{src:"/img/Qovery_Sign_Up_Page.jpg",alt:"Qovery Sign-up page"}))))),Object(r.b)(o.a,{value:"cli",mdxType:"TabItem"},Object(r.b)("li",null,Object(r.b)("h3",{id:"install-qovery-cli"},"Install Qovery CLI"),Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"linux",placeholder:"Select your OS",select:!1,size:null,values:[{group:"Platforms",label:"Linux",value:"linux"},{group:"Platforms",label:"MacOS",value:"macos"},{group:"Platforms",label:"Windows",value:"windows"},{group:"Platforms",label:"Docker",value:"docker"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"linux",mdxType:"TabItem"},Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"universal",values:[{label:"*nix",value:"universal"},{label:"Arch Linux",value:"arch"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"universal",mdxType:"TabItem"},Object(r.b)("p",null,"To download and install Qovery CLI on any Linux distribution:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(r.b)(o.a,{value:"arch",mdxType:"TabItem"},Object(r.b)("p",null,"Qovery is part of ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(r.b)(o.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Linux manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(r.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(r.b)(o.a,{value:"macos",mdxType:"TabItem"},Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"homebrew",values:[{label:"Homebrew",value:"homebrew"},{label:"Script",value:"script"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"homebrew",mdxType:"TabItem"},Object(r.b)("p",null,"The common solution to install a command line binary on the MacOS is to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery brew repository\n$ brew tap Qovery/qovery-cli\n\n# Install the CLI\n$ brew install qovery-cli\n"))),Object(r.b)(o.a,{value:"script",mdxType:"TabItem"},Object(r.b)("p",null,"To download and install Qovery CLI from the command line:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(r.b)(o.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Mac OS manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(r.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(r.b)(o.a,{value:"windows",mdxType:"TabItem"},Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"scoop",mdxType:"TabItem"},Object(r.b)("p",null,"The classic way to install binaries on Windows is to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery bucket\n$ scoop bucket add qovery https://github.com/Qovery/scoop-qovery-cli\n\n# Install the CLI\n$ scoop install qovery-cli\n"))),Object(r.b)(o.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Windows manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to\n",Object(r.b)("inlineCode",{parentName:"p"},"C:\\Windows"),".")))),Object(r.b)(o.a,{value:"docker",mdxType:"TabItem"},Object(r.b)("p",null,"Install Docker on your local machine and run the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Pull and Run the latest Qovery CLI\n$ docker run ghcr.io/qovery/qovery-cli:latest help\n")),Object(r.b)("p",null,"Change ",Object(r.b)("inlineCode",{parentName:"p"},"latest")," by the version you want to use. For example, to use the version 0.58.4, run:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ docker run ghcr.io/qovery/qovery-cli:0.58.4 help\n")),Object(r.b)("p",null,"Note: ",Object(r.b)("inlineCode",{parentName:"p"},"ghcr.io")," is the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/pkgs/container/qovery-cli"}),"GitHub Container Registry"),".")))),Object(r.b)("li",null,Object(r.b)("h3",{id:"sign-up"},"Sign up"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"If you are using an environment without access to GUI or a browser, you can use headless authentication instead:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth --headless\n"))),Object(r.b)("p",null,"Your browser window with sign-in options will open."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/qovery_signup.svg",alt:"Qovery Sign-up page"})),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/apps/qovery/installations/new"}),"Click here")," to authorize Qovery to clone and build your applications."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/github_signup.svg",alt:"Connect Github"})),Object(r.b)("p",null,"Congratulations, you are logged-in.")))),Object(r.b)("h3",{id:"deploying-the-app"},"Deploying the app"),Object(r.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,Object(r.b)("h3",{id:"create-a-new-project"},"Create a new project"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/heroku/heroku-2.png",alt:"Migrate from Heroku"}))),Object(r.b)("li",null,Object(r.b)("h3",{id:"create-a-new-environment"},"Create a new environment"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/heroku/heroku-3.png",alt:"Migrate from Heroku"}))),Object(r.b)("li",null,Object(r.b)("h3",{id:"create-a-new-application"},"Create a new application"),Object(r.b)("p",null,"To follow the guide, ",Object(r.b)("a",{href:"https://github.com/evoxmusic/twitter-clone-rust"},"you can fork and use our repository")),Object(r.b)("p",null,"Use the forked repository (and branch ",Object(r.b)("strong",{parentName:"p"},"master"),") while creating the application in the repository field:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/rust/rust.png",alt:"Migrate from Heroku"}))),Object(r.b)("li",null,Object(r.b)("p",null,"After the application is created: "),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Navigate application settings"),Object(r.b)("li",{parentName:"ul"},"Select ",Object(r.b)("strong",{parentName:"li"},"Port")),Object(r.b)("li",{parentName:"ul"},"Add port ",Object(r.b)("strong",{parentName:"li"},"9090"))),Object(r.b)("p",{align:"left"},Object(r.b)("img",{src:"/img/micro/micros-1.png",alt:"Microservices"}))),Object(r.b)("li",null,Object(r.b)("h3",{id:"deploy-a-database"},"Deploy a database"),Object(r.b)("p",null,"Create and deploy a new database"),Object(r.b)(c.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Name the database ",Object(r.b)("strong",{parentName:"p"},"my-pql-db")," to follow the guide flawlessly")),Object(r.b)("p",null,"To learn how to do it, you can ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"follow this guide"))),Object(r.b)("li",null,Object(r.b)("h3",{id:"configure-the-connection-to-the-database"},"Configure the connection to the database"),Object(r.b)("p",null,"In application overview, open the ",Object(r.b)("strong",{parentName:"p"},"Variables")," tab"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/open-env-var.png",alt:"Open Variable"})),Object(r.b)("p",null,"Configure the alias for each built_in environment variable to match the one required within your code"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/alias.png",alt:"Env Var Alias"})),Object(r.b)("p",null,"Have a look at ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-a-database"}),"this section")," to know more on how to connect to a database.")),Object(r.b)("h2",{id:"deploy-your-application"},"Deploy your application"),Object(r.b)("p",null,"All you have to do now is to navigate to your application and click ",Object(r.b)("strong",{parentName:"p"},"Deploy")," button"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/heroku/heroku-1.png",alt:"Deploy App"})),Object(r.b)("p",null,"That's it. Watch the status and wait till the app is deployed."))),Object(r.b)("p",null,"Congratulations, you have deployed your application!"),Object(r.b)("h2",{id:"live-test"},"Live test"),Object(r.b)("p",null,"To open the application in your browser, click on ",Object(r.b)("strong",{parentName:"p"},"Action")," and ",Object(r.b)("strong",{parentName:"p"},"Open")," buttons in your application overview:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/deploy-env-1.png",alt:"Open App"})),Object(r.b)("p",null,"Then, we can test it with the following CURL commands (replace the app URL with your own):"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="Curl commands to test our deployed API"',title:'"Curl',commands:!0,to:!0,test:!0,our:!0,deployed:!0,'API"':!0}),'# create a tweet\ncurl -X POST -d \'{"message": "This is a tweet"}\' -H "Content-type: application/json" https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets\n\n# list tweets\ncurl https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets\n\n# get a tweet\ncurl https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets/\n\n# list likes from a tweet\ncurl https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets//likes\n\n# add one like to a tweet\ncurl -X POST https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets//likes\n\n# remove one like to a tweet\ncurl -X DELETE https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets//likes\n\n# delete a tweet\ncurl -X DELETE https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets/\n')),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/setting-custom-domain/"}),"add your custom domain"))),Object(r.b)("h2",{id:"whats-next"},"What's next"),Object(r.b)("p",null,"In this first part we saw how to create a Rust API with Actix and Diesel. In the second part we will compare its performance with a Go application to see which one is the most performant."),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Special thanks to ",Object(r.b)("a",Object(n.a)({parentName:"strong"},{href:"https://twitter.com/imjasonmiller"}),"Jason")," and ",Object(r.b)("a",Object(n.a)({parentName:"strong"},{href:"https://twitter.com/doctor_code"}),"Kokou")," for your reviews")),Object(r.b)("h2",{id:"useful-resources"},"Useful resources"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/evoxmusic/twitter-clone-rust"}),"Source code"))),Object(r.b)("p",null,"Do you want to know more about Rust?"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://blog.rust-lang.org/inside-rust/"}),"A great blog to follow along with Rust development")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.youtube.com/channel/UC_iD0xppBwwsrM9DegC5cQQ"}),"Jon Gjengset")," - PhD student at MIT in distributed systems and Rust live-coder"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://doc.rust-lang.org/book/"}),"The Rust programming language book")," (Free)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.youtube.com/watch?v=j_4sadjjWh8"}),"My first service in Rust")," (French video - Fran\xe7ois T.)")),Object(r.b)(u.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}g.isMDXComponent=!0},421:function(e,t,a){"use strict";a(423);var n=a(0),l=a.n(n),r=a(420),i=a.n(r);a(132);t.a=function(e){var t=e.children,a=e.classNames,n=e.fill,r=e.icon,s=e.type,o=null;switch(s){case"danger":o="alert-triangle";break;case"success":o="check-circle";break;case"warning":o="alert-triangle";break;default:o="info"}return l.a.createElement("div",{className:i()(a,"alert","alert--"+s,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&l.a.createElement("i",{className:i()("feather","icon-"+(r||o))}),t)}},425:function(e,t,a){var n=a(28).f,l=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in l||a(10)&&n(l,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var n=a(0),l=a.n(n),r=a(421);t.a=function(e){var t=e.children,a=e.name;return l.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},l.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},427:function(e,t,a){"use strict";var n=a(1),l=a(0),r=a.n(l),i=a(39),s=a(430),o=a(20),c=a.n(o);t.a=function(e){var t,a=e.to,o=e.href,b=a||o,u=Object(s.a)(b),p=Object(l.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(l.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?r.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var a,n;d&&e&&u&&(a=e,n=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:b})):r.a.createElement("a",Object(n.a)({},e,{href:b}))}},429:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=a(427),i=a(420),s=a.n(i);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,i=e.leftIcon,o=e.rightIcon,c=e.size,b=e.target,u=e.to,p=s()("jump-to","jump-to--"+c,a),d=l.a.createElement("div",{className:"jump-to--inner"},l.a.createElement("div",{className:"jump-to--inner-2"},i&&l.a.createElement("div",{className:"jump-to--left"},l.a.createElement("i",{className:"feather icon-"+i})),l.a.createElement("div",{className:"jump-to--main"},n?l.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),l.a.createElement("div",{className:"jump-to--right"},l.a.createElement("i",{className:"feather icon-"+(o||"chevron-right")+" arrow"}))));return b?l.a.createElement("a",{href:u,target:b,className:p},d):l.a.createElement(r.a,{to:u,className:p},d)}},430:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},431:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(420),a(428)),i=a.n(r);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,r=e.hideFeedbackQuestion,s="undefined"!=typeof window?window.location:null,o={title:"Tutorial on "+s+" failed",body:"The tutorial on:\n\n"+s+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},c="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(o),b=Object(n.useState)(null),u=b[0],p=b[1];return l.a.createElement("div",{className:"steps steps--h"+a},t,!r&&!u&&l.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",l.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",l.a.createElement("a",{href:c,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&l.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",l.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},434:function(e,t,a){"use strict";var n=a(1),l=(a(439),a(436),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),i=a(446),s=a(420),o=a.n(s),c=a(428),b=a.n(c),u=a(445),p=37,d=39;function m(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,l=e.className,i=e.handleKeydown,s=e.style,c=e.values,b=e.selectedValue,u=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:o()("tabs",l,{"tabs--block":t}),style:s},c.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:o()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return i(u,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function h(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,l=e.size,s=e.values,o=s;if(o[0].group){var c=_.groupBy(o,"group");o=Object.keys(c).map((function(e){return{label:e,options:c[e]}}))}return r.a.createElement(i.a,{className:"react-select-container react-select--"+l,classNamePrefix:"react-select",options:o,isClearable:a,placeholder:t,value:s.find((function(e){return e.value==a})),onChange:function(e){return n(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,a=e.defaultValue,i=e.groupId,s=e.label,o=e.placeholder,c=e.select,g=e.size,w=(e.style,e.values),O=e.urlKey,j=Object(u.a)(),v=j.tabGroupChoices,f=j.setTabGroupChoices,y=Object(l.useState)(a),k=y[0],N=y[1];if(null!=i){var T=v[i];null!=T&&T!==k&&N(T)}var _=function(e){N(e),null!=i&&f(i,e)},I=[],x=function(e,t,a){switch(a.keyCode){case d:!function(e,t){var a=e.indexOf(t)+1;e[a]?e[a].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var a=e.indexOf(t)-1;e[a]?e[a].focus():e[e.length-1].focus()}(e,t)}};return Object(l.useEffect)((function(){if("undefined"!=typeof window&&window.location&&O){var e=b.a.parse(window.location.search);e[O]&&N(e[O])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(g||"md")},s&&r.a.createElement("div",{className:"margin-vert--sm"},s),w.length>1&&(c?r.a.createElement(h,Object(n.a)({changeSelectedValue:_,handleKeydown:x,placeholder:o,selectedValue:k,size:g,tabRefs:I},e)):r.a.createElement(m,Object(n.a)({changeSelectedValue:_,handleKeydown:x,selectedValue:k,tabRefs:I},e)))),l.Children.toArray(t).filter((function(e){return e.props.value===k}))[0])}},441:function(e,t,a){"use strict";var n=a(0),l=a.n(n);t.a=function(e){return l.a.createElement(l.a.Fragment,null,e.children)}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[135],{287:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return p})),a.d(t,"metadata",(function(){return d})),a.d(t,"rightToc",(function(){return m})),a.d(t,"default",(function(){return g}));var n=a(1),l=a(9),r=(a(0),a(425)),i=a(434),s=a(437),o=a(444),c=a(424),b=a(429),u=a(431),p={last_modified_on:"2023-04-24",$schema:"/.meta/.schemas/guides.json",title:"Create a blazingly fast REST API in Rust (Part 1/2)",description:"How to create a blazingly fast REST API in Rust, with zero-cost abstraction and very low overhead - Part 1/2",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","language: rust"],hide_pagination:!0},d={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Create a blazingly fast REST API in Rust (Part 1/2)",description:"How to create a blazingly fast REST API in Rust, with zero-cost abstraction and very low overhead - Part 1/2",permalink:"/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1",readingTime:"14 min read",source:"@site/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"language: rust",permalink:"/guides/tags/language-rust"}],title:"Create a blazingly fast REST API in Rust (Part 1/2)",truncated:!1,prevItem:{title:"Costs Control",permalink:"/guides/advanced/costs-control"},nextItem:{title:"Create a Playground Environment on AWS",permalink:"/guides/tutorial/create-a-playground-environment-on-aws"}},m=[{value:"Twitter clone",id:"twitter-clone",children:[{value:"API design",id:"api-design",children:[]}]},{value:"Implementation",id:"implementation",children:[{value:"Actix Web",id:"actix-web",children:[]},{value:"Let's code",id:"lets-code",children:[]},{value:"Validation",id:"validation",children:[]}]},{value:"PostgreSQL",id:"postgresql",children:[{value:"Diesel",id:"diesel",children:[]}]},{value:"Deployment",id:"deployment",children:[{value:"Install Qovery CLI",id:"install-qovery-cli",children:[]},{value:"Sign up",id:"sign-up",children:[]},{value:"Deploying the app",id:"deploying-the-app",children:[]},{value:"Create a new project",id:"create-a-new-project",children:[]},{value:"Create a new environment",id:"create-a-new-environment",children:[]},{value:"Create a new application",id:"create-a-new-application",children:[]},{value:"Deploy a database",id:"deploy-a-database",children:[]},{value:"Configure the connection to the database",id:"configure-the-connection-to-the-database",children:[]}]},{value:"Deploy your application",id:"deploy-your-application",children:[]},{value:"Live test",id:"live-test",children:[]},{value:"What's next",id:"whats-next",children:[]},{value:"Useful resources",id:"useful-resources",children:[]}],h={rightToc:m};function g(e){var t=e.components,a=Object(l.a)(e,["components"]);return Object(r.b)("wrapper",Object(n.a)({},h,a,{components:t,mdxType:"MDXLayout"}),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/rust-lang/www.rust-lang.org/issues/419#issuecomment-443418587"}),"Fast, reliable, productive - Pick three")," | Rust's slogan")),Object(r.b)("p",null,"Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety. Coupled with Actix, I should be able to build a fast REST API elegantly."),Object(r.b)("p",null,"The idea behind this article is to see how performant a Rust API can be. I am going to create an API that saves and reads data from/to a PostgreSQL database."),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,'Most of the Rust REST API tests across the web are "',Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://medium.com/sean3z/rest-api-node-vs-rust-c75aa8c96343"}),"Hello World"),"\" applications. They bench direct API I/O with no payload. It's very far from reality. In the part 2 of this article, I will bench our Rust application with an intensive payload.")),Object(r.b)("p",null,"This article is separate in two parts, in this first part you will learn how to:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Create a blazingly fast REST API in Rust"),Object(r.b)("li",{parentName:"ul"},"Connect it to a PostgreSQL database")),Object(r.b)("p",null,"In the second part, we will compare the performance of our application to a Go application."),Object(r.b)("h2",{id:"twitter-clone"},"Twitter clone"),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.twitter.com"}),"Twitter"),' is a "microblogging" system that allows people to send and receive short posts called tweets.')),Object(r.b)("p",null,"Let's create a small part of the Twitter API to be able to post, read, and like tweets. The goal is to be able to use our Twitter clone with a massive number of simultaneous fake users."),Object(r.b)(b.a,{mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have installed ",Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/rust-lang/cargo"}),"Cargo")," (Rust package manager)"))),Object(r.b)("h3",{id:"api-design"},"API design"),Object(r.b)("p",null,"Our REST API needs to have three endpoints :"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"/tweets"),Object(r.b)("ul",{parentName:"li"},Object(r.b)("li",{parentName:"ul"},"GET: list last 50 tweets"),Object(r.b)("li",{parentName:"ul"},"POST: create a new tweet"))),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"/tweets/:id"),Object(r.b)("ul",{parentName:"li"},Object(r.b)("li",{parentName:"ul"},"GET: find a tweet by its ID"),Object(r.b)("li",{parentName:"ul"},"DELETE: delete a tweet by its ID"))),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"/tweets/:id/likes"),Object(r.b)("ul",{parentName:"li"},Object(r.b)("li",{parentName:"ul"},"GET: list all likes attached to a tweet"),Object(r.b)("li",{parentName:"ul"},"POST: add +1 like to a tweet"),Object(r.b)("li",{parentName:"ul"},"DELETE: add -1 like to a tweet")))),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"For the sake of simplicity, I will not set up a user management service.")),Object(r.b)("h2",{id:"implementation"},"Implementation"),Object(r.b)("p",null,"Even though implementing an HTTP server could be fun, I choose to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://actix.rs/"}),"Actix"),", which is ranked as ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.techempower.com/benchmarks/#section=data-r18&hw=ph&test=fortune"}),"the most performant framework")," ever by ",Object(r.b)("em",{parentName:"p"},"Techempower"),"."),Object(r.b)("h3",{id:"actix-web"},"Actix Web"),Object(r.b)("p",null,"Actix is an actor framework prevalent in the Rust ecosystem. I am using it as an HTTP server to build our REST API."),Object(r.b)("h3",{id:"lets-code"},"Let's code"),Object(r.b)("p",null,"Three files structured our application."),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"main.rs")," to route HTTP requests to the right endpoint"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"tweet.rs")," to handle requests on /tweets"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"like.rs")," to handle requests on /tweets/:id/likes")),Object(r.b)(s.a,{centered:!1,className:"square",defaultValue:"main.rs",select:!1,size:null,values:[{group:"Files",label:"main.rs",value:"main.rs"},{group:"Files",label:"tweet.rs",value:"tweet.rs"},{group:"Files",label:"like.rs",value:"like.rs"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"main.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="main.rs"',title:'"main.rs"'}),'#[actix_rt::main]\nasync fn main() -> io::Result<()> {\n env::set_var("RUST_LOG", "actix_web=debug,actix_server=info");\n env_logger::init();\n\n HttpServer::new(|| {\n App::new()\n // enable logger - always register actix-web Logger middleware last\n .wrap(middleware::Logger::default())\n // register HTTP requests handlers\n .service(tweet::list)\n .service(tweet::get)\n .service(tweet::create)\n .service(tweet::delete)\n .service(like::list)\n .service(like::plus_one)\n .service(like::minus_one)\n })\n .bind("0.0.0.0:9090")?\n .run()\n .await\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/487198ee7b306f36dbab01f40a44345f85387db2/src/main.rs"}),"main.rs source code"))),Object(r.b)(o.a,{value:"tweet.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="tweet.rs"',title:'"tweet.rs"'}),'pub type Tweets = Response;\n\n#[derive(Debug, Deserialize, Serialize)]\npub struct Tweet {\n pub id: String,\n pub created_at: DateTime,\n pub message: String,\n pub likes: Vec,\n}\n\nimpl Tweet {\n pub fn new(message: String) -> Self {\n Self {\n id: Uuid::new_v4().to_string(),\n created_at: Utc::now(),\n message,\n likes: vec![],\n }\n }\n}\n\n#[derive(Debug, Deserialize, Serialize)]\npub struct TweetRequest {\n pub message: Option,\n}\n\nimpl TweetRequest {\n pub fn to_tweet(&self) -> Option {\n match &self.message {\n Some(message) => Some(Tweet::new(message.to_string())),\n None => None,\n }\n }\n}\n\n/// list 50 last tweets `/tweets`\n#[get("/tweets")]\npub async fn list() -> HttpResponse {\n // TODO find the last 50 tweets and return them\n\n let tweets = Tweets { results: vec![] };\n\n HttpResponse::Ok()\n .content_type(APPLICATION_JSON)\n .json(tweets)\n}\n\n/// create a tweet `/tweets`\n#[post("/tweets")]\npub async fn create(tweet_req: Json) -> HttpResponse {\n HttpResponse::Created()\n .content_type(APPLICATION_JSON)\n .json(tweet_req.to_tweet())\n}\n\n/// find a tweet by its id `/tweets/{id}`\n#[get("/tweets/{id}")]\npub async fn get(path: Path<(String,)>) -> HttpResponse {\n // TODO find tweet a tweet by ID and return it\n let found_tweet: Option = None;\n\n match found_tweet {\n Some(tweet) => HttpResponse::Ok()\n .content_type(APPLICATION_JSON)\n .json(tweet),\n None => HttpResponse::NoContent()\n .content_type(APPLICATION_JSON)\n .await\n .unwrap(),\n }\n}\n\n/// delete a tweet by its id `/tweets/{id}`\n#[delete("/tweets/{id}")]\npub async fn delete(path: Path<(String,)>) -> HttpResponse {\n // TODO delete tweet by ID\n // in any case return status 204\n\n HttpResponse::NoContent()\n .content_type(APPLICATION_JSON)\n .await\n .unwrap()\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/487198ee7b306f36dbab01f40a44345f85387db2/src/tweet.rs"}),"tweet.rs source code"))),Object(r.b)(o.a,{value:"like.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="like.rs"',title:'"like.rs"'}),'pub type Likes = Response;\n\n#[derive(Debug, Deserialize, Serialize)]\npub struct Like {\n pub id: String,\n pub created_at: DateTime,\n}\n\nimpl Like {\n pub fn new() -> Self {\n Self {\n id: Uuid::new_v4().to_string(),\n created_at: Utc::now(),\n }\n }\n}\n\n/// list last 50 likes from a tweet `/tweets/{id}/likes`\n#[get("/tweets/{id}/likes")]\npub async fn list(path: Path<(String,)>) -> HttpResponse {\n // TODO find likes by tweet ID and return them\n let likes = Likes { results: vec![] };\n\n HttpResponse::Ok()\n .content_type(APPLICATION_JSON)\n .json(likes)\n}\n\n/// add one like to a tweet `/tweets/{id}/likes`\n#[post("/tweets/{id}/likes")]\npub async fn plus_one(path: Path<(String,)>) -> HttpResponse {\n // TODO add one like to a tweet\n let like = Like::new();\n\n HttpResponse::Created()\n .content_type(APPLICATION_JSON)\n .json(like)\n}\n\n/// remove one like from a tweet `/tweets/{id}/likes`\n#[delete("/tweets/{id}/likes")]\npub async fn minus_one(path: Path<(String,)>) -> HttpResponse {\n // TODO remove one like to a tweet\n HttpResponse::NoContent()\n .content_type(APPLICATION_JSON)\n .await\n .unwrap()\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/487198ee7b306f36dbab01f40a44345f85387db2/src/like.rs"}),"like.rs source code")))),Object(r.b)("p",null,"With only these three files, our application is ready to receive HTTP requests. In a couple of lines, we have a fully operational application. Actix takes care of the low level boilerplate for us."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="Annotation"',title:'"Annotation"'}),'#[get("/tweets")]\n')),Object(r.b)("p",null,"Annotation is a very convenient way to bind a route to the right path."),Object(r.b)("h3",{id:"validation"},"Validation"),Object(r.b)("p",null,"Let's run our application:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="Run our application"',title:'"Run',our:!0,'application"':!0}),"# Go inside the root project directory\n$ cd twitter-clone-rust\n\n# Run the application\n$ cargo run\n")),Object(r.b)("p",null,"And validate that each endpoint with no errors:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="Curl commands to test our API"',title:'"Curl',commands:!0,to:!0,test:!0,our:!0,'API"':!0}),'# list tweets\ncurl http://localhost:9090/tweets\n\n# get a tweet (return status code: 204 because there is no tweet)\ncurl http://localhost:9090/tweets/abc\n\n# create a tweet\ncurl -X POST -d \'{"message": "This is a tweet"}\' -H "Content-type: application/json" http://localhost:9090/tweets\n\n# delete a tweet (return status code: 204 in any case)\ncurl -X DELETE http://localhost:9090/tweets/abc\n\n# list likes from a tweet\ncurl http://localhost:9090/tweets/abc/likes\n\n# add one like to a tweet\ncurl -X POST http://localhost:9090/tweets/abc/likes\n\n# remove one like to a tweet\ncurl -X DELETE http://localhost:9090/tweets/abc/likes\n')),Object(r.b)("p",null,"At this stage, our application works without any database. Let's go more in-depth and connect it to PostgreSQL."),Object(r.b)("h2",{id:"postgresql"},"PostgreSQL"),Object(r.b)("h3",{id:"diesel"},"Diesel"),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://diesel.rs/"}),"Diesel")," is the most popular ORM in Rust to connect to a ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.postgresql.org"}),"PostgreSQL")," database. Combined with Actix, it's a perfect fit to persist in our data. Let's see how we can make that happen. However, Diesel does not support ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/tokio-rs/tokio"}),"tokio")," (the asynchronous engine behind Actix), so we have to run it in separate threads using the web::block function, which offloads blocking code (like Diesel's) to do not block the server's thread."),Object(r.b)(c.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Read the Diesel ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"http://diesel.rs/guides/getting-started/"}),"Getting started")," to generate tables configurations.")),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="schema.rs"',title:'"schema.rs"'}),"table! {\n likes (id) {\n id -> Uuid,\n created_at -> Timestamp,\n tweet_id -> Uuid,\n }\n}\n\ntable! {\n tweets (id) {\n id -> Uuid,\n created_at -> Timestamp,\n message -> Text,\n }\n}\n\njoinable!(likes -> tweets (tweet_id));\n\nallow_tables_to_appear_in_same_query!(\n likes,\n tweets,\n);\n")),Object(r.b)("p",null,"Diesel uses a macro ",Object(r.b)("inlineCode",{parentName:"p"},"table!...")," and an internal DSL to declare the structure of our tables. There is no magic here. The code is compiled and statically linked at the compilation."),Object(r.b)(s.a,{centered:!1,className:"square",defaultValue:"main.rs",select:!1,size:null,values:[{group:"Files",label:"main.rs",value:"main.rs"},{group:"Files",label:"tweet.rs",value:"tweet.rs"},{group:"Files",label:"like.rs",value:"like.rs"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"main.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="main.rs" {6-11,15-16}',title:'"main.rs"',"{6-11,15-16}":!0}),'#[actix_rt::main]\nasync fn main() -> io::Result<()> {\n env::set_var("RUST_LOG", "actix_web=debug,actix_server=info");\n env_logger::init();\n\n // set up database connection pool\n let database_url = env::var("DATABASE_URL").expect("DATABASE_URL");\n let manager = ConnectionManager::::new(database_url);\n let pool = r2d2::Pool::builder()\n .build(manager)\n .expect("Failed to create pool");\n\n HttpServer::new(move || {\n App::new()\n // Set up DB pool to be used with web::Data extractor\n .data(pool.clone())\n // enable logger - always register actix-web Logger middleware last\n .wrap(middleware::Logger::default())\n // register HTTP requests handlers\n .service(tweet::list)\n .service(tweet::get)\n .service(tweet::create)\n .service(tweet::delete)\n .service(like::list)\n .service(like::plus_one)\n .service(like::minus_one)\n })\n .bind("0.0.0.0:9090")?\n .run()\n .await\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/master/src/main.rs"}),"main.rs source code"))),Object(r.b)(o.a,{value:"tweet.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="tweet.rs"',title:'"tweet.rs"'}),"//...\nfn list_tweets(total_tweets: i64, conn: &DBPooledConnection) -> Result {\n use crate::schema::tweets::dsl::*;\n\n let _tweets = match tweets\n .order(created_at.desc())\n .limit(total_tweets)\n .load::(conn)\n {\n Ok(tws) => tws,\n Err(_) => vec![],\n };\n\n Ok(Tweets {\n results: _tweets\n .into_iter()\n .map(|t| t.to_tweet())\n .collect::>(),\n })\n}\n\nfn find_tweet(_id: Uuid, conn: &DBPooledConnection) -> Result {\n use crate::schema::tweets::dsl::*;\n\n let res = tweets.filter(id.eq(_id)).load::(conn);\n match res {\n Ok(tweets_db) => match tweets_db.first() {\n Some(tweet_db) => Ok(tweet_db.to_tweet()),\n _ => Err(Error::NotFound),\n },\n Err(err) => Err(err),\n }\n}\n\nfn create_tweet(tweet: Tweet, conn: &DBPooledConnection) -> Result {\n use crate::schema::tweets::dsl::*;\n\n let tweet_db = tweet.to_tweet_db();\n let _ = diesel::insert_into(tweets).values(&tweet_db).execute(conn);\n\n Ok(tweet_db.to_tweet())\n}\n\nfn delete_tweet(_id: Uuid, conn: &DBPooledConnection) -> Result<(), Error> {\n use crate::schema::tweets::dsl::*;\n\n let res = diesel::delete(tweets.filter(id.eq(_id))).execute(conn);\n match res {\n Ok(_) => Ok(()),\n Err(err) => Err(err),\n }\n}\n//...\n")),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/master/src/tweet.rs"}),"tweet.rs source code"))),Object(r.b)(o.a,{value:"like.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="like.rs"',title:'"like.rs"'}),"//...\npub fn list_likes(_tweet_id: Uuid, conn: &DBPooledConnection) -> Result {\n use crate::schema::likes::dsl::*;\n\n let _likes: Vec = match likes\n .filter(tweet_id.eq(_tweet_id))\n .order(created_at.desc())\n .load::(conn)\n {\n Ok(lks) => lks,\n Err(_) => vec![],\n };\n\n Ok(Likes {\n results: _likes\n .into_iter()\n .map(|l| l.to_like())\n .collect::>(),\n })\n}\n\npub fn create_like(_tweet_id: Uuid, conn: &DBPooledConnection) -> Result {\n use crate::schema::likes::dsl::*;\n\n let like = Like::new();\n let _ = diesel::insert_into(likes)\n .values(like.to_like_db(_tweet_id))\n .execute(conn);\n\n Ok(like)\n}\n\npub fn delete_like(_tweet_id: Uuid, conn: &DBPooledConnection) -> Result<(), Error> {\n use crate::schema::likes::dsl::*;\n\n let _likes = list_likes(_tweet_id, conn);\n\n let like = match &_likes {\n Ok(_likes) if !_likes.results.is_empty() => _likes.results.first(),\n _ => None,\n };\n\n if like.is_none() {\n return Ok(());\n }\n\n let like_id = Uuid::from_str(like.unwrap().id.as_str()).unwrap();\n\n let res = diesel::delete(likes.filter(id.eq(like_id))).execute(conn);\n match res {\n Ok(_) => Ok(()),\n Err(err) => Err(err),\n }\n}\n//...\n")),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/master/src/like.rs"}),"like.rs source code")))),Object(r.b)("h2",{id:"deployment"},"Deployment"),Object(r.b)("p",null,"Qovery is going to help you to deploy your application in a few seconds. Let's deploy our Twitter Clone now."),Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"web",placeholder:"Select your interface",select:!1,size:null,values:[{group:"Interfaces",label:"Web",value:"web"},{group:"Interfaces",label:"CLI",value:"cli"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"web",mdxType:"TabItem"},Object(r.b)("li",null,Object(r.b)("p",null,"Sign in to the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web interface"),"."),Object(r.b)("p",{align:"center"},Object(r.b)("a",{href:"https://onboarding.qovery.com/"},Object(r.b)("img",{src:"/img/Qovery_Sign_Up_Page.jpg",alt:"Qovery Sign-up page"}))))),Object(r.b)(o.a,{value:"cli",mdxType:"TabItem"},Object(r.b)("li",null,Object(r.b)("h3",{id:"install-qovery-cli"},"Install Qovery CLI"),Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"linux",placeholder:"Select your OS",select:!1,size:null,values:[{group:"Platforms",label:"Linux",value:"linux"},{group:"Platforms",label:"MacOS",value:"macos"},{group:"Platforms",label:"Windows",value:"windows"},{group:"Platforms",label:"Docker",value:"docker"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"linux",mdxType:"TabItem"},Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"universal",values:[{label:"*nix",value:"universal"},{label:"Arch Linux",value:"arch"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"universal",mdxType:"TabItem"},Object(r.b)("p",null,"To download and install Qovery CLI on any Linux distribution:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(r.b)(o.a,{value:"arch",mdxType:"TabItem"},Object(r.b)("p",null,"Qovery is part of ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(r.b)(o.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Linux manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(r.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(r.b)(o.a,{value:"macos",mdxType:"TabItem"},Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"homebrew",values:[{label:"Homebrew",value:"homebrew"},{label:"Script",value:"script"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"homebrew",mdxType:"TabItem"},Object(r.b)("p",null,"The common solution to install a command line binary on the MacOS is to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery brew repository\n$ brew tap Qovery/qovery-cli\n\n# Install the CLI\n$ brew install qovery-cli\n"))),Object(r.b)(o.a,{value:"script",mdxType:"TabItem"},Object(r.b)("p",null,"To download and install Qovery CLI from the command line:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(r.b)(o.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Mac OS manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(r.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(r.b)(o.a,{value:"windows",mdxType:"TabItem"},Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"scoop",mdxType:"TabItem"},Object(r.b)("p",null,"The classic way to install binaries on Windows is to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery bucket\n$ scoop bucket add qovery https://github.com/Qovery/scoop-qovery-cli\n\n# Install the CLI\n$ scoop install qovery-cli\n"))),Object(r.b)(o.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Windows manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to\n",Object(r.b)("inlineCode",{parentName:"p"},"C:\\Windows"),".")))),Object(r.b)(o.a,{value:"docker",mdxType:"TabItem"},Object(r.b)("p",null,"Install Docker on your local machine and run the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Pull and Run the latest Qovery CLI\n$ docker run ghcr.io/qovery/qovery-cli:latest help\n")),Object(r.b)("p",null,"Change ",Object(r.b)("inlineCode",{parentName:"p"},"latest")," by the version you want to use. For example, to use the version 0.58.4, run:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ docker run ghcr.io/qovery/qovery-cli:0.58.4 help\n")),Object(r.b)("p",null,"Note: ",Object(r.b)("inlineCode",{parentName:"p"},"ghcr.io")," is the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/pkgs/container/qovery-cli"}),"GitHub Container Registry"),".")))),Object(r.b)("li",null,Object(r.b)("h3",{id:"sign-up"},"Sign up"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"If you are using an environment without access to GUI or a browser, you can use headless authentication instead:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth --headless\n"))),Object(r.b)("p",null,"Your browser window with sign-in options will open."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/qovery_signup.svg",alt:"Qovery Sign-up page"})),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/apps/qovery/installations/new"}),"Click here")," to authorize Qovery to clone and build your applications."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/github_signup.svg",alt:"Connect Github"})),Object(r.b)("p",null,"Congratulations, you are logged-in.")))),Object(r.b)("h3",{id:"deploying-the-app"},"Deploying the app"),Object(r.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,Object(r.b)("h3",{id:"create-a-new-project"},"Create a new project"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/heroku/heroku-2.png",alt:"Migrate from Heroku"}))),Object(r.b)("li",null,Object(r.b)("h3",{id:"create-a-new-environment"},"Create a new environment"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/heroku/heroku-3.png",alt:"Migrate from Heroku"}))),Object(r.b)("li",null,Object(r.b)("h3",{id:"create-a-new-application"},"Create a new application"),Object(r.b)("p",null,"To follow the guide, ",Object(r.b)("a",{href:"https://github.com/evoxmusic/twitter-clone-rust"},"you can fork and use our repository")),Object(r.b)("p",null,"Use the forked repository (and branch ",Object(r.b)("strong",{parentName:"p"},"master"),") while creating the application in the repository field:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/rust/rust.png",alt:"Migrate from Heroku"}))),Object(r.b)("li",null,Object(r.b)("p",null,"After the application is created: "),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Navigate application settings"),Object(r.b)("li",{parentName:"ul"},"Select ",Object(r.b)("strong",{parentName:"li"},"Port")),Object(r.b)("li",{parentName:"ul"},"Add port ",Object(r.b)("strong",{parentName:"li"},"9090"))),Object(r.b)("p",{align:"left"},Object(r.b)("img",{src:"/img/micro/micros-1.png",alt:"Microservices"}))),Object(r.b)("li",null,Object(r.b)("h3",{id:"deploy-a-database"},"Deploy a database"),Object(r.b)("p",null,"Create and deploy a new database"),Object(r.b)(c.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Name the database ",Object(r.b)("strong",{parentName:"p"},"my-pql-db")," to follow the guide flawlessly")),Object(r.b)("p",null,"To learn how to do it, you can ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"follow this guide"))),Object(r.b)("li",null,Object(r.b)("h3",{id:"configure-the-connection-to-the-database"},"Configure the connection to the database"),Object(r.b)("p",null,"In application overview, open the ",Object(r.b)("strong",{parentName:"p"},"Variables")," tab"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/open-env-var.png",alt:"Open Variable"})),Object(r.b)("p",null,"Configure the alias for each built_in environment variable to match the one required within your code"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/alias.png",alt:"Env Var Alias"})),Object(r.b)("p",null,"Have a look at ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-a-database"}),"this section")," to know more on how to connect to a database.")),Object(r.b)("h2",{id:"deploy-your-application"},"Deploy your application"),Object(r.b)("p",null,"All you have to do now is to navigate to your application and click ",Object(r.b)("strong",{parentName:"p"},"Deploy")," button"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/heroku/heroku-1.png",alt:"Deploy App"})),Object(r.b)("p",null,"That's it. Watch the status and wait till the app is deployed."))),Object(r.b)("p",null,"Congratulations, you have deployed your application!"),Object(r.b)("h2",{id:"live-test"},"Live test"),Object(r.b)("p",null,"To open the application in your browser, click on ",Object(r.b)("strong",{parentName:"p"},"Action")," and ",Object(r.b)("strong",{parentName:"p"},"Open")," buttons in your application overview:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/deploy-env-1.png",alt:"Open App"})),Object(r.b)("p",null,"Then, we can test it with the following CURL commands (replace the app URL with your own):"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="Curl commands to test our deployed API"',title:'"Curl',commands:!0,to:!0,test:!0,our:!0,deployed:!0,'API"':!0}),'# create a tweet\ncurl -X POST -d \'{"message": "This is a tweet"}\' -H "Content-type: application/json" https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets\n\n# list tweets\ncurl https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets\n\n# get a tweet\ncurl https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets/\n\n# list likes from a tweet\ncurl https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets//likes\n\n# add one like to a tweet\ncurl -X POST https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets//likes\n\n# remove one like to a tweet\ncurl -X DELETE https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets//likes\n\n# delete a tweet\ncurl -X DELETE https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets/\n')),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/setting-custom-domain/"}),"add your custom domain"))),Object(r.b)("h2",{id:"whats-next"},"What's next"),Object(r.b)("p",null,"In this first part we saw how to create a Rust API with Actix and Diesel. In the second part we will compare its performance with a Go application to see which one is the most performant."),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Special thanks to ",Object(r.b)("a",Object(n.a)({parentName:"strong"},{href:"https://twitter.com/imjasonmiller"}),"Jason")," and ",Object(r.b)("a",Object(n.a)({parentName:"strong"},{href:"https://twitter.com/doctor_code"}),"Kokou")," for your reviews")),Object(r.b)("h2",{id:"useful-resources"},"Useful resources"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/evoxmusic/twitter-clone-rust"}),"Source code"))),Object(r.b)("p",null,"Do you want to know more about Rust?"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://blog.rust-lang.org/inside-rust/"}),"A great blog to follow along with Rust development")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.youtube.com/channel/UC_iD0xppBwwsrM9DegC5cQQ"}),"Jon Gjengset")," - PhD student at MIT in distributed systems and Rust live-coder"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://doc.rust-lang.org/book/"}),"The Rust programming language book")," (Free)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.youtube.com/watch?v=j_4sadjjWh8"}),"My first service in Rust")," (French video - Fran\xe7ois T.)")),Object(r.b)(u.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}g.isMDXComponent=!0},424:function(e,t,a){"use strict";a(426);var n=a(0),l=a.n(n),r=a(423),i=a.n(r);a(132);t.a=function(e){var t=e.children,a=e.classNames,n=e.fill,r=e.icon,s=e.type,o=null;switch(s){case"danger":o="alert-triangle";break;case"success":o="check-circle";break;case"warning":o="alert-triangle";break;default:o="info"}return l.a.createElement("div",{className:i()(a,"alert","alert--"+s,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&l.a.createElement("i",{className:i()("feather","icon-"+(r||o))}),t)}},428:function(e,t,a){var n=a(28).f,l=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in l||a(10)&&n(l,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var n=a(0),l=a.n(n),r=a(424);t.a=function(e){var t=e.children,a=e.name;return l.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},l.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},430:function(e,t,a){"use strict";var n=a(1),l=a(0),r=a.n(l),i=a(39),s=a(432),o=a(20),c=a.n(o);t.a=function(e){var t,a=e.to,o=e.href,b=a||o,u=Object(s.a)(b),p=Object(l.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(l.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?r.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var a,n;d&&e&&u&&(a=e,n=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:b})):r.a.createElement("a",Object(n.a)({},e,{href:b}))}},431:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=a(430),i=a(423),s=a.n(i);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,i=e.leftIcon,o=e.rightIcon,c=e.size,b=e.target,u=e.to,p=s()("jump-to","jump-to--"+c,a),d=l.a.createElement("div",{className:"jump-to--inner"},l.a.createElement("div",{className:"jump-to--inner-2"},i&&l.a.createElement("div",{className:"jump-to--left"},l.a.createElement("i",{className:"feather icon-"+i})),l.a.createElement("div",{className:"jump-to--main"},n?l.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),l.a.createElement("div",{className:"jump-to--right"},l.a.createElement("i",{className:"feather icon-"+(o||"chevron-right")+" arrow"}))));return b?l.a.createElement("a",{href:u,target:b,className:p},d):l.a.createElement(r.a,{to:u,className:p},d)}},432:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},434:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(423),a(433)),i=a.n(r);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,r=e.hideFeedbackQuestion,s="undefined"!=typeof window?window.location:null,o={title:"Tutorial on "+s+" failed",body:"The tutorial on:\n\n"+s+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},c="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(o),b=Object(n.useState)(null),u=b[0],p=b[1];return l.a.createElement("div",{className:"steps steps--h"+a},t,!r&&!u&&l.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",l.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",l.a.createElement("a",{href:c,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&l.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",l.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},437:function(e,t,a){"use strict";var n=a(1),l=(a(442),a(439),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),i=a(449),s=a(423),o=a.n(s),c=a(433),b=a.n(c),u=a(448),p=37,d=39;function m(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,l=e.className,i=e.handleKeydown,s=e.style,c=e.values,b=e.selectedValue,u=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:o()("tabs",l,{"tabs--block":t}),style:s},c.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:o()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return i(u,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function h(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,l=e.size,s=e.values,o=s;if(o[0].group){var c=_.groupBy(o,"group");o=Object.keys(c).map((function(e){return{label:e,options:c[e]}}))}return r.a.createElement(i.a,{className:"react-select-container react-select--"+l,classNamePrefix:"react-select",options:o,isClearable:a,placeholder:t,value:s.find((function(e){return e.value==a})),onChange:function(e){return n(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,a=e.defaultValue,i=e.groupId,s=e.label,o=e.placeholder,c=e.select,g=e.size,w=(e.style,e.values),O=e.urlKey,j=Object(u.a)(),v=j.tabGroupChoices,f=j.setTabGroupChoices,y=Object(l.useState)(a),k=y[0],N=y[1];if(null!=i){var T=v[i];null!=T&&T!==k&&N(T)}var _=function(e){N(e),null!=i&&f(i,e)},I=[],x=function(e,t,a){switch(a.keyCode){case d:!function(e,t){var a=e.indexOf(t)+1;e[a]?e[a].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var a=e.indexOf(t)-1;e[a]?e[a].focus():e[e.length-1].focus()}(e,t)}};return Object(l.useEffect)((function(){if("undefined"!=typeof window&&window.location&&O){var e=b.a.parse(window.location.search);e[O]&&N(e[O])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(g||"md")},s&&r.a.createElement("div",{className:"margin-vert--sm"},s),w.length>1&&(c?r.a.createElement(h,Object(n.a)({changeSelectedValue:_,handleKeydown:x,placeholder:o,selectedValue:k,size:g,tabRefs:I},e)):r.a.createElement(m,Object(n.a)({changeSelectedValue:_,handleKeydown:x,selectedValue:k,tabRefs:I},e)))),l.Children.toArray(t).filter((function(e){return e.props.value===k}))[0])}},444:function(e,t,a){"use strict";var n=a(0),l=a.n(n);t.a=function(e){return l.a.createElement(l.a.Fragment,null,e.children)}}}]); \ No newline at end of file diff --git a/89de14d0.f93cc991.js b/89de14d0.99ea72b2.js similarity index 88% rename from 89de14d0.f93cc991.js rename to 89de14d0.99ea72b2.js index 6ae789e9dc..c1cbbdd26a 100644 --- a/89de14d0.f93cc991.js +++ b/89de14d0.99ea72b2.js @@ -1,2 +1,2 @@ -/*! For license information please see 89de14d0.f93cc991.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[134],{286:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return c})),t.d(r,"metadata",(function(){return u})),t.d(r,"rightToc",(function(){return s})),t.d(r,"default",(function(){return p}));var n=t(1),o=t(9),a=(t(0),t(422)),i=t(429),c={last_modified_on:"2023-11-25",title:"Provider",description:"Learn how to install Qovery on your provider",sidebar_label:"hidden",hide_pagination:!0},u={id:"using-qovery/configuration/provider",title:"Provider",description:"Learn how to install Qovery on your provider",source:"@site/docs/using-qovery/configuration/provider.md",permalink:"/docs/using-qovery/configuration/provider",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Other Cloud Service Provider",permalink:"/docs/using-qovery/configuration/cloud-service-provider/other-csps"},next:{title:"Kubernetes",permalink:"/docs/using-qovery/configuration/provider/kubernetes"}},s=[],l={rightToc:s};function p(e){var r=e.components,t=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},l,t,{components:r,mdxType:"MDXLayout"}),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/provider/kubernetes/",mdxType:"Jump"},"Kubernetes"))}p.isMDXComponent=!0},420:function(e,r,t){var n;!function(){"use strict";var t={}.hasOwnProperty;function o(){for(var e=[],r=0;r=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=o.a.createContext({}),l=function(e){var r=o.a.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},p=function(e){var r=l(e.components);return o.a.createElement(s.Provider,{value:r},e.children)},f={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},d=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(t),d=n,m=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return t?o.a.createElement(m,c({ref:r},s,{components:t})):o.a.createElement(m,c({ref:r},s))}));function m(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var a=t.length,i=new Array(a);i[0]=d;var c={};for(var u in r)hasOwnProperty.call(r,u)&&(c[u]=r[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s0)&&(r.unobserve(t),r.disconnect(),n())}))}))).observe(t))},to:l})):a.a.createElement("a",Object(n.a)({},e,{href:l}))}},429:function(e,r,t){"use strict";var n=t(0),o=t.n(n),a=t(427),i=t(420),c=t.n(i);t(133);r.a=function(e){var r=e.children,t=e.className,n=e.badge,i=e.leftIcon,u=e.rightIcon,s=e.size,l=e.target,p=e.to,f=c()("jump-to","jump-to--"+s,t),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},n?o.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",r),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return l?o.a.createElement("a",{href:p,target:l,className:f},d):o.a.createElement(a.a,{to:p,className:f},d)}},430:function(e,r,t){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(r,"a",(function(){return n}))}}]); \ No newline at end of file +/*! For license information please see 89de14d0.99ea72b2.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[136],{288:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return c})),t.d(r,"metadata",(function(){return u})),t.d(r,"rightToc",(function(){return s})),t.d(r,"default",(function(){return p}));var n=t(1),o=t(9),a=(t(0),t(425)),i=t(431),c={last_modified_on:"2023-11-25",title:"Provider",description:"Learn how to install Qovery on your provider",sidebar_label:"hidden",hide_pagination:!0},u={id:"using-qovery/configuration/provider",title:"Provider",description:"Learn how to install Qovery on your provider",source:"@site/docs/using-qovery/configuration/provider.md",permalink:"/docs/using-qovery/configuration/provider",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Other Cloud Service Provider",permalink:"/docs/using-qovery/configuration/cloud-service-provider/other-csps"},next:{title:"Kubernetes",permalink:"/docs/using-qovery/configuration/provider/kubernetes"}},s=[],l={rightToc:s};function p(e){var r=e.components,t=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},l,t,{components:r,mdxType:"MDXLayout"}),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/provider/kubernetes/",mdxType:"Jump"},"Kubernetes"))}p.isMDXComponent=!0},423:function(e,r,t){var n;!function(){"use strict";var t={}.hasOwnProperty;function o(){for(var e=[],r=0;r=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=o.a.createContext({}),l=function(e){var r=o.a.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},p=function(e){var r=l(e.components);return o.a.createElement(s.Provider,{value:r},e.children)},f={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},d=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(t),d=n,m=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return t?o.a.createElement(m,c({ref:r},s,{components:t})):o.a.createElement(m,c({ref:r},s))}));function m(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var a=t.length,i=new Array(a);i[0]=d;var c={};for(var u in r)hasOwnProperty.call(r,u)&&(c[u]=r[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s0)&&(r.unobserve(t),r.disconnect(),n())}))}))).observe(t))},to:l})):a.a.createElement("a",Object(n.a)({},e,{href:l}))}},431:function(e,r,t){"use strict";var n=t(0),o=t.n(n),a=t(430),i=t(423),c=t.n(i);t(133);r.a=function(e){var r=e.children,t=e.className,n=e.badge,i=e.leftIcon,u=e.rightIcon,s=e.size,l=e.target,p=e.to,f=c()("jump-to","jump-to--"+s,t),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},n?o.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",r),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return l?o.a.createElement("a",{href:p,target:l,className:f},d):o.a.createElement(a.a,{to:p,className:f},d)}},432:function(e,r,t){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(r,"a",(function(){return n}))}}]); \ No newline at end of file diff --git a/8bfd1931.4d787926.js.LICENSE.txt b/89de14d0.99ea72b2.js.LICENSE.txt similarity index 100% rename from 8bfd1931.4d787926.js.LICENSE.txt rename to 89de14d0.99ea72b2.js.LICENSE.txt diff --git a/8ae34d0a.e9c2c699.js b/8ae34d0a.ee4caedd.js similarity index 94% rename from 8ae34d0a.e9c2c699.js rename to 8ae34d0a.ee4caedd.js index 8508038b9c..e2f8d831bf 100644 --- a/8ae34d0a.e9c2c699.js +++ b/8ae34d0a.ee4caedd.js @@ -1,2 +1,2 @@ -/*! For license information please see 8ae34d0a.e9c2c699.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[135],{287:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return c})),n.d(t,"default",(function(){return u}));var o=n(1),r=n(9),i=(n(0),n(422)),a=(n(429),n(421)),l=(n(426),{last_modified_on:"2023-09-27",title:"Deployment Actions",description:"Learn how to deploy your application"}),s={id:"using-qovery/deployment/deployment-actions",title:"Deployment Actions",description:"Learn how to deploy your application",source:"@site/docs/using-qovery/deployment/deployment-actions.md",permalink:"/docs/using-qovery/deployment/deployment-actions",sidebar:"docs",previous:{title:"Deployment Pipeline",permalink:"/docs/using-qovery/deployment/deployment-pipeline"},next:{title:"Deployment History",permalink:"/docs/using-qovery/deployment/deployment-history"}},c=[{value:"Deployment Actions",id:"deployment-actions",children:[{value:"Deploy",id:"deploy",children:[]},{value:"Redeploy",id:"redeploy",children:[]},{value:"Stop",id:"stop",children:[]},{value:"Restart Service",id:"restart-service",children:[]},{value:"Cancel Deployment",id:"cancel-deployment",children:[]},{value:"Deploy other version",id:"deploy-other-version",children:[]},{value:"Deploy latest version",id:"deploy-latest-version",children:[]}]}],p={rightToc:c};function u(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Qovery allows you to manage the deployment lifecycle of your services and environments via a set of ",Object(i.b)("inlineCode",{parentName:"p"},"Deployment actions")," (example: deploy, redeploy, restart, stop etc..). These actions can be triggered via the Qovery web console, via the Qovery API, via the Qovery CLI or from your CI/CD depending on your integration type."),Object(i.b)("p",null,"You can imagine the deployment lifecycle of a service or environment like a state machine: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"each state is identified by a ",Object(i.b)("inlineCode",{parentName:"li"},"Deployment Status")),Object(i.b)("li",{parentName:"ul"},"the execution of a deployment action will modify the state of the service/environment until it reaches a final status (ok or error)"),Object(i.b)("li",{parentName:"ul"},"the list of allowed ",Object(i.b)("inlineCode",{parentName:"li"},"Deployment action")," depends on the current ",Object(i.b)("inlineCode",{parentName:"li"},"Deployment Status"),". Example: if the deployment status is ",Object(i.b)("inlineCode",{parentName:"li"},"Deployment Ok"),", you can trigger only the action ",Object(i.b)("inlineCode",{parentName:"li"},"Stop"),". This will stop the execution of the service (deployment status ",Object(i.b)("inlineCode",{parentName:"li"},"Stopped"),").")),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Example"),":\nWhen a new application is created within Qovery, the application will have the deployment status ",Object(i.b)("inlineCode",{parentName:"p"},"Ready"),". Once the action ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," is executed on the service, the service will go through the statuses ",Object(i.b)("inlineCode",{parentName:"p"},"Queued"),", ",Object(i.b)("inlineCode",{parentName:"p"},"Building"),", ",Object(i.b)("inlineCode",{parentName:"p"},"Deploying")," and then finally on the status ",Object(i.b)("inlineCode",{parentName:"p"},"Deployed")," (meaning that the application is correctly deployed)."),Object(i.b)("p",null,"You can find the deployment status directly in the Qovery console in the service or environment list:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deployment/deployment_statuses.png",alt:"Deployment Statuses"})),Object(i.b)("p",null,"Note that the deployment status of the environment is built based on the deployment statuses of each service within it."),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Deployment Status and Running Status do not provide the same information. Just because an error arose during deployment does not mean your application is not running anymore. Monitoring both your deployment and service statuses allows you to know exactly which applications are currently running on your platform.\nHave a look at ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/running-and-deployment-statuses/"}),"this section")," for more information")),Object(i.b)("p",null,"You can decide to execute a deployment action on:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"an environment: the action will be executed on each service within the environment. To know more about the deployment order of your services, have a look at the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deployment-pipeline/"}),"Deployment Pipeline")," "),Object(i.b)("li",{parentName:"ul"},"a single service: the action will be executed only on the selected service.")),Object(i.b)("p",null,"The deployment actions are accessible through the ",Object(i.b)("inlineCode",{parentName:"p"},"Play")," button available at service or environment level. "),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deployment/deployment_actions.png",alt:"Deployment Actions"})),Object(i.b)("p",null,"You can trigger the deployment actions via the UI but also via any interface described within ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/"}),"this section"),"."),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"You cannot have two or more deployment actions running at the same time on one environment. Example: you can't trigger the deployment of service A and stop service B at the same time. You need to wait for the deployment of service A to finish before triggering the pause of the service B")),Object(i.b)("h2",{id:"deployment-actions"},"Deployment Actions"),Object(i.b)("p",null,"You can find below a description of each deployment action, including its purpose and the deployment status your environment and/or service will go through."),Object(i.b)("h3",{id:"deploy"},"Deploy"),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," action allows you to create the resource necessary to run your code on your Kubernetes cluster. This action is available only if the service or environment have never been deployed."),Object(i.b)("p",null,"Based on the configuration of your services within, a certain number of ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://kubernetes.io/docs/concepts/workloads/pods/"}),"Pods")," will be created in a dedicated ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/"}),"Namespace")," of the target Kubernetes cluster. "),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"The commit id or tag that will be deployed is the one visible on the interface and not necessarily the latest version (unless the auto-deploy feature is activated)")),Object(i.b)("p",null,"Once triggered, the deployment of a service goes through the following deployment statuses:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"QUEUED")," : the deployment has been queued and it is waiting for the necessary resources to be allocated to manage your request"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"BUILDING")," : the Qovery engine is downloading the git repository and building your code. At the end of this step an image is built and pushed to a registry available on your cloud account. The status will become ",Object(i.b)("strong",{parentName:"li"},"BUILD ERROR")," in case of issues on building your code"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"DEPLOYING")," : the pods are being created on your cluster based on the image built on the previous step. The status will become ",Object(i.b)("strong",{parentName:"li"},"DEPLOYMENT ERROR")," in case of issues on deploying your service. A service is considered un-healthy if the Kubernetes readiness probe check is never OK (more info on ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#before-you-begin"}),"readiness probe"),")."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"DEPLOYMENT OK")," : all the requested pods have been created and the service is correctly running (liveness and readiness probes are ok).")),Object(i.b)("p",null,"If the deployment was triggered on the entire environment, the environment will go through the following deployment statuses:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"QUEUED")," : at least one service is in status ",Object(i.b)("strong",{parentName:"li"},"QUEUED")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"BUILDING")," : at least one service is in status ",Object(i.b)("strong",{parentName:"li"},"BUILDING")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"DEPLOYING")," : at least one service is in status ",Object(i.b)("strong",{parentName:"li"},"DEPLOYING")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"DEPLOYMENT OK")," : at least one service is in status ",Object(i.b)("strong",{parentName:"li"},"DEPLOYMENT OK")," but none of them is in error (",Object(i.b)("strong",{parentName:"li"},"BUILD ERROR")," or ",Object(i.b)("strong",{parentName:"li"},"DEPLOYMENT ERROR"),")"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"DEPLOYMENT ERROR")," : at least one service is in status ",Object(i.b)("strong",{parentName:"li"},"DEPLOYMENT ERROR"))),Object(i.b)("h3",{id:"redeploy"},"Redeploy"),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"Redeploy")," action allows you to update the remote configuration of your services based on their configuration on Qovery side. If any difference exists (vCPU, number of instances, code version etc..), a new set of pod will be created with the new configuration and replace the existing ones. If there are no configuration differences, nothing will happen on the pods running on your cluster (not even a restart, please use the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deployment-actions/#restart-service"}),"Restart Service")," feature).\nThis action is available only if the ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," action has been triggered at least once on the service or environment."),Object(i.b)("p",null,"When replacing the pods of your application, Qovery uses the rolling-restart deployment logic:"),Object(i.b)("p",null,"1) Deploy new version of instance ","#","1."),Object(i.b)("p",null,"2) New version of instance ","#","1 is running => kill previous version of instance ","#","1."),Object(i.b)("p",null,"3) Deploy new version of instance ","#","2."),Object(i.b)("p",null,"4) New version of instance ","#","2 is running => kill previous version of instance ","#","2."),Object(i.b)("p",null,"And so on..."),Object(i.b)("p",null,"You can trigger the re-deployment of a service or of the entire environment. The service or environment goes through the same deployment statuses described in the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deployment-actions/#deploy"}),"deployment section"),". "),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"A redeploy on an environment triggers the deployment of any service in the environment, no matter their previous status (even stopped ones)")),Object(i.b)("h3",{id:"stop"},"Stop"),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"Stop")," action allows you to stop the execution on the cluster of the selected service or environment (deployment status = Stopped). This action is available only if the current deployment status is ",Object(i.b)("inlineCode",{parentName:"p"},"Deployment OK")," or ",Object(i.b)("inlineCode",{parentName:"p"},"Deployment Error"),"."),Object(i.b)("p",null,"The effect on your cluster of the stop operation is different depending on the type of service:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Application, Container, Container DB ")," : Pods of those services are stopped. Any attached storage is preserved"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Cloud provider Managed DB"),": the database is paused (only for AWS, not working on Redis)")),Object(i.b)("h3",{id:"restart-service"},"Restart Service"),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"Restart Service")," action allows you to restart the pods of your service without applying any configuration change. This action is available only if the current deployment status is ",Object(i.b)("inlineCode",{parentName:"p"},"Deployment OK")," and only for a single service."),Object(i.b)("p",null,"Once triggered, the deployment status service goes through the following statuses:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"RESTARTING")," : the request to restart has been received"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"RESTARTED")," : all the pods of the service have been restarted"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"RESTART ERROR")," : Qovery couldn't process the restart request")),Object(i.b)("h3",{id:"cancel-deployment"},"Cancel Deployment"),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"Cancel Deployment")," action allows you to abort any ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," or ",Object(i.b)("inlineCode",{parentName:"p"},"Redeploy")," action. This action is available only if the current deployment status is ",Object(i.b)("inlineCode",{parentName:"p"},"Queued")," or ",Object(i.b)("inlineCode",{parentName:"p"},"Building")," or ",Object(i.b)("inlineCode",{parentName:"p"},"Deploying"),"."),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"The action allows to cancel the operation, not to rollback to the previous state. If during the deployment of services A and B, the ",Object(i.b)("inlineCode",{parentName:"p"},"Cancel Deployment")," action is triggered after that the deployment of service A has been completed, only the deployment of service B will be cancelled (service A will use the new config / version)")),Object(i.b)("h3",{id:"deploy-other-version"},"Deploy other version"),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy other version")," action allows you to deploy a different version for your service. This action is available no matter the deployment status of the service."),Object(i.b)("p",null,"Once you click on the action, this panel will appear, and you will be able to choose the version you wish to update/rollback (either git commit or image Tag)."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deployment/deploy_other_version.png",alt:"Deploy Other Version"})),Object(i.b)("p",null,"By pressing on the Deploy button, a deployment of the service will be triggered using the selected version."),Object(i.b)("h3",{id:"deploy-latest-version"},"Deploy latest version"),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy latest version")," action allows you to deploy the latest version for any of your services within the environment. This action is available no matter the deployment status of the service and only at environment level"),Object(i.b)("p",null,"Once you click on the action, this panel will appear, and you will be able to choose the services you wish to update to the latest version (only for services with source = git repository)."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deployment/deploy_latest_version.png",alt:"Deploy Latest Version"})),Object(i.b)("p",null,"By pressing on the Deploy button, a deployment of the service will be triggered using the selected version."))}u.isMDXComponent=!0},420:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=r.a.createContext({}),p=function(e){var t=r.a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},u=function(e){var t=p(e.components);return r.a.createElement(c.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=p(n),d=o,m=u["".concat(a,".").concat(d)]||u[d]||b[d]||i;return n?r.a.createElement(m,l({ref:t},c,{components:n})):r.a.createElement(m,l({ref:t},c))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:o,a[1]=l;for(var c=2;c1?arguments[1]:void 0,n),s=a>2?arguments[2]:void 0,c=void 0===s?n:r(s,n);c>l;)t[l++]=e;return t}},425:function(e,t,n){var o=n(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var o=n(0),r=n.n(o),i=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var o=n(1),r=n(0),i=n.n(r),a=n(39),l=n(430),s=n(20),c=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,p=n||s,u=Object(l.a)(p),b=Object(r.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&t&&t.disconnect()}}),[p,d,u]),p&&u?i.a.createElement(a.b,Object(o.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(p),b.current=!0)},innerRef:function(e){var n,o;d&&e&&u&&(n=e,o=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:p})):i.a.createElement("a",Object(o.a)({},e,{href:p}))}},429:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=n(427),a=n(420),l=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,a=e.leftIcon,s=e.rightIcon,c=e.size,p=e.target,u=e.to,b=l()("jump-to","jump-to--"+c,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},a&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+a})),r.a.createElement("div",{className:"jump-to--main"},o?r.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:u,target:p,className:b},d):r.a.createElement(i.a,{to:u,className:b},d)}},430:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))}}]); \ No newline at end of file +/*! For license information please see 8ae34d0a.ee4caedd.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[137],{289:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return c})),n.d(t,"default",(function(){return u}));var o=n(1),r=n(9),i=(n(0),n(425)),a=(n(431),n(424)),l=(n(429),{last_modified_on:"2023-09-27",title:"Deployment Actions",description:"Learn how to deploy your application"}),s={id:"using-qovery/deployment/deployment-actions",title:"Deployment Actions",description:"Learn how to deploy your application",source:"@site/docs/using-qovery/deployment/deployment-actions.md",permalink:"/docs/using-qovery/deployment/deployment-actions",sidebar:"docs",previous:{title:"Deployment Pipeline",permalink:"/docs/using-qovery/deployment/deployment-pipeline"},next:{title:"Deployment History",permalink:"/docs/using-qovery/deployment/deployment-history"}},c=[{value:"Deployment Actions",id:"deployment-actions",children:[{value:"Deploy",id:"deploy",children:[]},{value:"Redeploy",id:"redeploy",children:[]},{value:"Stop",id:"stop",children:[]},{value:"Restart Service",id:"restart-service",children:[]},{value:"Cancel Deployment",id:"cancel-deployment",children:[]},{value:"Deploy other version",id:"deploy-other-version",children:[]},{value:"Deploy latest version",id:"deploy-latest-version",children:[]}]}],p={rightToc:c};function u(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Qovery allows you to manage the deployment lifecycle of your services and environments via a set of ",Object(i.b)("inlineCode",{parentName:"p"},"Deployment actions")," (example: deploy, redeploy, restart, stop etc..). These actions can be triggered via the Qovery web console, via the Qovery API, via the Qovery CLI or from your CI/CD depending on your integration type."),Object(i.b)("p",null,"You can imagine the deployment lifecycle of a service or environment like a state machine: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"each state is identified by a ",Object(i.b)("inlineCode",{parentName:"li"},"Deployment Status")),Object(i.b)("li",{parentName:"ul"},"the execution of a deployment action will modify the state of the service/environment until it reaches a final status (ok or error)"),Object(i.b)("li",{parentName:"ul"},"the list of allowed ",Object(i.b)("inlineCode",{parentName:"li"},"Deployment action")," depends on the current ",Object(i.b)("inlineCode",{parentName:"li"},"Deployment Status"),". Example: if the deployment status is ",Object(i.b)("inlineCode",{parentName:"li"},"Deployment Ok"),", you can trigger only the action ",Object(i.b)("inlineCode",{parentName:"li"},"Stop"),". This will stop the execution of the service (deployment status ",Object(i.b)("inlineCode",{parentName:"li"},"Stopped"),").")),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Example"),":\nWhen a new application is created within Qovery, the application will have the deployment status ",Object(i.b)("inlineCode",{parentName:"p"},"Ready"),". Once the action ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," is executed on the service, the service will go through the statuses ",Object(i.b)("inlineCode",{parentName:"p"},"Queued"),", ",Object(i.b)("inlineCode",{parentName:"p"},"Building"),", ",Object(i.b)("inlineCode",{parentName:"p"},"Deploying")," and then finally on the status ",Object(i.b)("inlineCode",{parentName:"p"},"Deployed")," (meaning that the application is correctly deployed)."),Object(i.b)("p",null,"You can find the deployment status directly in the Qovery console in the service or environment list:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deployment/deployment_statuses.png",alt:"Deployment Statuses"})),Object(i.b)("p",null,"Note that the deployment status of the environment is built based on the deployment statuses of each service within it."),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Deployment Status and Running Status do not provide the same information. Just because an error arose during deployment does not mean your application is not running anymore. Monitoring both your deployment and service statuses allows you to know exactly which applications are currently running on your platform.\nHave a look at ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/running-and-deployment-statuses/"}),"this section")," for more information")),Object(i.b)("p",null,"You can decide to execute a deployment action on:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"an environment: the action will be executed on each service within the environment. To know more about the deployment order of your services, have a look at the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deployment-pipeline/"}),"Deployment Pipeline")," "),Object(i.b)("li",{parentName:"ul"},"a single service: the action will be executed only on the selected service.")),Object(i.b)("p",null,"The deployment actions are accessible through the ",Object(i.b)("inlineCode",{parentName:"p"},"Play")," button available at service or environment level. "),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deployment/deployment_actions.png",alt:"Deployment Actions"})),Object(i.b)("p",null,"You can trigger the deployment actions via the UI but also via any interface described within ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/"}),"this section"),"."),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"You cannot have two or more deployment actions running at the same time on one environment. Example: you can't trigger the deployment of service A and stop service B at the same time. You need to wait for the deployment of service A to finish before triggering the pause of the service B")),Object(i.b)("h2",{id:"deployment-actions"},"Deployment Actions"),Object(i.b)("p",null,"You can find below a description of each deployment action, including its purpose and the deployment status your environment and/or service will go through."),Object(i.b)("h3",{id:"deploy"},"Deploy"),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," action allows you to create the resource necessary to run your code on your Kubernetes cluster. This action is available only if the service or environment have never been deployed."),Object(i.b)("p",null,"Based on the configuration of your services within, a certain number of ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://kubernetes.io/docs/concepts/workloads/pods/"}),"Pods")," will be created in a dedicated ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/"}),"Namespace")," of the target Kubernetes cluster. "),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"The commit id or tag that will be deployed is the one visible on the interface and not necessarily the latest version (unless the auto-deploy feature is activated)")),Object(i.b)("p",null,"Once triggered, the deployment of a service goes through the following deployment statuses:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"QUEUED")," : the deployment has been queued and it is waiting for the necessary resources to be allocated to manage your request"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"BUILDING")," : the Qovery engine is downloading the git repository and building your code. At the end of this step an image is built and pushed to a registry available on your cloud account. The status will become ",Object(i.b)("strong",{parentName:"li"},"BUILD ERROR")," in case of issues on building your code"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"DEPLOYING")," : the pods are being created on your cluster based on the image built on the previous step. The status will become ",Object(i.b)("strong",{parentName:"li"},"DEPLOYMENT ERROR")," in case of issues on deploying your service. A service is considered un-healthy if the Kubernetes readiness probe check is never OK (more info on ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#before-you-begin"}),"readiness probe"),")."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"DEPLOYMENT OK")," : all the requested pods have been created and the service is correctly running (liveness and readiness probes are ok).")),Object(i.b)("p",null,"If the deployment was triggered on the entire environment, the environment will go through the following deployment statuses:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"QUEUED")," : at least one service is in status ",Object(i.b)("strong",{parentName:"li"},"QUEUED")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"BUILDING")," : at least one service is in status ",Object(i.b)("strong",{parentName:"li"},"BUILDING")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"DEPLOYING")," : at least one service is in status ",Object(i.b)("strong",{parentName:"li"},"DEPLOYING")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"DEPLOYMENT OK")," : at least one service is in status ",Object(i.b)("strong",{parentName:"li"},"DEPLOYMENT OK")," but none of them is in error (",Object(i.b)("strong",{parentName:"li"},"BUILD ERROR")," or ",Object(i.b)("strong",{parentName:"li"},"DEPLOYMENT ERROR"),")"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"DEPLOYMENT ERROR")," : at least one service is in status ",Object(i.b)("strong",{parentName:"li"},"DEPLOYMENT ERROR"))),Object(i.b)("h3",{id:"redeploy"},"Redeploy"),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"Redeploy")," action allows you to update the remote configuration of your services based on their configuration on Qovery side. If any difference exists (vCPU, number of instances, code version etc..), a new set of pod will be created with the new configuration and replace the existing ones. If there are no configuration differences, nothing will happen on the pods running on your cluster (not even a restart, please use the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deployment-actions/#restart-service"}),"Restart Service")," feature).\nThis action is available only if the ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," action has been triggered at least once on the service or environment."),Object(i.b)("p",null,"When replacing the pods of your application, Qovery uses the rolling-restart deployment logic:"),Object(i.b)("p",null,"1) Deploy new version of instance ","#","1."),Object(i.b)("p",null,"2) New version of instance ","#","1 is running => kill previous version of instance ","#","1."),Object(i.b)("p",null,"3) Deploy new version of instance ","#","2."),Object(i.b)("p",null,"4) New version of instance ","#","2 is running => kill previous version of instance ","#","2."),Object(i.b)("p",null,"And so on..."),Object(i.b)("p",null,"You can trigger the re-deployment of a service or of the entire environment. The service or environment goes through the same deployment statuses described in the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deployment-actions/#deploy"}),"deployment section"),". "),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"A redeploy on an environment triggers the deployment of any service in the environment, no matter their previous status (even stopped ones)")),Object(i.b)("h3",{id:"stop"},"Stop"),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"Stop")," action allows you to stop the execution on the cluster of the selected service or environment (deployment status = Stopped). This action is available only if the current deployment status is ",Object(i.b)("inlineCode",{parentName:"p"},"Deployment OK")," or ",Object(i.b)("inlineCode",{parentName:"p"},"Deployment Error"),"."),Object(i.b)("p",null,"The effect on your cluster of the stop operation is different depending on the type of service:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Application, Container, Container DB ")," : Pods of those services are stopped. Any attached storage is preserved"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Cloud provider Managed DB"),": the database is paused (only for AWS, not working on Redis)")),Object(i.b)("h3",{id:"restart-service"},"Restart Service"),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"Restart Service")," action allows you to restart the pods of your service without applying any configuration change. This action is available only if the current deployment status is ",Object(i.b)("inlineCode",{parentName:"p"},"Deployment OK")," and only for a single service."),Object(i.b)("p",null,"Once triggered, the deployment status service goes through the following statuses:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"RESTARTING")," : the request to restart has been received"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"RESTARTED")," : all the pods of the service have been restarted"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"RESTART ERROR")," : Qovery couldn't process the restart request")),Object(i.b)("h3",{id:"cancel-deployment"},"Cancel Deployment"),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"Cancel Deployment")," action allows you to abort any ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," or ",Object(i.b)("inlineCode",{parentName:"p"},"Redeploy")," action. This action is available only if the current deployment status is ",Object(i.b)("inlineCode",{parentName:"p"},"Queued")," or ",Object(i.b)("inlineCode",{parentName:"p"},"Building")," or ",Object(i.b)("inlineCode",{parentName:"p"},"Deploying"),"."),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"The action allows to cancel the operation, not to rollback to the previous state. If during the deployment of services A and B, the ",Object(i.b)("inlineCode",{parentName:"p"},"Cancel Deployment")," action is triggered after that the deployment of service A has been completed, only the deployment of service B will be cancelled (service A will use the new config / version)")),Object(i.b)("h3",{id:"deploy-other-version"},"Deploy other version"),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy other version")," action allows you to deploy a different version for your service. This action is available no matter the deployment status of the service."),Object(i.b)("p",null,"Once you click on the action, this panel will appear, and you will be able to choose the version you wish to update/rollback (either git commit or image Tag)."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deployment/deploy_other_version.png",alt:"Deploy Other Version"})),Object(i.b)("p",null,"By pressing on the Deploy button, a deployment of the service will be triggered using the selected version."),Object(i.b)("h3",{id:"deploy-latest-version"},"Deploy latest version"),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy latest version")," action allows you to deploy the latest version for any of your services within the environment. This action is available no matter the deployment status of the service and only at environment level"),Object(i.b)("p",null,"Once you click on the action, this panel will appear, and you will be able to choose the services you wish to update to the latest version (only for services with source = git repository)."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deployment/deploy_latest_version.png",alt:"Deploy Latest Version"})),Object(i.b)("p",null,"By pressing on the Deploy button, a deployment of the service will be triggered using the selected version."))}u.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=r.a.createContext({}),p=function(e){var t=r.a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},u=function(e){var t=p(e.components);return r.a.createElement(c.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=p(n),d=o,m=u["".concat(a,".").concat(d)]||u[d]||b[d]||i;return n?r.a.createElement(m,l({ref:t},c,{components:n})):r.a.createElement(m,l({ref:t},c))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:o,a[1]=l;for(var c=2;c1?arguments[1]:void 0,n),s=a>2?arguments[2]:void 0,c=void 0===s?n:r(s,n);c>l;)t[l++]=e;return t}},428:function(e,t,n){var o=n(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var o=n(0),r=n.n(o),i=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var o=n(1),r=n(0),i=n.n(r),a=n(39),l=n(432),s=n(20),c=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,p=n||s,u=Object(l.a)(p),b=Object(r.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&t&&t.disconnect()}}),[p,d,u]),p&&u?i.a.createElement(a.b,Object(o.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(p),b.current=!0)},innerRef:function(e){var n,o;d&&e&&u&&(n=e,o=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:p})):i.a.createElement("a",Object(o.a)({},e,{href:p}))}},431:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=n(430),a=n(423),l=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,a=e.leftIcon,s=e.rightIcon,c=e.size,p=e.target,u=e.to,b=l()("jump-to","jump-to--"+c,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},a&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+a})),r.a.createElement("div",{className:"jump-to--main"},o?r.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:u,target:p,className:b},d):r.a.createElement(i.a,{to:u,className:b},d)}},432:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))}}]); \ No newline at end of file diff --git a/8d146bfd.11f1dd37.js.LICENSE.txt b/8ae34d0a.ee4caedd.js.LICENSE.txt similarity index 100% rename from 8d146bfd.11f1dd37.js.LICENSE.txt rename to 8ae34d0a.ee4caedd.js.LICENSE.txt diff --git a/8bd1b610.7e5f565e.js b/8bd1b610.7e5f565e.js new file mode 100644 index 0000000000..172f9aa5dc --- /dev/null +++ b/8bd1b610.7e5f565e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[138],{290:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return a})),t.d(r,"metadata",(function(){return c})),t.d(r,"rightToc",(function(){return u})),t.d(r,"default",(function(){return s}));var n=t(1),o=t(9),i=(t(0),t(425)),a={last_modified_on:"2023-11-30",title:"Helm Repository",description:"Learn how to use a helm repository within Qovery"},c={id:"using-qovery/integration/helm-repository",title:"Helm Repository",description:"Learn how to use a helm repository within Qovery",source:"@site/docs/using-qovery/integration/helm-repository.md",permalink:"/docs/using-qovery/integration/helm-repository",sidebar:"docs",previous:{title:"Container Registry",permalink:"/docs/using-qovery/integration/container-registry"},next:{title:"Terraform",permalink:"/docs/using-qovery/integration/terraform"}},u=[],l={rightToc:u};function s(e){var r=e.components,t=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(n.a)({},l,t,{components:r,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Qovery allows you to integrate with major helm registries, enabling you to deploy your own helm charts or those available on public registries."),Object(i.b)("p",null,"You can control the helm registry used by your teams directly within the ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),". "),Object(i.b)("p",null,"To know more about how to configure your helm registry connection and the supported container registries, have a look at ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"this section")))}s.isMDXComponent=!0},425:function(e,r,t){"use strict";t.d(r,"a",(function(){return p})),t.d(r,"b",(function(){return m}));var n=t(0),o=t.n(n);function i(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function a(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function c(e){for(var r=1;r=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=o.a.createContext({}),s=function(e){var r=o.a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},p=function(e){var r=s(e.components);return o.a.createElement(l.Provider,{value:r},e.children)},y={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},f=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,i=e.originalType,a=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),p=s(t),f=n,m=p["".concat(a,".").concat(f)]||p[f]||y[f]||i;return t?o.a.createElement(m,c({ref:r},l,{components:t})):o.a.createElement(m,c({ref:r},l))}));function m(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var i=t.length,a=new Array(i);a[0]=f;var c={};for(var u in r)hasOwnProperty.call(r,u)&&(c[u]=r[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,a[1]=c;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},b=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},p=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),b=l(n),p=r,d=b["".concat(i,".").concat(p)]||b[p]||m[p]||o;return n?a.a.createElement(d,c({ref:t},s,{components:n})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=p;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:a(u,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),b=l[0],m=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return m("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 8bfd1931.0475c469.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[139],{291:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),o=(n(0),n(425)),i=(n(434),n(429),n(424),{last_modified_on:"2023-08-31",$schema:"/.meta/.schemas/guides.json",title:"Preview Environments",description:"Learn how to use and leverage Preview Environments with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),c={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Preview Environments",description:"Learn how to use and leverage Preview Environments with Qovery",permalink:"/guides/advanced/use-preview-environments",readingTime:"2 min read",source:"@site/guides/advanced/use-preview-environments.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Preview Environments",truncated:!1,prevItem:{title:"Mono repository",permalink:"/guides/advanced/monorepository"},nextItem:{title:"Production",permalink:"/guides/advanced/production"}},u=[{value:"Recommendations",id:"recommendations",children:[]},{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:u};function l(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Use Preview Environment to get early feedback on your application changes by creating a dedicated environment for each of your pull requests.\nYour production environment runs 24/7, where your other environments may not need to run all day long.\nE.g. you may need to run Environments to get early feedback on your application changes before the changes are merged into production. This is what we call ",Object(o.b)("strong",{parentName:"p"},"Preview Environment"),"."),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"}," Sometimes ",Object(o.b)("strong",{parentName:"p"},"Preview Environment")," is also known as ",Object(o.b)("strong",{parentName:"p"},"Ephemeral Environment"),", ",Object(o.b)("strong",{parentName:"p"},"Temporary Environment"),", ",Object(o.b)("strong",{parentName:"p"},"Development Environment"),", ",Object(o.b)("strong",{parentName:"p"},"Review App"),".")),Object(o.b)("h2",{id:"recommendations"},"Recommendations"),Object(o.b)("p",null,"If you are using Qovery to run your Production, we recommend using Preview Environments on a separate ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/"}),"cluster"),". This will ensure that your Production is not impacted by the Preview Environments and vice versa."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to use and take advantage of Qovery Preview Environments:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners/"}),"Getting Started with Preview Environment")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners/"}),"Learn how to get started with Qovery Preview Environments")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/customizing-preview-url-with-qovery-cli/"}),"Customize preview URL")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/customizing-preview-url-with-qovery-cli/"}),"Learn how to customize your Preview URL with the Qovery CLI")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/deployment-rule/"}),"Automatically stop unused Preview Environments")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/deployment-rule/"}),"Learn how to automatically teardown your Preview Environments on a specific schedule")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/build-e2e-testing-ephemeral-environments/"}),"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/build-e2e-testing-ephemeral-environments/"}),"Step-by-step guide to build e2e testing ephemeral environments with GitHub Actions and Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=preview%20environment"}),'Forum "Preview Environment"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=preview%20environment"}),'List "Preview Environments" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}l.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},b=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},p=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),b=l(n),p=r,d=b["".concat(i,".").concat(p)]||b[p]||m[p]||o;return n?a.a.createElement(d,c({ref:t},s,{components:n})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=p;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:a(u,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),b=l[0],m=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return m("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/8d1c77c1.42e77c01.js.LICENSE.txt b/8bfd1931.0475c469.js.LICENSE.txt similarity index 100% rename from 8d1c77c1.42e77c01.js.LICENSE.txt rename to 8bfd1931.0475c469.js.LICENSE.txt diff --git a/8ca6d3cf.58169029.js b/8ca6d3cf.bb5c63c2.js similarity index 97% rename from 8ca6d3cf.58169029.js rename to 8ca6d3cf.bb5c63c2.js index a72579bc60..5f936e804a 100644 --- a/8ca6d3cf.58169029.js +++ b/8ca6d3cf.bb5c63c2.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[137],{289:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return a})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return c})),n.d(t,"default",(function(){return s}));var o=n(1),r=n(9),i=(n(0),n(422)),a={last_modified_on:"2023-10-10",title:"Deployment",description:"Everything you need to know about the deployment of your applications with Qovery",sidebar_label:"hidden",hide_pagination:!0},l={id:"using-qovery/deployment",title:"Deployment",description:"Everything you need to know about the deployment of your applications with Qovery",source:"@site/docs/using-qovery/deployment.md",permalink:"/docs/using-qovery/deployment",sidebar_label:"hidden",sidebar:"docs",previous:{title:"User Account",permalink:"/docs/using-qovery/configuration/user-account"},next:{title:"Deploying with the auto-deploy feature",permalink:"/docs/using-qovery/deployment/deploying-with-auto-deploy"}},c=[],p={rightToc:c};function s(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"In the following subsections, you'll find all the information about the deployment management with Qovery."),Object(i.b)("p",null,"The deployment has the end goal to create the resources necessary to run your applications on your cloud account, based on the configuration you have done on the Qovery console."),Object(i.b)("p",null,"In the image below you can find the complete flow that your application will go through, from your Git repository up to your Kuernetes cluster."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/deployment/deployment_overview_qovery.png",alt:"Deployment history access"})),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"The developer pushes the code within the git repository"),Object(i.b)("li",{parentName:"ol"},"The deployment trigger can come from different sources depending on your integration type:\n2.a The auto-deploy feature is activated on Qovery. When the new commit is pushed, a webhook call is received by Qovery and can proceed with the application deployment. See ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"this section")," for more information.\n2.b The auto-deploy feature is not activated on Qovery and the deployment is managed via ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deploying-with-ci-cd/"}),"the CI/CD"),".\n2.c The auto-deploy feature is not activated on Qovery and the user decides to trigger the deployment directly from within the Qovery console."),Object(i.b)("li",{parentName:"ol"},"The Qovery engine starts processing based on the configured ",Object(i.b)("inlineCode",{parentName:"li"},"Deployment Pipeline"),". The pipeline defines the steps that need to be followed in order to deploy your applications. See ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deployment-pipeline/"}),"this section")," for more information."),Object(i.b)("li",{parentName:"ol"},"The Qovery engine pulls the code from your repository."),Object(i.b)("li",{parentName:"ol"},"The Qovery engine builds the code and pushes the generated images on a registry present within your cloud account (See the ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/image-mirroring/"}),"Image Mirroring")," page for more information)."),Object(i.b)("li",{parentName:"ol"},"The Qovery engine creates the load balancers and configure the network."),Object(i.b)("li",{parentName:"ol"},"The Qovery engine creates a namespace within the Kubernetes cluster and deploys the application."),Object(i.b)("li",{parentName:"ol"},"The Qovery engine takes care of creating a custom domain for your application and as well configure the TLS so that you can access the application from the internet.")),Object(i.b)("p",null,"The developer can monitor at each time the status of the deployment or of the running applications by:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"checking the ",Object(i.b)("inlineCode",{parentName:"li"},"Deployment Status")," and ",Object(i.b)("inlineCode",{parentName:"li"},"Running Status"),". See ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/running-and-deployment-statuses/"}),"this section")," for more information."),Object(i.b)("li",{parentName:"ul"},"access the ",Object(i.b)("inlineCode",{parentName:"li"},"Logs")," interface to retrieve the deployment logs and as well the application logs in real-time. See ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/logs/"}),"this section")," for more information."),Object(i.b)("li",{parentName:"ul"},"access the ",Object(i.b)("inlineCode",{parentName:"li"},"Deployment History")," section to get all the information about the past deployments. See ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deployment-history/"}),"this section")," for more information.")),Object(i.b)("p",null,"Note: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Qovery also support deployments from container registry but actions 2a is not supported plus 4 and 5 are not done."),Object(i.b)("li",{parentName:"ul"},"In the example above we have shown how the deployment of an application is done but Qovery provides you with a complete set of ",Object(i.b)("inlineCode",{parentName:"li"},"Deployment Actions")," allowing you to manage the deployment lifecycle of your applications and environments (Stop, restart etc..). See ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deployment-actions/"}),"this section")," for more information.")))}s.isMDXComponent=!0},422:function(e,t,n){"use strict";n.d(t,"a",(function(){return u})),n.d(t,"b",(function(){return m}));var o=n(0),r=n.n(o);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function l(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=r.a.createContext({}),s=function(e){var t=r.a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},u=function(e){var t=s(e.components);return r.a.createElement(p.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},y=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=s(n),y=o,m=u["".concat(a,".").concat(y)]||u[y]||d[y]||i;return n?r.a.createElement(m,l({ref:t},p,{components:n})):r.a.createElement(m,l({ref:t},p))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=y;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:o,a[1]=l;for(var p=2;p=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=r.a.createContext({}),s=function(e){var t=r.a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},u=function(e){var t=s(e.components);return r.a.createElement(p.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},y=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=s(n),y=o,m=u["".concat(a,".").concat(y)]||u[y]||d[y]||i;return n?r.a.createElement(m,l({ref:t},p,{components:n})):r.a.createElement(m,l({ref:t},p))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=y;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:o,a[1]=l;for(var p=2;p /qovery-output/qovery-output.json")," to create a ",Object(a.b)("inlineCode",{parentName:"p"},"/qovery-output/qovery-output.json")," file. This file will be used by Qovery to inject the database credentials into our Environment Variables. We will cover this part later."),Object(a.b)("p",null,"For the ",Object(a.b)("strong",{parentName:"p"},"Deleted Event"),", we want to run the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform destroy -no-color -auto-approve")," command."),Object(a.b)("p",null,"So for the ",Object(a.b)("strong",{parentName:"p"},"Start Event"),", we have: ",Object(a.b)("inlineCode",{parentName:"p"},'["-c","terraform apply -no-color -auto-approve && terraform output -json > /qovery-output/qovery-output.json"]')," and for the ",Object(a.b)("strong",{parentName:"p"},"Deleted Event"),", we have: ",Object(a.b)("inlineCode",{parentName:"p"},'["-c","terraform destroy -no-color -auto-approve"]'),". Feel free to copy/paste these commands."),Object(a.b)(c.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Yes the commands contains a comma. It is not a typo. It is a JSON array. You need to use a comma to separate the elements of the array."))),Object(a.b)("li",null,Object(a.b)("p",null,"I recommend setting the ",Object(a.b)("strong",{parentName:"p"},"Timeout")," to 1800 seconds (30 minutes). It is the maximum time your Lifecycle Job can run. If your Lifecycle Job takes more than 30 minutes to run it will be stopped by Qovery. In our case, it should take less than 10 minutes to create the AWS RDS MySQL instance. But let's be safe."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/4.png",alt:""})),Object(a.b)("p",null,"Click ",Object(a.b)("strong",{parentName:"p"},"Continue"),".")),Object(a.b)("li",null,Object(a.b)("p",null,"Now we need to set the vCPU and RAM required to run our Job. We can allocate 0.5 CPU and 256 MB of RAM. It's more than enough."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/5.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"We need to set the Environment Variables required by our Lifecycle Job. In our case, we need to set the AWS credentials and some other environment variables. If you look at our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/blob/main/examples/aws-rds-with-terraform/Dockerfile#L3-L7"}),"Dockerfile"),", you will find the declaration of all those environment variables. You can copy/paste them."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-Dockerfile",metastring:'title="Dockerfile"',title:'"Dockerfile"'}),"...\nARG TF_VAR_terraform_backend_bucket\nARG TF_VAR_aws_region\nARG TF_VAR_aws_access_key_id\nARG TF_VAR_aws_secret_access_key\nARG TF_VAR_qovery_environment_id\n...\n")),Object(a.b)("p",null,"Those are the ones that we need to set."),Object(a.b)(c.a,{type:"warning",mdxType:"Alert"},Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"We do not set here the ",Object(a.b)("inlineCode",{parentName:"li"},"TF_VAR_qovery_environment_id")," since we will create it in the next step."),Object(a.b)("li",{parentName:"ol"},Object(a.b)("inlineCode",{parentName:"li"},"TF_VAR_terraform_backend_bucket")," is the name of the S3 bucket where Terraform will store the state of your infrastructure. You need to create this bucket on S3 before running the Lifecycle Job. You can use the same bucket for all your Lifecycle Jobs. It is not a problem. You will just need to make sure that the S3 object key is unique."))),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/6.png",alt:""})),Object(a.b)("p",null,"Click on ",Object(a.b)("strong",{parentName:"p"},"Continue"),".")),Object(a.b)("li",null,Object(a.b)("p",null,"Then click on ",Object(a.b)("strong",{parentName:"p"},"Create")," (and not ",Object(a.b)("strong",{parentName:"p"},"Create and Deploy"),")."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/7.png",alt:""}))),Object(a.b)("p",null,"Congrats, your Lifecycle Job is created. Now we just need to add the ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," environment variable before launching it."))),Object(a.b)("h3",{id:"make-your-terraform-deployment-multi-environments-ready"},"Make your Terraform deployment multi-environments ready"),Object(a.b)("p",null,"To support multiple environments, we need to make sure that the name of the S3 object key where Terraform will store the state of your infrastructure is unique. To do that, we will use the ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," environment variable. This environment variable is automatically created by Qovery and contains the ID of your Environment. We just need to create an environment variable alias."),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Go inside your ",Object(a.b)("strong",{parentName:"p"},"MySQL RDS")," service, click on the ",Object(a.b)("strong",{parentName:"p"},"Variables")," tab."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/8.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Search for ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable. Then click on ",Object(a.b)("strong",{parentName:"p"},"Creat alias")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/9.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Set the name of the environment variable to ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," with a ",Object(a.b)("strong",{parentName:"p"},"service")," scope and click on ",Object(a.b)("strong",{parentName:"p"},"Confirm"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/10.png",alt:""}))))),Object(a.b)("h3",{id:"deploy-aws-rds-mysql-instance"},"Deploy AWS RDS MySQL instance"),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Now you are ready to deploy your Lifecycle Job and see what happened."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/11.png",alt:""})),Object(a.b)("p",null,"The job execution will take approximately 3 to 10 minutes.")),Object(a.b)("li",null,Object(a.b)("p",null,"Follow the logs of the job execution by clicking on the ",Object(a.b)("strong",{parentName:"p"},"Logs")," button."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/12.png",alt:""})),Object(a.b)("p",null,"From the ",Object(a.b)("strong",{parentName:"p"},"Deployment logs")," tab you can see that your Lifecycle Job is built and that the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform init")," command is executed."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/13.png",alt:""})),Object(a.b)("p",null,"From the ",Object(a.b)("strong",{parentName:"p"},"MySQL RDS")," tab you can see that the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform apply -no-color -auto-approve")," command is executed. The creation of the AWS RDS MySQL instance is in progress."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/14.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Once the deployment is done, you should see that the AWS RDS MySQL instance is green and completed."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/15.png",alt:""}))))),Object(a.b)("h3",{id:"get-the-mysql-rds-credentials-from-the-lifecycle-job"},"Get the MySQL RDS credentials from the Lifecycle Job"),Object(a.b)("p",null,"Now that the AWS RDS MySQL instance is created, we need to get the credentials to connect to it. We have use the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform output -json > /qovery-output/qovery-output.json")," command to get the credentials. If you go back to the ",Object(a.b)("inlineCode",{parentName:"p"},"Variables")," tab of your MySQL RDS service, you will see that the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_OUTPUT_**")," environment variables are created."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/16.png",alt:""})),Object(a.b)("p",null,"By using ",Object(a.b)("inlineCode",{parentName:"p"},"terraform output -json > /qovery-output/qovery-output.json")," Qovery automatically create those environment variables for you. You can use them in your application to connect to the AWS RDS MySQL instance. ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/#job-output"}),"Learn more on how Lifecycle Job output...")),Object(a.b)(c.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,"Job output is a powerful feature that allows you to get the output of your Lifecycle Job and use it in your application. You can use it to get the credentials of your database, the URL of your S3 bucket, the URL of your CDN, etc...")),Object(a.b)("h2",{id:"faq"},"FAQ"),Object(a.b)("h3",{id:"what-happen-if-i-delete-my-environment-with-your-example"},"What happen if I delete my environment with your example?"),Object(a.b)("p",null,"If you delete your environment, the AWS RDS MySQL instance will be deleted too. You can see that in the ",Object(a.b)("strong",{parentName:"p"},"MySQL RDS")," service logs. You will see that the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform destroy -no-color -auto-approve")," command is executed."),Object(a.b)("h3",{id:"can-i-use-the-lifecycle-job-to-deploy-my-application"},"Can I use the Lifecycle Job to deploy my application?"),Object(a.b)("p",null,"Some users ask us if they can use the Lifecycle Job to deploy their application. The answer is yes!. The Lifecycle Job is designed to deploy all type of resources. However, we recommend using the official Qovery way to deploy applications. ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/"}),"Learn more on how to deploy your application...")),Object(a.b)("h3",{id:"what-happen-if-i-clone-my-environment-with-the-lifecycle-job"},"What happen if I clone my Environment with the Lifecycle Job?"),Object(a.b)("p",null,"If you clone an Environment with the Lifecycle Job, the Lifecycle Job will be cloned too. In our example we have set the ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," environment variable to the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable. So when you clone your Environment, the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable will be different. That's why you need to create a new alias environment variable for the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable. ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#clone-environment"}),"Learn more on how to clone an Environment...")),Object(a.b)("h3",{id:"what-happen-if-i-modify-my-lifecycle-job-after-my-environment-is-deployed"},"What happen if I modify my Lifecycle Job after my Environment is deployed?"),Object(a.b)("p",null,"If you modify your Lifecycle Job after your Environment is deployed, the Lifecycle Job will be redeployed. In our example, since the state of our AWS RDS MySQL instance is stored in the S3 bucket, the AWS RDS MySQL instance will not be recreated. However, if you modify the ",Object(a.b)("inlineCode",{parentName:"p"},"main.tf")," file, the AWS RDS MySQL instance will be updated."),Object(a.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(a.b)("p",null,"In this guide, we have seen how to use the Lifecycle Job to create an AWS RDS MySQL instance with Terraform. We have also seen how to get the credentials of the AWS RDS MySQL instance to connect to it from our application. To learn more about the Lifecycle Job, you can read the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"Lifecycle Job documentation"),". To get more examples, check out the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples"}),"Qovery Lifecycle Examples repository"),"."))}m.isMDXComponent=!0},420:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),b=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=b(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=b(n),m=o,y=u["".concat(i,".").concat(m)]||u[m]||p[m]||a;return n?r.a.createElement(y,c({ref:t},s,{components:n})):r.a.createElement(y,c({ref:t},s))}));function y(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var o=n(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var o=n(0),r=n.n(o),a=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var o=n(432),r=n(51);function a(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(r),a,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[a(t,e),"[",o,"]"].join(""):[a(t,e),"[",a(o,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return a(o,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(n(o,e,i.length))})),i.join("&")}return a(o,t)+"="+a(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),b=Object(o.useState)(null),u=b[0],p=b[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 8d146bfd.d09f2cb2.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[141],{293:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return m}));var o=n(1),r=n(9),a=(n(0),n(425)),i=n(434),c=n(424),l=n(429),s={last_modified_on:"2023-08-14",$schema:"/.meta/.schemas/guides.json",title:"How To Use Lifecycle Job To Deploy Any Kind Of Resources",description:"Learn how to use Lifecycle Job to deploy any kind of resources with Qovery.",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},b={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How To Use Lifecycle Job To Deploy Any Kind Of Resources",description:"Learn how to use Lifecycle Job to deploy any kind of resources with Qovery.",permalink:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources",readingTime:"10 min read",source:"@site/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How To Use Lifecycle Job To Deploy Any Kind Of Resources",truncated:!1,prevItem:{title:"How to use Github Organizations with Qovery",permalink:"/guides/tutorial/github-organization-repository-access"},nextItem:{title:"How to write a Dockerfile",permalink:"/guides/tutorial/how-to-write-a-dockerfile"}},u=[{value:"How to use Lifecycle Job (example with Terraform)",id:"how-to-use-lifecycle-job-example-with-terraform",children:[{value:"Execution Flow",id:"execution-flow",children:[]},{value:"Create a Lifecycle Job",id:"create-a-lifecycle-job",children:[]},{value:"Make your Terraform deployment multi-environments ready",id:"make-your-terraform-deployment-multi-environments-ready",children:[]},{value:"Deploy AWS RDS MySQL instance",id:"deploy-aws-rds-mysql-instance",children:[]},{value:"Get the MySQL RDS credentials from the Lifecycle Job",id:"get-the-mysql-rds-credentials-from-the-lifecycle-job",children:[]}]},{value:"FAQ",id:"faq",children:[{value:"What happen if I delete my environment with your example?",id:"what-happen-if-i-delete-my-environment-with-your-example",children:[]},{value:"Can I use the Lifecycle Job to deploy my application?",id:"can-i-use-the-lifecycle-job-to-deploy-my-application",children:[]},{value:"What happen if I clone my Environment with the Lifecycle Job?",id:"what-happen-if-i-clone-my-environment-with-the-lifecycle-job",children:[]},{value:"What happen if I modify my Lifecycle Job after my Environment is deployed?",id:"what-happen-if-i-modify-my-lifecycle-job-after-my-environment-is-deployed",children:[]}]},{value:"Wrapping up",id:"wrapping-up",children:[]}],p={rightToc:u};function m(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"The ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"Lifecycle Job")," is a powerful feature that allows you to run any kind of commands before or after your environment is deployed. It can be used to run database migrations, create a new database, or even to run a script that will create a new user."),Object(a.b)("p",null,"Some use cases:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Run Terraform, Pulumi, or any other infrastructure as code tool to create resources."),Object(a.b)("li",{parentName:"ul"},"You want to deploy SQS, SNS, Lambdas, or any other AWS resources."),Object(a.b)("li",{parentName:"ul"},"You want to deploy MongoDB Atlas, Google BigQuery, or any other cloud services."),Object(a.b)("li",{parentName:"ul"},"Seed your database when your environment is created.")),Object(a.b)(c.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,"You can find some Lifecycle Jobs examples on our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples"}),"GitHub"),".")),Object(a.b)("p",null,"In a more general way, you can see the Lifecycle Job as a way to create and destroy resources when your environment is deployed or deleted. Possibilities are endless."),Object(a.b)("h2",{id:"how-to-use-lifecycle-job-example-with-terraform"},"How to use Lifecycle Job (example with Terraform)"),Object(a.b)("p",null,"In this example, we will use Terraform to create a new AWS RDS MySQL instance. I will use ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-rds-with-terraform"}),"this example")," to schematize the process of using the Lifecycle Job. \u26a0\ufe0f Note that you can use any other tool to create your resources. Lifecycle Job is not limited to Terraform. However, Terraform is a great way to show the power of the Lifecycle Job since it requires a lot of configuration and can be used to create a lot of different resources."),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"In our example, we use S3 as a Terraform backend. You can use any other backend you want. However, if you want to use S3, you need to create a new bucket and a new IAM user with the right permissions. You can find more information about this in the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://www.terraform.io/docs/language/settings/backends/s3.html"}),"Terraform documentation"),".")),Object(a.b)("h3",{id:"execution-flow"},"Execution Flow"),Object(a.b)("p",null,"Here is the execution flow when my Environment is deployed:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Qovery builds my Lifecycle Job (and my others services)."),Object(a.b)("li",{parentName:"ol"},"Qovery runs my Lifecycle Job ",Object(a.b)("strong",{parentName:"li"},"Start Event")," (and my others services)."),Object(a.b)("li",{parentName:"ol"},"My Lifecycle Job creates a new AWS RDS MySQL instance."),Object(a.b)("li",{parentName:"ol"},"My Lifecycle Job injects the database credentials into a ",Object(a.b)("inlineCode",{parentName:"li"},"/qovery-output/qovery-output.json")," file."),Object(a.b)("li",{parentName:"ol"},"Qovery reads the ",Object(a.b)("inlineCode",{parentName:"li"},"/qovery-output/qovery-output.json")," file and injects the database credentials into my Environment Variables."),Object(a.b)("li",{parentName:"ol"},"My others services can access my database.")),Object(a.b)("p",null,"When my Environment is deleted:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Qovery runs my Lifecycle Job ",Object(a.b)("strong",{parentName:"li"},"Deleted Event")),Object(a.b)("li",{parentName:"ol"},"My Lifecycle Job destroys the AWS RDS MySQL instance."),Object(a.b)("li",{parentName:"ol"},"Qovery destroys my Environment and release all the resources.")),Object(a.b)("h3",{id:"create-a-lifecycle-job"},"Create a Lifecycle Job"),Object(a.b)(l.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have a ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"https://start.qovery.com"}),"Qovery account")),Object(a.b)("li",{parentName:"ul"},"You have an existing project and an existing environment."))),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Fork ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples"}),"this repository"),".")),Object(a.b)("li",null,Object(a.b)("p",null,"Go inside your Environment, and add a ",Object(a.b)("strong",{parentName:"p"},"Lifecycle Job"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/1.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Give a name, description, pick your GitHub account, and select the repository of the Lifecycle Job. In our example, the root application path is ",Object(a.b)("inlineCode",{parentName:"p"},"/examples/aws-rds-with-terraform"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/2.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Since we are using Terraform, we want to make sure that our MySQL RDS instance is created when our Environment is deployed. So we select the ",Object(a.b)("strong",{parentName:"p"},"Start Event"),".\nWe also want to make sure that our MySQL RDS instance is destroyed when our Environment is deleted. So we select the ",Object(a.b)("strong",{parentName:"p"},"Deleted Event"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/3.png",alt:""})),Object(a.b)("p",null,"If you look at our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/blob/main/examples/aws-rds-with-terraform/Dockerfile"}),"Dockerfile")," in the repository, you will see that we are using the official Terraform image. I have also inserted by default the ",Object(a.b)("inlineCode",{parentName:"p"},'ENTRYPOINT ["/bin/sh"]')," to simplify the Qovery Lifecycle Job configuration."),Object(a.b)("p",null,"For the ",Object(a.b)("strong",{parentName:"p"},"Start Event"),", we want to run the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform apply -no-color -auto-approve")," command. We don't need to run the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform init")," command since it is already done in the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/blob/main/examples/aws-rds-with-terraform/Dockerfile#L14"}),"Dockerfile"),"."),Object(a.b)("p",null,"You will also notice that we are also using ",Object(a.b)("inlineCode",{parentName:"p"},"&& terraform output -json > /qovery-output/qovery-output.json")," to create a ",Object(a.b)("inlineCode",{parentName:"p"},"/qovery-output/qovery-output.json")," file. This file will be used by Qovery to inject the database credentials into our Environment Variables. We will cover this part later."),Object(a.b)("p",null,"For the ",Object(a.b)("strong",{parentName:"p"},"Deleted Event"),", we want to run the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform destroy -no-color -auto-approve")," command."),Object(a.b)("p",null,"So for the ",Object(a.b)("strong",{parentName:"p"},"Start Event"),", we have: ",Object(a.b)("inlineCode",{parentName:"p"},'["-c","terraform apply -no-color -auto-approve && terraform output -json > /qovery-output/qovery-output.json"]')," and for the ",Object(a.b)("strong",{parentName:"p"},"Deleted Event"),", we have: ",Object(a.b)("inlineCode",{parentName:"p"},'["-c","terraform destroy -no-color -auto-approve"]'),". Feel free to copy/paste these commands."),Object(a.b)(c.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Yes the commands contains a comma. It is not a typo. It is a JSON array. You need to use a comma to separate the elements of the array."))),Object(a.b)("li",null,Object(a.b)("p",null,"I recommend setting the ",Object(a.b)("strong",{parentName:"p"},"Timeout")," to 1800 seconds (30 minutes). It is the maximum time your Lifecycle Job can run. If your Lifecycle Job takes more than 30 minutes to run it will be stopped by Qovery. In our case, it should take less than 10 minutes to create the AWS RDS MySQL instance. But let's be safe."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/4.png",alt:""})),Object(a.b)("p",null,"Click ",Object(a.b)("strong",{parentName:"p"},"Continue"),".")),Object(a.b)("li",null,Object(a.b)("p",null,"Now we need to set the vCPU and RAM required to run our Job. We can allocate 0.5 CPU and 256 MB of RAM. It's more than enough."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/5.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"We need to set the Environment Variables required by our Lifecycle Job. In our case, we need to set the AWS credentials and some other environment variables. If you look at our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/blob/main/examples/aws-rds-with-terraform/Dockerfile#L3-L7"}),"Dockerfile"),", you will find the declaration of all those environment variables. You can copy/paste them."),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-Dockerfile",metastring:'title="Dockerfile"',title:'"Dockerfile"'}),"...\nARG TF_VAR_terraform_backend_bucket\nARG TF_VAR_aws_region\nARG TF_VAR_aws_access_key_id\nARG TF_VAR_aws_secret_access_key\nARG TF_VAR_qovery_environment_id\n...\n")),Object(a.b)("p",null,"Those are the ones that we need to set."),Object(a.b)(c.a,{type:"warning",mdxType:"Alert"},Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"We do not set here the ",Object(a.b)("inlineCode",{parentName:"li"},"TF_VAR_qovery_environment_id")," since we will create it in the next step."),Object(a.b)("li",{parentName:"ol"},Object(a.b)("inlineCode",{parentName:"li"},"TF_VAR_terraform_backend_bucket")," is the name of the S3 bucket where Terraform will store the state of your infrastructure. You need to create this bucket on S3 before running the Lifecycle Job. You can use the same bucket for all your Lifecycle Jobs. It is not a problem. You will just need to make sure that the S3 object key is unique."))),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/6.png",alt:""})),Object(a.b)("p",null,"Click on ",Object(a.b)("strong",{parentName:"p"},"Continue"),".")),Object(a.b)("li",null,Object(a.b)("p",null,"Then click on ",Object(a.b)("strong",{parentName:"p"},"Create")," (and not ",Object(a.b)("strong",{parentName:"p"},"Create and Deploy"),")."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/7.png",alt:""}))),Object(a.b)("p",null,"Congrats, your Lifecycle Job is created. Now we just need to add the ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," environment variable before launching it."))),Object(a.b)("h3",{id:"make-your-terraform-deployment-multi-environments-ready"},"Make your Terraform deployment multi-environments ready"),Object(a.b)("p",null,"To support multiple environments, we need to make sure that the name of the S3 object key where Terraform will store the state of your infrastructure is unique. To do that, we will use the ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," environment variable. This environment variable is automatically created by Qovery and contains the ID of your Environment. We just need to create an environment variable alias."),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Go inside your ",Object(a.b)("strong",{parentName:"p"},"MySQL RDS")," service, click on the ",Object(a.b)("strong",{parentName:"p"},"Variables")," tab."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/8.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Search for ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable. Then click on ",Object(a.b)("strong",{parentName:"p"},"Creat alias")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/9.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Set the name of the environment variable to ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," with a ",Object(a.b)("strong",{parentName:"p"},"service")," scope and click on ",Object(a.b)("strong",{parentName:"p"},"Confirm"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/10.png",alt:""}))))),Object(a.b)("h3",{id:"deploy-aws-rds-mysql-instance"},"Deploy AWS RDS MySQL instance"),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Now you are ready to deploy your Lifecycle Job and see what happened."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/11.png",alt:""})),Object(a.b)("p",null,"The job execution will take approximately 3 to 10 minutes.")),Object(a.b)("li",null,Object(a.b)("p",null,"Follow the logs of the job execution by clicking on the ",Object(a.b)("strong",{parentName:"p"},"Logs")," button."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/12.png",alt:""})),Object(a.b)("p",null,"From the ",Object(a.b)("strong",{parentName:"p"},"Deployment logs")," tab you can see that your Lifecycle Job is built and that the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform init")," command is executed."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/13.png",alt:""})),Object(a.b)("p",null,"From the ",Object(a.b)("strong",{parentName:"p"},"MySQL RDS")," tab you can see that the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform apply -no-color -auto-approve")," command is executed. The creation of the AWS RDS MySQL instance is in progress."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/14.png",alt:""}))),Object(a.b)("li",null,Object(a.b)("p",null,"Once the deployment is done, you should see that the AWS RDS MySQL instance is green and completed."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/15.png",alt:""}))))),Object(a.b)("h3",{id:"get-the-mysql-rds-credentials-from-the-lifecycle-job"},"Get the MySQL RDS credentials from the Lifecycle Job"),Object(a.b)("p",null,"Now that the AWS RDS MySQL instance is created, we need to get the credentials to connect to it. We have use the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform output -json > /qovery-output/qovery-output.json")," command to get the credentials. If you go back to the ",Object(a.b)("inlineCode",{parentName:"p"},"Variables")," tab of your MySQL RDS service, you will see that the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_OUTPUT_**")," environment variables are created."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/how-to-use-lifecycle-job/16.png",alt:""})),Object(a.b)("p",null,"By using ",Object(a.b)("inlineCode",{parentName:"p"},"terraform output -json > /qovery-output/qovery-output.json")," Qovery automatically create those environment variables for you. You can use them in your application to connect to the AWS RDS MySQL instance. ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/#job-output"}),"Learn more on how Lifecycle Job output...")),Object(a.b)(c.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,"Job output is a powerful feature that allows you to get the output of your Lifecycle Job and use it in your application. You can use it to get the credentials of your database, the URL of your S3 bucket, the URL of your CDN, etc...")),Object(a.b)("h2",{id:"faq"},"FAQ"),Object(a.b)("h3",{id:"what-happen-if-i-delete-my-environment-with-your-example"},"What happen if I delete my environment with your example?"),Object(a.b)("p",null,"If you delete your environment, the AWS RDS MySQL instance will be deleted too. You can see that in the ",Object(a.b)("strong",{parentName:"p"},"MySQL RDS")," service logs. You will see that the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform destroy -no-color -auto-approve")," command is executed."),Object(a.b)("h3",{id:"can-i-use-the-lifecycle-job-to-deploy-my-application"},"Can I use the Lifecycle Job to deploy my application?"),Object(a.b)("p",null,"Some users ask us if they can use the Lifecycle Job to deploy their application. The answer is yes!. The Lifecycle Job is designed to deploy all type of resources. However, we recommend using the official Qovery way to deploy applications. ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/"}),"Learn more on how to deploy your application...")),Object(a.b)("h3",{id:"what-happen-if-i-clone-my-environment-with-the-lifecycle-job"},"What happen if I clone my Environment with the Lifecycle Job?"),Object(a.b)("p",null,"If you clone an Environment with the Lifecycle Job, the Lifecycle Job will be cloned too. In our example we have set the ",Object(a.b)("inlineCode",{parentName:"p"},"TF_VAR_qovery_environment_id")," environment variable to the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable. So when you clone your Environment, the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable will be different. That's why you need to create a new alias environment variable for the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_ENVIRONMENT_ID")," built-in environment variable. ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#clone-environment"}),"Learn more on how to clone an Environment...")),Object(a.b)("h3",{id:"what-happen-if-i-modify-my-lifecycle-job-after-my-environment-is-deployed"},"What happen if I modify my Lifecycle Job after my Environment is deployed?"),Object(a.b)("p",null,"If you modify your Lifecycle Job after your Environment is deployed, the Lifecycle Job will be redeployed. In our example, since the state of our AWS RDS MySQL instance is stored in the S3 bucket, the AWS RDS MySQL instance will not be recreated. However, if you modify the ",Object(a.b)("inlineCode",{parentName:"p"},"main.tf")," file, the AWS RDS MySQL instance will be updated."),Object(a.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(a.b)("p",null,"In this guide, we have seen how to use the Lifecycle Job to create an AWS RDS MySQL instance with Terraform. We have also seen how to get the credentials of the AWS RDS MySQL instance to connect to it from our application. To learn more about the Lifecycle Job, you can read the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"Lifecycle Job documentation"),". To get more examples, check out the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples"}),"Qovery Lifecycle Examples repository"),"."))}m.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),b=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=b(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=b(n),m=o,y=u["".concat(i,".").concat(m)]||u[m]||p[m]||a;return n?r.a.createElement(y,c({ref:t},s,{components:n})):r.a.createElement(y,c({ref:t},s))}));function y(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var o=n(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var o=n(0),r=n.n(o),a=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var o=n(435),r=n(51);function a(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(r),a,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[a(t,e),"[",o,"]"].join(""):[a(t,e),"[",a(o,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return a(o,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(n(o,e,i.length))})),i.join("&")}return a(o,t)+"="+a(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),b=Object(o.useState)(null),u=b[0],p=b[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/8d5726d6.f71ea248.js.LICENSE.txt b/8d146bfd.d09f2cb2.js.LICENSE.txt similarity index 100% rename from 8d5726d6.f71ea248.js.LICENSE.txt rename to 8d146bfd.d09f2cb2.js.LICENSE.txt diff --git a/8d1c77c1.1993c6dc.js b/8d1c77c1.1993c6dc.js new file mode 100644 index 0000000000..a8cf76fc6e --- /dev/null +++ b/8d1c77c1.1993c6dc.js @@ -0,0 +1,2 @@ +/*! For license information please see 8d1c77c1.1993c6dc.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[142],{294:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return c})),r.d(t,"metadata",(function(){return s})),r.d(t,"rightToc",(function(){return u})),r.d(t,"default",(function(){return l}));var n=r(1),o=r(9),i=(r(0),r(425)),a=r(431),c={last_modified_on:"2023-11-30",title:"Integrations",description:"Integrate Qovery with your existing tools and workflow",sidebar_label:"hidden",hide_pagination:!0},s={id:"using-qovery/integration",title:"Integrations",description:"Integrate Qovery with your existing tools and workflow",source:"@site/docs/using-qovery/integration.md",permalink:"/docs/using-qovery/integration",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Terraform",permalink:"/docs/using-qovery/interface/terraform-interface"},next:{title:"Git Repository",permalink:"/docs/using-qovery/integration/git-repository"}},u=[],p={rightToc:u};function l(e){var t=e.components,r=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(n.a)({},p,r,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Qovery integrations improve developers' experience with Qovery and make their lives easier."),Object(i.b)("p",null,"This section shows several Qovery integrations."),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/api-integration/",mdxType:"Jump"},"Api integration"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/container-registry/",mdxType:"Jump"},"Container registry"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/continuous-integration/",mdxType:"Jump"},"Continuous integration"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/git-repository/",mdxType:"Jump"},"Git repository"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/helm-repository/",mdxType:"Jump"},"Helm repository"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/monitoring/",mdxType:"Jump"},"Monitoring"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/secret-manager/",mdxType:"Jump"},"Secret manager"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/slack/",mdxType:"Jump"},"Slack"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/terraform/",mdxType:"Jump"},"Terraform"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/webhook/",mdxType:"Jump"},"Webhook"))}l.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=o.a.createContext({}),p=function(e){var t=o.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},l=function(e){var t=p(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,a=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),l=p(r),f=n,d=l["".concat(a,".").concat(f)]||l[f]||m[f]||i;return r?o.a.createElement(d,c({ref:t},u,{components:r})):o.a.createElement(d,c({ref:t},u))}));function d(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,a=new Array(i);a[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,a[1]=c;for(var u=2;u0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:p})):i.a.createElement("a",Object(n.a)({},e,{href:p}))}},431:function(e,t,r){"use strict";var n=r(0),o=r.n(n),i=r(430),a=r(423),c=r.n(a);r(133);t.a=function(e){var t=e.children,r=e.className,n=e.badge,a=e.leftIcon,s=e.rightIcon,u=e.size,p=e.target,l=e.to,m=c()("jump-to","jump-to--"+u,r),f=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},a&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+a})),o.a.createElement("div",{className:"jump-to--main"},n?o.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return p?o.a.createElement("a",{href:l,target:p,className:m},f):o.a.createElement(i.a,{to:l,className:m},f)}},432:function(e,t,r){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}r.d(t,"a",(function(){return n}))}}]); \ No newline at end of file diff --git a/8f02216a.59eeb2b1.js.LICENSE.txt b/8d1c77c1.1993c6dc.js.LICENSE.txt similarity index 100% rename from 8f02216a.59eeb2b1.js.LICENSE.txt rename to 8d1c77c1.1993c6dc.js.LICENSE.txt diff --git a/8d1c77c1.42e77c01.js b/8d1c77c1.42e77c01.js deleted file mode 100644 index aaa658b3e3..0000000000 --- a/8d1c77c1.42e77c01.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see 8d1c77c1.42e77c01.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[139],{291:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return l}));var r=n(1),o=n(9),i=(n(0),n(422)),a=n(429),c={last_modified_on:"2023-10-10",title:"Integrations",description:"Integrate Qovery with your existing tools and workflow",sidebar_label:"hidden",hide_pagination:!0},s={id:"using-qovery/integration",title:"Integrations",description:"Integrate Qovery with your existing tools and workflow",source:"@site/docs/using-qovery/integration.md",permalink:"/docs/using-qovery/integration",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Terraform",permalink:"/docs/using-qovery/interface/terraform-interface"},next:{title:"Git Repository",permalink:"/docs/using-qovery/integration/git-repository"}},u=[],p={rightToc:u};function l(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Qovery integrations improve developers' experience with Qovery and make their lives easier."),Object(i.b)("p",null,"This section shows several Qovery integrations."),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/api-integration/",mdxType:"Jump"},"Api integration"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/container-registry/",mdxType:"Jump"},"Container registry"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/continuous-integration/",mdxType:"Jump"},"Continuous integration"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/git-repository/",mdxType:"Jump"},"Git repository"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/monitoring/",mdxType:"Jump"},"Monitoring"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/secret-manager/",mdxType:"Jump"},"Secret manager"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/slack/",mdxType:"Jump"},"Slack"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/terraform/",mdxType:"Jump"},"Terraform"),Object(i.b)(a.a,{to:"/docs/using-qovery/integration/webhook/",mdxType:"Jump"},"Webhook"))}l.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),p=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},l=function(e){var t=p(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,a=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),l=p(n),m=r,d=l["".concat(a,".").concat(m)]||l[m]||f[m]||i;return n?o.a.createElement(d,c({ref:t},u,{components:n})):o.a.createElement(d,c({ref:t},u))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=m;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,a[1]=c;for(var u=2;u0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:p})):i.a.createElement("a",Object(r.a)({},e,{href:p}))}},429:function(e,t,n){"use strict";var r=n(0),o=n.n(r),i=n(427),a=n(420),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,a=e.leftIcon,s=e.rightIcon,u=e.size,p=e.target,l=e.to,f=c()("jump-to","jump-to--"+u,n),m=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},a&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+a})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return p?o.a.createElement("a",{href:l,target:p,className:f},m):o.a.createElement(i.a,{to:l,className:f},m)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/8d5726d6.f71ea248.js b/8d5726d6.f71ea248.js deleted file mode 100644 index 44cfada4ea..0000000000 --- a/8d5726d6.f71ea248.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see 8d5726d6.f71ea248.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[140],{292:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return p})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return d}));var a=n(1),o=n(9),i=(n(0),n(422)),r=n(431),c=(n(429),n(421)),l=n(426),s={last_modified_on:"2023-10-11",title:"Application",description:"Learn how to configure your Application on Qovery"},p={id:"using-qovery/configuration/application",title:"Application",description:"Learn how to configure your Application on Qovery",source:"@site/docs/using-qovery/configuration/application.md",permalink:"/docs/using-qovery/configuration/application",sidebar:"docs",previous:{title:"Environment",permalink:"/docs/using-qovery/configuration/environment"},next:{title:"Databases",permalink:"/docs/using-qovery/configuration/database"}},b=[{value:"Deploying from a Git Repository",id:"deploying-from-a-git-repository",children:[]},{value:"Deploying from a Container Registry",id:"deploying-from-a-container-registry",children:[]},{value:"Create an Application",id:"create-an-application",children:[]},{value:"Deployment Management",id:"deployment-management",children:[]},{value:"Configuration",id:"configuration",children:[{value:"General",id:"general",children:[]},{value:"Resources",id:"resources",children:[]},{value:"Storage",id:"storage",children:[]},{value:"Ports",id:"ports",children:[]},{value:"Health Checks",id:"health-checks",children:[]},{value:"Domains",id:"domains",children:[]}]},{value:"Connecting from the internet",id:"connecting-from-the-internet",children:[{value:"Qovery provided domains",id:"qovery-provided-domains",children:[]},{value:"Custom domains",id:"custom-domains",children:[]}]},{value:"Connecting to a database",id:"connecting-to-a-database",children:[]},{value:"Connecting to another application",id:"connecting-to-another-application",children:[]},{value:"Environment Variable",id:"environment-variable",children:[]},{value:"Secrets",id:"secrets",children:[]},{value:"Logs",id:"logs",children:[]},{value:"SSH",id:"ssh",children:[]},{value:"Clone",id:"clone",children:[]},{value:"Delete an Application",id:"delete-an-application",children:[]}],u={rightToc:b};function d(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(l.a,{name:"documentation",mdxType:"Assumptions"},Object(i.b)("p",null,"You have created an ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment"),".")),Object(i.b)("p",null,"An ",Object(i.b)("strong",{parentName:"p"},"application")," is part of a ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/project/"}),"Project")," within an ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment")," and is a container unit. Multiple applications can be part of the same ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment"),", be connected to a set of dependencies (databases and other services), and can communicate with other applications within the same Environment."),Object(i.b)("p",null,"Qovery allows you to create and deploy applications from two different sources: Git Repository or Container Registry"),Object(i.b)("h2",{id:"deploying-from-a-git-repository"},"Deploying from a Git Repository"),Object(i.b)("p",null,"In this configuration, Qovery will pull the code from the chosen repository, build the application and deploy it on your kubernetes cluster."),Object(i.b)("p",null,"The list of Git repositories available during the setup is strictly tied to the permissions of your git account (by default Qovery can access all your repositories). If you want to restrict the Qovery access only to a few repositories, user the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/git-repository-access/"}),"GitHub Qovery Application")," (only for Github)."),Object(i.b)("h2",{id:"deploying-from-a-container-registry"},"Deploying from a Container Registry"),Object(i.b)("p",null,"In this configuration, Qovery will pull the chosen container registry an image you have pre-built and deploy it on your kubernetes cluster."),Object(i.b)("p",null,"To improve security and avoid deploying images from non-authorized registries, we have decided to restrict the list of Container Registry you can use during the setup process. Only an administrator with the right permissions can manage it from the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,'Make sure that the image tag used are unique (do not use "latest", "dev", "master" etc..), see ',Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/image-mirroring/#why-unique-image-tags-are-necessary"}),"this section")," for more information.")),Object(i.b)("h2",{id:"create-an-application"},"Create an Application"),Object(i.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,'Go into the chosen environment and press the "New Service" button and then the "Create application" button'),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/creation_1.png",alt:"Creation"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Select the following fields:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Application Name: give a name to your application"),Object(i.b)("li",{parentName:"ul"},"Application Source: Chose between Git Repository or Container Registry, depending on the source location of your application")),Object(i.b)("p",null,"If you want to deploy an application from a Git Repository you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Git Repository: Select the git provider hosting your code (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Branch: Select branch that Qovery should use to deploy your application"),Object(i.b)("li",{parentName:"ul"},"Root Application Path: base folder in which the application resides in your repository"),Object(i.b)("li",{parentName:"ul"},"Build Mode: choose between Docker or Buildpack. For more information, go to ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/application/#build-mode"}),"this section"))),Object(i.b)("p",null,"If you want to deploy an application from a Container Registry you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Registry: select the container registry storing the image of your application. Note: only pre-configured registry are available in this list, check the ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," for more information."),Object(i.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this application (example: postgres)"),Object(i.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this application (example: 1.0). "),Object(i.b)("li",{parentName:"ul"},"Image Entrypoint: the entrypoint to be used to launch your applicaiton (not mandatory)"),Object(i.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your applicaiton (not mandatory). We expect the format to be an array. Example ",'["rails", "-h", "0.0.0.0", "-p", "8080", "string"]')),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,'Make sure that the image tag used are unique (do not use "latest", "dev", "master" etc..), see ',Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/image-mirroring/#why-unique-image-tags-are-necessary"}),"this section")," for more information.")),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Auto Deploy ")),Object(i.b)("p",null,"See the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section.")),Object(i.b)("li",null,Object(i.b)("p",null,"Within this section, you will need to define the resources to be assigned to your application at run time."),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"vCPU: the vCPU assigned to each instance of your application. The default is 500m (0.5 vCPU)."),Object(i.b)("li",{parentName:"ul"},"RAM: the amount of RAM assigned to each instance of your application. The default is 512MB."),Object(i.b)("li",{parentName:"ul"},"Number of instances (Application Auto-scaling): select the minimum and the maximum number of instances of your application that can run within your cluster. The number of instances running at an insant t is automatically managed by Kubernetes (Application auto-scaling) and it is based on real-time CPU consumption. When your app goes above 60% of CPU consumption for 5 minutes, your app will be auto-scaled and more instances will be added. It is transparent.\nQovery runs your application on Kubernetes and relies on ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/kubernetes-sigs/metrics-server"}),"metrics-server")," service to auto-scale your app.")),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Please note that in this section you configure the CPU/RAM allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU/RAM.")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/application_creation_resources.png",alt:"Resources"}))),Object(i.b)("li",null,Object(i.b)("p",null,"You can now define one or more ports for your Application. Most of the application needs to be accessed by other services inside or outside your environment over different L7/L4 protocols.\nToday Qovery supports the following protocols:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"HTTPS (Select this protocol if you need to run Websockets)"),Object(i.b)("li",{parentName:"ul"},"gRPC"),Object(i.b)("li",{parentName:"ul"},"TCP"),Object(i.b)("li",{parentName:"ul"},"UDP")),Object(i.b)("p",null,"By default ports are accessible only from inside your environment. You can also expose them publicly, making them accessible over the public network via a dedicated public domain that will be assigned to your application by Qovery during the deployment (See the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"#qovery-provided-domains"}),"Qovery Provided Domains section"),"). Note that HTTPS/gRPC ports are always exposed over the port 443."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/application_creation_port.png",alt:"Application Ports"})),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Important Informations")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Most of the ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/service-health-checks/"}),"Kubernetes Health Checks")," are based on the port declared in this section. Make sure you declare the right port and that you configure the health checks properly."),Object(i.b)("li",{parentName:"ul"},"Connections on public ports are automatically closed after 60 seconds. If you want to implement long living connection (like for websockets) please make sure to use the rigth ingress timeouts in the ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/advanced-settings/#network-settings"}),"advanced settings section")),Object(i.b)("li",{parentName:"ul"},"Exposing publicly TCP/UDP ports requires to create a dedicated load balancer and it takes a few minutes before having it ready (~15 minutes). Note also that this has a direct impact on your cloud provider bill."),Object(i.b)("li",{parentName:"ul"},"You can configure your application to use the ",Object(i.b)("strong",{parentName:"li"},"PORT")," environment variable by adding the ",Object(i.b)("strong",{parentName:"li"},"PORT")," on your application env variables page."),Object(i.b)("li",{parentName:"ul"},"A Note on Listening IPs: It's best for your application to listen on ",Object(i.b)("inlineCode",{parentName:"li"},"0.0.0.0:$PORT"),". While most things work with ",Object(i.b)("inlineCode",{parentName:"li"},"127.0.0.1")," and ",Object(i.b)("inlineCode",{parentName:"li"},"localhost"),", some do not (NodeJS for example)"))),Object(i.b)("li",null,Object(i.b)("p",null,"(Optional) If a port has been defined for your application, you can define the health check probes to run in order to verify the state of your application"),Object(i.b)("p",null,"To know more about how to configure your Liveness and Readiness probes, have a look at ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application-health-checks/"}),"the health-checks section"))),Object(i.b)("li",null,Object(i.b)("p",null,"You will find a recap of your application setup and you can now decide to:"),Object(i.b)("h1",{id:"go-back-to-one-of-the-previous-steps-and-change-your-application-settings"},"Go back to one of the previous steps and change your application settings"),Object(i.b)("h1",{id:"create-your-application-without-deploying-it"},"Create your application without deploying it"),Object(i.b)("h1",{id:"create-and-deploy-your-application"},"Create and deploy your application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/application_creation_recap.png",alt:"Application"}))))),Object(i.b)("h2",{id:"deployment-management"},"Deployment Management"),Object(i.b)("p",null,"Have a look at the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/"}),"Deployment Management")," section for more information."),Object(i.b)("h2",{id:"configuration"},"Configuration"),Object(i.b)("p",null,"Once created, you can access the configuration of an application at any time via the Settings tab available on the application section"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/settings.png",alt:"Application Settings"})),Object(i.b)("p",null,"You can find below the description of each of the tabs available in this section"),Object(i.b)("h3",{id:"general"},"General"),Object(i.b)("p",null,"General settings section allows you to set up your application name and the source code location (git repository or image registry) ."),Object(i.b)("h4",{id:"git-repository"},"Git Repository"),Object(i.b)("p",null,"If your application is built and deployed from a git repository, within this section you can:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Modify the git provider where your code is stored (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Modify the branch that Qovery should use for deploying your application"),Object(i.b)("li",{parentName:"ul"},"Modify ",Object(i.b)("inlineCode",{parentName:"li"},"Root Application Path")," - base folder in which the application resides in your repository")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-general-git.png",alt:"General Settings Git"})),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Qovery supports mono repositories. ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/advanced/monorepository/"}),"See our advanced guide for more details."))),Object(i.b)(c.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"If your repository contains private submodules using SSH protocol, you will need to add a secret beginning with GIT",Object(i.b)("em",{parentName:"p"},"SSH_KEY"),", containing a private SSH key with access rights to your sumbodules repositories."),Object(i.b)("p",null,"Secret names examples:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITHUB"),Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITLAB"),Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_MYAPP"))),Object(i.b)("h4",{id:"container-registry"},"Container Registry"),Object(i.b)("p",null,"If your application is deployed from an image registry, within this section you can modify:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Registry: select the container registry storing the image of your application. Note: only pre-configured registry are available in this list, check the ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," for more information."),Object(i.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this application (example: postgres)"),Object(i.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this application (example: 1.0)."),Object(i.b)("li",{parentName:"ul"},"Image Entrypoint: the entrypoint to be used to launch your applicaiton (not mandatory)"),Object(i.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your applicaiton (not mandatory). We expect the format to be an array. Example ",'["rails", "-h", "0.0.0.0", "-p", "8080", "string"]')),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,'Make sure that the image tag used are unique (do not use "latest", "dev", "master" etc..), see ',Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/image-mirroring/#why-unique-image-tags-are-necessary"}),"this section")," for more information.")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-general-registry.png",alt:"General Settings Git"})),Object(i.b)("h4",{id:"build-mode"},"Build Mode"),Object(i.b)("p",null,'This option is available only if you have selected "Git Repository" as source'),Object(i.b)("h4",{id:"option-1-buildpacks"},"Option 1: Buildpacks"),Object(i.b)("p",null,"To simplify the application build for the developer, Qovery supports ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://buildpacks.io"}),"Buildpacks")," out of the box. Buildpacks determine the build process for an app and which assets and runtimes should be made available to your code at runtime. If your complex apps are running multiple languages, you can also use multiple buildpacks within a single app.\nMeaning, as a developer, you don't need to write a ",Object(i.b)("inlineCode",{parentName:"p"},"Dockerfile")," to build and run your app. Qovery Buildpacks takes care of everything for you."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Supported languages")),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"language"),Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"version"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Node.JS"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Clojure"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Python"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Java"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Gradle"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"JVM"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Grails"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Scala"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Play"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"PHP"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Go"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")))),Object(i.b)("p",null,"You don't find a cool language? ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://roadmap.qovery.com/"}),"Suggest us to support it")),Object(i.b)("h4",{id:"option-2-dockerfile"},"Option 2: Dockerfile"),Object(i.b)("p",null,"Qovery runs your application within the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.docker.com/resources/what-container"}),"Container technology"),". To build and run your application, you need to provide a valid ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.docker.com/engine/reference/builder"}),"Dockerfile"),"."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-Dockerfile",metastring:'title="Valid NodeJS Dockerfile"',title:'"Valid',NodeJS:!0,'Dockerfile"':!0}),"FROM node:13-alpine\nRUN mkdir -p /usr/src/app\nWORKDIR /usr/src/app\nCOPY . .\nRUN npm install\nEXPOSE 3000\nCMD node ./bin/www\n")),Object(i.b)("p",null,"After creating a Dockerfile, specify the location of your Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"Dockefile path")," field."),Object(i.b)("p",null,"Configuration from above will make Qovery look for the Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"/timescale/Dockerfile")," path of your repository (",Object(i.b)("inlineCode",{parentName:"p"},"Root Application Path")," + ",Object(i.b)("inlineCode",{parentName:"p"},"Dockerfile Path"),")."),Object(i.b)("h4",{id:"auto-deploy"},"Auto Deploy"),Object(i.b)("p",null,"See the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section."),Object(i.b)("h3",{id:"resources"},"Resources"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-13.png",alt:"CPU"})),Object(i.b)("h4",{id:"cpu"},"CPU"),Object(i.b)("p",null,"To configure the number of CPUs that your app needs, adjust the setting in the ",Object(i.b)("inlineCode",{parentName:"p"},"Resources")," section of the application configuration."),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Default is 500m (0.5 vCPU). ")),Object(i.b)("p",null,"Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consumes fewer resources, the cluster will still reserve the selected amount of CPU."),Object(i.b)("h4",{id:"ram"},"RAM"),Object(i.b)("p",null,"To configure the amount of RAM that your app needs, adjust the setting in ",Object(i.b)("inlineCode",{parentName:"p"},"Resources")," section of the application configuration."),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Default is 512MB.")),Object(i.b)("p",null,"Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU. If your application requires more RAM than requested, it will be killed by the kubernetes scheduler."),Object(i.b)("h4",{id:"auto-scaling"},"Auto-scaling"),Object(i.b)("p",null,"Application auto-scaling is based on real-time CPU consumption. When your app goes above 60% of CPU consumption for 15 seconds, your app will be auto-scaled and more instances will be added. It is transparent. The downscale will happen if the CPU consumption is lower than 60% for at least 5 minutes.\nYou can adjust the minimum and maximum of instances you need in your application settings. Qovery runs your application on Kubernetes and relies on ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/kubernetes-sigs/metrics-server"}),"metrics-server")," service to auto-scale your app."),Object(i.b)("h3",{id:"storage"},"Storage"),Object(i.b)("h4",{id:"block-storage"},"Block Storage"),Object(i.b)("p",null,"The default filesystem for applications running on Qovery is ephemeral. Application data isn\u2019t persisted across deploys and restarts, which works just fine for most apps because they use managed databases to persist data."),Object(i.b)("p",null,"However, many applications need persistent disk storage that isn\u2019t ephemeral. These include:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Blogging platforms and CMSs like WordPress, Ghost, and Strapi."),Object(i.b)("li",{parentName:"ul"},"Collaboration apps like Mattermost, GitLab, and Discourse.")),Object(i.b)("p",null,"This is where Qovery block Storage comes in. Qovery applications can use storage to store data that persists across deploys and restarts, making it easy to deploy stateful applications."),Object(i.b)(c.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"For most use cases, it is better to use ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/object-storage/"}),"Object Storage")," instead of Block Storage.")),Object(i.b)("h6",{id:"use-cases"},"Use cases"),Object(i.b)("h6",{id:"-good-use-cases"},"\u2705 Good use cases"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"For I/O intensive applications (E.g. database)"),Object(i.b)("li",{parentName:"ul"},"To store temporary files")),Object(i.b)("h6",{id:"-bad-use-cases"},"\u274c Bad use cases"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"To store file > 1 TB"),Object(i.b)("li",{parentName:"ul"},"To expose files from an application (E.g. images)")),Object(i.b)("h5",{id:"types-of-block-storage"},"Types of Block Storage"),Object(i.b)("p",null,"Qovery Storage supports:"),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Type"),Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Max IOPS"),Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Max Throughput"),Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Min Size"),Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Max Size"),Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Use cases"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"fast_ssd"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"64000"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"1GB/s"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"5GB"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"10GB ",Object(i.b)("inlineCode",{parentName:"td"},"Community")," / 1TB paid plans"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Critical business applications that require sustained IOPS like databases")))),Object(i.b)("h5",{id:"configuration-1"},"Configuration"),Object(i.b)("p",null,"You can set up your Block Storage in ",Object(i.b)("inlineCode",{parentName:"p"},"Storage")," section of your application configuration."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-7.png",alt:"Application Storage"})),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Storage can be added only if the application has never been deployed before AND if it runs only with one instance (check the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#resources"}),"Resources section"),")")),Object(i.b)("h3",{id:"ports"},"Ports"),Object(i.b)("p",null,"Within this section you can define the port exposed by your application to the other services or even over the internet.\nYou can edit the existing ports or declare new ones by specifying:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Application port: this is the port exposed internally by your application for the other services. "),Object(i.b)("li",{parentName:"ul"},"Protocol: you can select the protocol used by your application : HTTP (for both standard HTTP or websocket communications), gRPC, TCP, UDP."),Object(i.b)("li",{parentName:"ul"},"Publicly exposed: it allows you to expose over the public network your service. A public domain will be assigned to your application during the deployment (see ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#connecting-from-the-internet"}),"Connectin from the internet section"),")"),Object(i.b)("li",{parentName:"ul"},"If Publicly Exposed is selected:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"External port: it is the port that can be used to access this service over the internet (when exposed publicly). Note that for HTTP and gRPC the port is set by default to 443."),Object(i.b)("li",{parentName:"ul"},"Port Name: it is the name assigned to the port. When multiple ports are exposed publicly, its value is used to route the traffic to the right port based on the called subdomain (which will contain the port name value). Since each port is exposed on the port 443, having a different subdomain is the only way to have multiple ports exposed over the internet. If not set, the default value is ",Object(i.b)("inlineCode",{parentName:"li"},"p")," (see ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#qovery-provided-domains"}),"Qovery Provided Domain section")," for more information)")))),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-15.png",alt:"Application Ports"})),Object(i.b)("h4",{id:"important-informations"},"Important Informations"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Most of the Kubernetes Health Checks]",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/service-health-checks/"}),"docs.using-qovery.configuration.service-health-checks")," are based on the port declared in this section. Make sure you declare the right port and that you configure the health checks properly."),Object(i.b)("li",{parentName:"ul"},"Connections on public ports are automatically closed after 60 seconds. If you want to implement long living connection (like for websockets) please make sure to use the rigth ingress timeouts in the ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/advanced-settings/#network-settings"}),"advanced settings section")),Object(i.b)("li",{parentName:"ul"},"Exposing publicly TCP/UDP ports requires to create a dedicated load balancer and it takes a few minutes before having it ready (~15 minutes). Note also that this has a direct impact on your cloud provider bill."),Object(i.b)("li",{parentName:"ul"},"You can configure your application to use the ",Object(i.b)("strong",{parentName:"li"},"PORT")," environment variable by adding the ",Object(i.b)("strong",{parentName:"li"},"PORT")," on your application env variables page."),Object(i.b)("li",{parentName:"ul"},"A Note on Listening IPs: It's best for your application to listen on ",Object(i.b)("inlineCode",{parentName:"li"},"0.0.0.0:$PORT"),". While most things work with ",Object(i.b)("inlineCode",{parentName:"li"},"127.0.0.1")," and ",Object(i.b)("inlineCode",{parentName:"li"},"localhost"),", some do not (NodeJS for example)")),Object(i.b)("h3",{id:"health-checks"},"Health Checks"),Object(i.b)("p",null,"To know more about how to configure your Liveness and Readiness probes, have a look at ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application-health-checks/"}),"the health-checks section")),Object(i.b)("h3",{id:"domains"},"Domains"),Object(i.b)("p",null,"Within this section you can customize the domain used to reach your application. "),Object(i.b)("p",null,"You can customize the domain of your application in different ways, depending on what you want to achieve:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"You want to use your own domain for this application"),Object(i.b)("li",{parentName:"ul"},"You want to modify the subdomain assigned to your application by Qovery (i.e. change ",Object(i.b)("inlineCode",{parentName:"li"},"p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh")," into ",Object(i.b)("inlineCode",{parentName:"li"},"my-app-domain.za8ad0657.bool.sh"),").")),Object(i.b)("p",null,"In both cases, you can assign the new custom domain to your application press the ",Object(i.b)("inlineCode",{parentName:"p"},"Add Domain")," button. "),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-16.png",alt:"Application Domains"})),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"This configuration will be ",Object(i.b)("strong",{parentName:"p"},"automatically removed")," on every cloned environment or preview environment in order to avoid domain collision.")),Object(i.b)("h4",{id:"configuring-your-own-domain"},"Configuring your own domain"),Object(i.b)("p",null,"Once the domain is added within the Qovery console (Example: mydomain.com), you need to configure within your DNS two ",Object(i.b)("inlineCode",{parentName:"p"},"CNAME")," records pointing to the domain provided by Qovery, as shown in the UI (example: mydomain.com CNAME za7cc1b71-z4b8474b3-gtw.zc531a994.rustrocks.cloud and *.mydomain.com CNAME za7cc1b71-z4b8474b3-gtw.zc531a994.rustrocks.cloud). "),Object(i.b)("p",null,"Having a wildcard domain (example: *.mydomain.com) configured on your DNS will avoid you to modify the Qovery setup every time you want to add a new subdomain. If ",Object(i.b)("inlineCode",{parentName:"p"},"wildcard")," is not supported by your DNS provider, you will have to configure each subdomain manually."),Object(i.b)("p",null,"If the service needs to expose more than one port publicly, you can define a dedicated subdomain to redirect the traffic on the right port by setting the \u201cPort Name\u201d value within the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"#ports"}),"port settings"),"."),Object(i.b)("p",null,"From this point, Qovery will automatically handle the TLS/SSL certificate creation and renewal for the configured domain."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/custom-domain.png",alt:"Custom Domain"})),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Special case - CDN in proxy mode ")),Object(i.b)("p",null,"If your service is behind a CDN using a ",Object(i.b)("inlineCode",{parentName:"p"},"proxy mode"),' (i.e. the traffic is routed through the CDN to Qovery), make sure to disable the option "Generate certificate" on the domain setup. Since the certificate of your domain is directly managed by the CDN, Qovery won\'t be able to do that for you and it will raise warnings on your application status.'),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/cdn-proxy.png",alt:"CDN Proxy"})),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/setting-custom-domain/"}),"We prepared a guide and video tutorial that explains how to set up your custom domain."))),Object(i.b)("h4",{id:"change-the-auto-assigned-sub-domain"},"Change the auto assigned sub-domain"),Object(i.b)("p",null,"You can specify a different sub-domain for your application as long as it belongs to the assigned cluster domain (see ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"#qovery-provided-domains"}),"Qovery provided domains"),").\nExample: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"your current domain is zdf72de71-z709e1a85-gtw.za8ad0659.bool.sh (so your assigned cluster domain is ",Object(i.b)("inlineCode",{parentName:"li"},"za8ad0659.bool.sh"),")"),Object(i.b)("li",{parentName:"ul"},"you can enter a new custom domain ",Object(i.b)("inlineCode",{parentName:"li"},"myfrontend.za8ad0659.bool.sh")," (since it is a subdomain of the cluster domain)")),Object(i.b)("p",null,"The application will now be accessible from both the default and the new custom domain."),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Qovery does not check collision in the domain declaration. Make sure you assign a unique subdomain within your cluster.")),Object(i.b)("h2",{id:"connecting-from-the-internet"},"Connecting from the internet"),Object(i.b)("p",null,"Your application can be reached from the internet by publicly exposing at least one of its ports (See the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"#ports"}),"Ports")," section to know more). Once this is done, Qovery will generate for you a domain to reach your application from the internet. You can also customize the domain assigned to your application and manage by yourself this assignment via the ",Object(i.b)("inlineCode",{parentName:"p"},"Domain")," section."),Object(i.b)("h3",{id:"qovery-provided-domains"},"Qovery provided domains"),Object(i.b)("p",null,"For each port publicly exposed, a domain is automatically assigned by Qovery to your application. Qovery will manage for you the networking and the TLS configuration for these domains. "),Object(i.b)("p",null,"Example: ",Object(i.b)("inlineCode",{parentName:"p"},"p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh")),Object(i.b)("p",null,"Note:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"each service deployed on the same cluster will have the same root domain assigned (example: ",Object(i.b)("inlineCode",{parentName:"li"},"za8ad0657.bool.sh"),")"),Object(i.b)("li",{parentName:"ul"},"the first characters of the domain (before the ",Object(i.b)("inlineCode",{parentName:"li"},"-"),") is based on the portName given to the port associated with this domain (See the ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#ports"}),"port section"),")"),Object(i.b)("li",{parentName:"ul"},"a default domain (without the portName) is assigned to the ",Object(i.b)("inlineCode",{parentName:"li"},"default port"),"(See the ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#ports"}),"port section"),"). Example ",Object(i.b)("inlineCode",{parentName:"li"},"zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh"))),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Special Case - Preview Environment"),"\nFor each port exposed publicly, an additional domain will be created with the following pattern ",Object(i.b)("inlineCode",{parentName:"p"},"portName-prId-srvName-envSourceName.cluster_domain"),":"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"portName: is the port name, as explained above"),Object(i.b)("li",{parentName:"ul"},"prID: is the id of the PR that has generated the preview environment"),Object(i.b)("li",{parentName:"ul"},"srvName: is the name of the service"),Object(i.b)("li",{parentName:"ul"},"envSourceName: is the name of the blueprint environment that has created the current preview environment")),Object(i.b)("p",null,"domain example: ",Object(i.b)("inlineCode",{parentName:"p"},"p80-123-frontend-blueprint.za8ad0657.bool.sh")),Object(i.b)("h3",{id:"custom-domains"},"Custom domains"),Object(i.b)("p",null,"If you prefer to assign your own domain to the application have a look at the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"#domains"}),"Domain section")," to know more."),Object(i.b)("h2",{id:"connecting-to-a-database"},"Connecting to a database"),Object(i.b)("p",null,"To know how to access your database from your application, ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-a-database"}),"have a look at the database section"),"."),Object(i.b)("h2",{id:"connecting-to-another-application"},"Connecting to another application"),Object(i.b)("p",null,"To know how to access your database from your application, ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-another-application"}),"have a look at the database section"),"."),Object(i.b)("h2",{id:"environment-variable"},"Environment Variable"),Object(i.b)("p",null,"To learn how to set up environment variables in your projects and applications, navigate to ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Environment Variables")," section."),Object(i.b)("h2",{id:"secrets"},"Secrets"),Object(i.b)("p",null,"To learn how to set up secrets in your projects and applications, navigate to ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Secrets")," section."),Object(i.b)("h2",{id:"logs"},"Logs"),Object(i.b)("p",null,"To learn how to display your application logs, navigate to ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#live-logs"}),"logs section")),Object(i.b)("h2",{id:"ssh"},"SSH"),Object(i.b)("p",null,"To connect to your application via SSH, please use the via the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery SSH command")," available on our CLI."),Object(i.b)("h2",{id:"clone"},"Clone"),Object(i.b)("p",null,"You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/clone_service.png",alt:"Clone Service"})),Object(i.b)("p",null,"The target environment can be the same as the current environment or even another one in a completely different project."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Important information ")),Object(i.b)("p",null,"Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"same environment:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"))),Object(i.b)("li",{parentName:"ul"},"another environment:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"),Object(i.b)("li",{parentName:"ul"},"environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)"),Object(i.b)("li",{parentName:"ul"},"deployment pipeline: stage setup is not copied (since the target stage might not exist)"),Object(i.b)("li",{parentName:"ul"},"number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)")))),Object(i.b)("p",null,"Please check the configuration of the new service before deploying it."),Object(i.b)("h2",{id:"delete-an-application"},"Delete an Application"),Object(i.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Choose your application")),Object(i.b)("li",null,Object(i.b)("p",null,"In the application overview, click on the ",Object(i.b)("inlineCode",{parentName:"p"},"3 dots")," button and remove the application."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-1.png",alt:"Application"}))))))}d.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),p=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},b=function(e){var t=p(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,r=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=p(n),d=a,m=b["".concat(r,".").concat(d)]||b[d]||u[d]||i;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,r[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=r>2?arguments[2]:void 0,s=void 0===l?n:o(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var a=n(28).f,o=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in o||n(10)&&a(o,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),o=n.n(a),i=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),o=n(0),i=n.n(o),r=n(39),c=n(430),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,p=n||l,b=Object(c.a)(p),u=Object(o.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(p),function(){d&&t&&t.disconnect()}}),[p,d,b]),p&&b?i.a.createElement(r.b,Object(a.a)({},e,{onMouseEnter:function(){u.current||(window.docusaurus.preload(p),u.current=!0)},innerRef:function(e){var n,a;d&&e&&b&&(n=e,a=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:p})):i.a.createElement("a",Object(a.a)({},e,{href:p}))}},428:function(e,t,n){"use strict";var a=n(432),o=n(51);function i(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(o),i,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[i(t,e),"[",a,"]"].join(""):[i(t,e),"[",i(a,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var o=e[a];if(void 0===o)return"";if(null===o)return i(a,t);if(Array.isArray(o)){var r=[];return o.slice().forEach((function(e){void 0!==e&&r.push(n(a,e,r.length))})),r.join("&")}return i(a,t)+"="+i(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var a=n(0),o=n.n(a),i=n(427),r=n(420),c=n.n(r);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,r=e.leftIcon,l=e.rightIcon,s=e.size,p=e.target,b=e.to,u=c()("jump-to","jump-to--"+s,n),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},r&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+r})),o.a.createElement("div",{className:"jump-to--main"},a?o.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return p?o.a.createElement("a",{href:b,target:p,className:u},d):o.a.createElement(i.a,{to:b,className:u},d)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},431:function(e,t,n){"use strict";var a=n(0),o=n.n(a),i=(n(420),n(428)),r=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+r.a.stringify(l),p=Object(a.useState)(null),b=p[0],u=p[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!b&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return u("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/8d5726d6.f7ba9f14.js b/8d5726d6.f7ba9f14.js new file mode 100644 index 0000000000..6a29a2cbe2 --- /dev/null +++ b/8d5726d6.f7ba9f14.js @@ -0,0 +1,2 @@ +/*! For license information please see 8d5726d6.f7ba9f14.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[143],{295:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return p})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return d}));var a=n(1),o=n(9),i=(n(0),n(425)),r=n(434),c=(n(431),n(424)),l=n(429),s={last_modified_on:"2023-12-19",title:"Application",description:"Learn how to configure your Application on Qovery"},p={id:"using-qovery/configuration/application",title:"Application",description:"Learn how to configure your Application on Qovery",source:"@site/docs/using-qovery/configuration/application.md",permalink:"/docs/using-qovery/configuration/application",sidebar:"docs",previous:{title:"Environment",permalink:"/docs/using-qovery/configuration/environment"},next:{title:"Helm",permalink:"/docs/using-qovery/configuration/helm"}},b=[{value:"Deploying from a Git Repository",id:"deploying-from-a-git-repository",children:[]},{value:"Deploying from a Container Registry",id:"deploying-from-a-container-registry",children:[]},{value:"Create an Application",id:"create-an-application",children:[]},{value:"Deployment Management",id:"deployment-management",children:[]},{value:"Configuration",id:"configuration",children:[{value:"General",id:"general",children:[]},{value:"Resources",id:"resources",children:[]},{value:"Storage",id:"storage",children:[]},{value:"Ports",id:"ports",children:[]},{value:"Health Checks",id:"health-checks",children:[]},{value:"Domains",id:"domains",children:[]}]},{value:"Connecting from the internet",id:"connecting-from-the-internet",children:[{value:"Qovery provided domains",id:"qovery-provided-domains",children:[]},{value:"Custom domains",id:"custom-domains",children:[]}]},{value:"Connecting to a database",id:"connecting-to-a-database",children:[]},{value:"Connecting to another application",id:"connecting-to-another-application",children:[]},{value:"Environment Variable",id:"environment-variable",children:[]},{value:"Secrets",id:"secrets",children:[]},{value:"Logs",id:"logs",children:[]},{value:"SSH",id:"ssh",children:[]},{value:"Clone",id:"clone",children:[]},{value:"Delete an Application",id:"delete-an-application",children:[]}],u={rightToc:b};function d(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(l.a,{name:"documentation",mdxType:"Assumptions"},Object(i.b)("p",null,"You have created an ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment"),".")),Object(i.b)("p",null,"An ",Object(i.b)("strong",{parentName:"p"},"application")," is part of a ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/project/"}),"Project")," within an ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment")," and is a container unit. Multiple applications can be part of the same ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment"),", be connected to a set of dependencies (databases and other services), and can communicate with other applications within the same Environment."),Object(i.b)("p",null,"Qovery allows you to create and deploy applications from two different sources: Git Repository or Container Registry"),Object(i.b)("h2",{id:"deploying-from-a-git-repository"},"Deploying from a Git Repository"),Object(i.b)("p",null,"In this configuration, Qovery will pull the code from the chosen repository, build the application and deploy it on your kubernetes cluster."),Object(i.b)("p",null,"The list of Git repositories available during the setup is strictly tied to the permissions of your git account (by default Qovery can access all your repositories). If you want to restrict the Qovery access only to a few repositories, user the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/git-repository-access/"}),"GitHub Qovery Application")," (only for Github)."),Object(i.b)("h2",{id:"deploying-from-a-container-registry"},"Deploying from a Container Registry"),Object(i.b)("p",null,"In this configuration, Qovery will pull the chosen container registry an image you have pre-built and deploy it on your kubernetes cluster."),Object(i.b)("p",null,"To improve security and avoid deploying images from non-authorized registries, we have decided to restrict the list of Container Registry you can use during the setup process. Only an administrator with the right permissions can manage it from the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,'Make sure that the image tag used are unique (do not use "latest", "dev", "master" etc..), see ',Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/image-mirroring/#why-unique-image-tags-are-necessary"}),"this section")," for more information.")),Object(i.b)("h2",{id:"create-an-application"},"Create an Application"),Object(i.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,'Go into the chosen environment and press the "New Service" button and then the "Create application" button'),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/creation_1.png",alt:"Creation"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Select the following fields:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Application Name: give a name to your application"),Object(i.b)("li",{parentName:"ul"},"Application Source: Chose between Git Repository or Container Registry, depending on the source location of your application")),Object(i.b)("p",null,"If you want to deploy an application from a Git Repository you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Git Repository: Select the git provider hosting your code (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Branch: Select branch that Qovery should use to deploy your application"),Object(i.b)("li",{parentName:"ul"},"Root Application Path: base folder in which the application resides in your repository"),Object(i.b)("li",{parentName:"ul"},"Build Mode: choose between Docker or Buildpack. For more information, go to ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/application/#build-mode"}),"this section"))),Object(i.b)("p",null,"If you want to deploy an application from a Container Registry you will have to select:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Registry: select the container registry storing the image of your application. Note: only pre-configured registry are available in this list, check the ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," for more information."),Object(i.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this application (example: postgres)"),Object(i.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this application (example: 1.0). "),Object(i.b)("li",{parentName:"ul"},"Image Entrypoint: the entrypoint to be used to launch your applicaiton (not mandatory)"),Object(i.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your applicaiton (not mandatory). We expect the format to be an array. Example ",'["rails", "-h", "0.0.0.0", "-p", "8080", "string"]')),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,'Make sure that the image tag used are unique (do not use "latest", "dev", "master" etc..), see ',Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/image-mirroring/#why-unique-image-tags-are-necessary"}),"this section")," for more information.")),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Auto Deploy ")),Object(i.b)("p",null,"See the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section.")),Object(i.b)("li",null,Object(i.b)("p",null,"Within this section, you will need to define the resources to be assigned to your application at run time."),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"vCPU: the vCPU assigned to each instance of your application. The default is 500m (0.5 vCPU)."),Object(i.b)("li",{parentName:"ul"},"RAM: the amount of RAM assigned to each instance of your application. The default is 512MB."),Object(i.b)("li",{parentName:"ul"},"Number of instances (Application Auto-scaling): select the minimum and the maximum number of instances of your application that can run within your cluster. The number of instances running at an insant t is automatically managed by Kubernetes (Application auto-scaling) and it is based on real-time CPU consumption. When your app goes above 60% of CPU consumption for 5 minutes, your app will be auto-scaled and more instances will be added. It is transparent.\nQovery runs your application on Kubernetes and relies on ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/kubernetes-sigs/metrics-server"}),"metrics-server")," service to auto-scale your app.")),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Please note that in this section you configure the CPU/RAM allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU/RAM.")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/application_creation_resources.png",alt:"Resources"}))),Object(i.b)("li",null,Object(i.b)("p",null,"You can now define one or more ports for your Application. Most of the application needs to be accessed by other services inside or outside your environment over different L7/L4 protocols.\nToday Qovery supports the following protocols:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"HTTPS (Select this protocol if you need to run Websockets)"),Object(i.b)("li",{parentName:"ul"},"gRPC"),Object(i.b)("li",{parentName:"ul"},"TCP"),Object(i.b)("li",{parentName:"ul"},"UDP")),Object(i.b)("p",null,"By default ports are accessible only from inside your environment. You can also expose them publicly, making them accessible over the public network via a dedicated public domain that will be assigned to your application by Qovery during the deployment (See the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"#qovery-provided-domains"}),"Qovery Provided Domains section"),"). Note that HTTPS/gRPC ports are always exposed over the port 443."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/application_creation_port.png",alt:"Application Ports"})),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Important Informations")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Most of the ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/service-health-checks/"}),"Kubernetes Health Checks")," are based on the port declared in this section. Make sure you declare the right port and that you configure the health checks properly."),Object(i.b)("li",{parentName:"ul"},"Connections on public ports are automatically closed after 60 seconds. If you want to implement long living connection (like for websockets) please make sure to use the rigth ingress timeouts in the ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/advanced-settings/#network-settings"}),"advanced settings section")),Object(i.b)("li",{parentName:"ul"},"Exposing publicly TCP/UDP ports requires to create a dedicated load balancer and it takes a few minutes before having it ready (~15 minutes). Note also that this has a direct impact on your cloud provider bill."),Object(i.b)("li",{parentName:"ul"},"You can configure your application to use the ",Object(i.b)("strong",{parentName:"li"},"PORT")," environment variable by adding the ",Object(i.b)("strong",{parentName:"li"},"PORT")," on your application env variables page."),Object(i.b)("li",{parentName:"ul"},"A Note on Listening IPs: It is best for your application to listen on ",Object(i.b)("inlineCode",{parentName:"li"},"0.0.0.0:$PORT"),". While most things work with ",Object(i.b)("inlineCode",{parentName:"li"},"127.0.0.1")," and ",Object(i.b)("inlineCode",{parentName:"li"},"localhost"),", some do not (NodeJS for example)"))),Object(i.b)("li",null,Object(i.b)("p",null,"(Optional) If a port has been defined for your application, you can define the health check probes to run in order to verify the state of your application"),Object(i.b)("p",null,"To know more about how to configure your Liveness and Readiness probes, have a look at ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application-health-checks/"}),"the health-checks section"))),Object(i.b)("li",null,Object(i.b)("p",null,"You will find a recap of your application setup and you can now decide to:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Go back to one of the previous steps and change your application settings"),Object(i.b)("li",{parentName:"ul"},"Create your application without deploying it"),Object(i.b)("li",{parentName:"ul"},"Create and deploy your application")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/application_creation_recap.png",alt:"Application"}))))),Object(i.b)("h2",{id:"deployment-management"},"Deployment Management"),Object(i.b)("p",null,"Have a look at the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/"}),"Deployment Management")," section for more information."),Object(i.b)("h2",{id:"configuration"},"Configuration"),Object(i.b)("p",null,"Once created, you can access the configuration of an application at any time via the Settings tab available on the application section"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/settings.png",alt:"Application Settings"})),Object(i.b)("p",null,"You can find below the description of each of the tabs available in this section"),Object(i.b)("h3",{id:"general"},"General"),Object(i.b)("p",null,"General settings section allows you to set up your application name and the source code location (git repository or image registry) ."),Object(i.b)("h4",{id:"git-repository"},"Git Repository"),Object(i.b)("p",null,"If your application is built and deployed from a git repository, within this section you can:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Modify the git provider where your code is stored (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(i.b)("li",{parentName:"ul"},"Modify the branch that Qovery should use for deploying your application"),Object(i.b)("li",{parentName:"ul"},"Modify ",Object(i.b)("inlineCode",{parentName:"li"},"Root Application Path")," - base folder in which the application resides in your repository")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-general-git.png",alt:"General Settings Git"})),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Qovery supports mono repositories. ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/advanced/monorepository/"}),"See our advanced guide for more details."))),Object(i.b)(c.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"If your repository contains private submodules using SSH protocol, you will need to add a secret beginning with GIT",Object(i.b)("em",{parentName:"p"},"SSH_KEY"),", containing a private SSH key with access rights to your sumbodules repositories."),Object(i.b)("p",null,"Secret names examples:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITHUB"),Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITLAB"),Object(i.b)("li",{parentName:"ul"},"GIT_SSH_KEY_MYAPP"))),Object(i.b)("h4",{id:"container-registry"},"Container Registry"),Object(i.b)("p",null,"If your application is deployed from an image registry, within this section you can modify:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Registry: select the container registry storing the image of your application. Note: only pre-configured registry are available in this list, check the ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," for more information."),Object(i.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this application (example: postgres)"),Object(i.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this application (example: 1.0)."),Object(i.b)("li",{parentName:"ul"},"Image Entrypoint: the entrypoint to be used to launch your applicaiton (not mandatory)"),Object(i.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your applicaiton (not mandatory). We expect the format to be an array. Example ",'["rails", "-h", "0.0.0.0", "-p", "8080", "string"]')),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,'Make sure that the image tag used are unique (do not use "latest", "dev", "master" etc..), see ',Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/image-mirroring/#why-unique-image-tags-are-necessary"}),"this section")," for more information.")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-general-registry.png",alt:"General Settings Git"})),Object(i.b)("h4",{id:"build-mode"},"Build Mode"),Object(i.b)("p",null,'This option is available only if you have selected "Git Repository" as source'),Object(i.b)("h4",{id:"option-1-buildpacks"},"Option 1: Buildpacks"),Object(i.b)("p",null,"To simplify the application build for the developer, Qovery supports ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://buildpacks.io"}),"Buildpacks")," out of the box. Buildpacks determine the build process for an app and which assets and runtimes should be made available to your code at runtime. If your complex apps are running multiple languages, you can also use multiple buildpacks within a single app.\nMeaning, as a developer, you don't need to write a ",Object(i.b)("inlineCode",{parentName:"p"},"Dockerfile")," to build and run your app. Qovery Buildpacks takes care of everything for you."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Supported languages")),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"language"),Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"version"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Node.JS"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Clojure"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Python"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Java"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Gradle"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"JVM"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Grails"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Scala"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Play"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"PHP"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Go"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"any")))),Object(i.b)("p",null,"You don't find a cool language? ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://roadmap.qovery.com/"}),"Suggest us to support it")),Object(i.b)("h4",{id:"option-2-dockerfile"},"Option 2: Dockerfile"),Object(i.b)("p",null,"Qovery runs your application within the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.docker.com/resources/what-container"}),"Container technology"),". To build and run your application, you need to provide a valid ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.docker.com/engine/reference/builder"}),"Dockerfile"),"."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-Dockerfile",metastring:'title="Valid NodeJS Dockerfile"',title:'"Valid',NodeJS:!0,'Dockerfile"':!0}),"FROM node:13-alpine\nRUN mkdir -p /usr/src/app\nWORKDIR /usr/src/app\nCOPY . .\nRUN npm install\nEXPOSE 3000\nCMD node ./bin/www\n")),Object(i.b)("p",null,"After creating a Dockerfile, specify the location of your Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"Dockefile path")," field."),Object(i.b)("p",null,"Configuration from above will make Qovery look for the Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"/timescale/Dockerfile")," path of your repository (",Object(i.b)("inlineCode",{parentName:"p"},"Root Application Path")," + ",Object(i.b)("inlineCode",{parentName:"p"},"Dockerfile Path"),")."),Object(i.b)("h4",{id:"auto-deploy"},"Auto Deploy"),Object(i.b)("p",null,"See the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section."),Object(i.b)("h3",{id:"resources"},"Resources"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-13.png",alt:"CPU"})),Object(i.b)("h4",{id:"cpu"},"CPU"),Object(i.b)("p",null,"To configure the number of CPUs that your app needs, adjust the setting in the ",Object(i.b)("inlineCode",{parentName:"p"},"Resources")," section of the application configuration."),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Default is 500m (0.5 vCPU). ")),Object(i.b)("p",null,"Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consumes fewer resources, the cluster will still reserve the selected amount of CPU."),Object(i.b)("h4",{id:"ram"},"RAM"),Object(i.b)("p",null,"To configure the amount of RAM that your app needs, adjust the setting in ",Object(i.b)("inlineCode",{parentName:"p"},"Resources")," section of the application configuration."),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Default is 512MB.")),Object(i.b)("p",null,"Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU. If your application requires more RAM than requested, it will be killed by the kubernetes scheduler."),Object(i.b)("h4",{id:"auto-scaling"},"Auto-scaling"),Object(i.b)("p",null,"Application auto-scaling is based on real-time CPU consumption. When your app goes above 60% of CPU consumption for 15 seconds, your app will be auto-scaled and more instances will be added. It is transparent. The downscale will happen if the CPU consumption is lower than 60% for at least 5 minutes.\nYou can adjust the minimum and maximum of instances you need in your application settings. Qovery runs your application on Kubernetes and relies on ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/kubernetes-sigs/metrics-server"}),"metrics-server")," service to auto-scale your app."),Object(i.b)("h3",{id:"storage"},"Storage"),Object(i.b)("h4",{id:"block-storage"},"Block Storage"),Object(i.b)("p",null,"The default filesystem for applications running on Qovery is ephemeral. Application data isn\u2019t persisted across deploys and restarts, which works just fine for most apps because they use managed databases to persist data."),Object(i.b)("p",null,"However, many applications need persistent disk storage that isn\u2019t ephemeral. These include:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Blogging platforms and CMSs like WordPress, Ghost, and Strapi."),Object(i.b)("li",{parentName:"ul"},"Collaboration apps like Mattermost, GitLab, and Discourse.")),Object(i.b)("p",null,"This is where Qovery block Storage comes in. Qovery applications can use storage to store data that persists across deploys and restarts, making it easy to deploy stateful applications."),Object(i.b)(c.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"For most use cases, it is better to use ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/object-storage/"}),"Object Storage")," instead of Block Storage.")),Object(i.b)("h6",{id:"use-cases"},"Use cases"),Object(i.b)("h6",{id:"-good-use-cases"},"\u2705 Good use cases"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"For I/O intensive applications (E.g. database)"),Object(i.b)("li",{parentName:"ul"},"To store temporary files")),Object(i.b)("h6",{id:"-bad-use-cases"},"\u274c Bad use cases"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"To store file > 1 TB"),Object(i.b)("li",{parentName:"ul"},"To expose files from an application (E.g. images)")),Object(i.b)("h5",{id:"types-of-block-storage"},"Types of Block Storage"),Object(i.b)("p",null,"Qovery Storage supports:"),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Type"),Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Max IOPS"),Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Max Throughput"),Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Min Size"),Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Max Size"),Object(i.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Use cases"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"fast_ssd"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"64000"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"1GB/s"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"5GB"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"10GB ",Object(i.b)("inlineCode",{parentName:"td"},"Community")," / 1TB paid plans"),Object(i.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Critical business applications that require sustained IOPS like databases")))),Object(i.b)("h5",{id:"configuration-1"},"Configuration"),Object(i.b)("p",null,"You can set up your Block Storage in ",Object(i.b)("inlineCode",{parentName:"p"},"Storage")," section of your application configuration."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-7.png",alt:"Application Storage"})),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Storage can be added only if the application has never been deployed before AND if it runs only with one instance (check the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#resources"}),"Resources section"),")")),Object(i.b)("h3",{id:"ports"},"Ports"),Object(i.b)("p",null,"Within this section you can define the port exposed by your application to the other services or even over the internet.\nYou can edit the existing ports or declare new ones by specifying:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Application port: this is the port exposed internally by your application for the other services. "),Object(i.b)("li",{parentName:"ul"},"Protocol: you can select the protocol used by your application : HTTP (for both standard HTTP or websocket communications), gRPC, TCP, UDP."),Object(i.b)("li",{parentName:"ul"},"Publicly exposed: it allows you to expose over the public network your service. A public domain will be assigned to your application during the deployment (see ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#connecting-from-the-internet"}),"Connectin from the internet section"),")"),Object(i.b)("li",{parentName:"ul"},"If Publicly Exposed is selected:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"External port: it is the port that can be used to access this service over the internet (when exposed publicly). Note that for HTTP and gRPC the port is set by default to 443."),Object(i.b)("li",{parentName:"ul"},"Port Name: it is the name assigned to the port. When multiple ports are exposed publicly, its value is used to route the traffic to the right port based on the called subdomain (which will contain the port name value). Since each port is exposed on the port 443, having a different subdomain is the only way to have multiple ports exposed over the internet. If not set, the default value is ",Object(i.b)("inlineCode",{parentName:"li"},"p")," (see ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#qovery-provided-domains"}),"Qovery Provided Domain section")," for more information)")))),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-15.png",alt:"Application Ports"})),Object(i.b)("h4",{id:"important-informations"},"Important Informations"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Most of the Kubernetes Health Checks]",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/service-health-checks/"}),"docs.using-qovery.configuration.service-health-checks")," are based on the port declared in this section. Make sure you declare the right port and that you configure the health checks properly."),Object(i.b)("li",{parentName:"ul"},"Connections on public ports are automatically closed after 60 seconds. If you want to implement long living connection (like for websockets) please make sure to use the rigth ingress timeouts in the ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/advanced-settings/#network-settings"}),"advanced settings section")),Object(i.b)("li",{parentName:"ul"},"Exposing publicly TCP/UDP ports requires to create a dedicated load balancer and it takes a few minutes before having it ready (~15 minutes). Note also that this has a direct impact on your cloud provider bill."),Object(i.b)("li",{parentName:"ul"},"You can configure your application to use the ",Object(i.b)("strong",{parentName:"li"},"PORT")," environment variable by adding the ",Object(i.b)("strong",{parentName:"li"},"PORT")," on your application env variables page."),Object(i.b)("li",{parentName:"ul"},"A Note on Listening IPs: It's best for your application to listen on ",Object(i.b)("inlineCode",{parentName:"li"},"0.0.0.0:$PORT"),". While most things work with ",Object(i.b)("inlineCode",{parentName:"li"},"127.0.0.1")," and ",Object(i.b)("inlineCode",{parentName:"li"},"localhost"),", some do not (NodeJS for example)")),Object(i.b)("h3",{id:"health-checks"},"Health Checks"),Object(i.b)("p",null,"To know more about how to configure your Liveness and Readiness probes, have a look at ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application-health-checks/"}),"the health-checks section")),Object(i.b)("h3",{id:"domains"},"Domains"),Object(i.b)("p",null,"Within this section you can customize the domain used to reach your application. "),Object(i.b)("p",null,"You can customize the domain of your application in different ways, depending on what you want to achieve:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"You want to use your own domain for your application"),Object(i.b)("li",{parentName:"ul"},"You want to modify the subdomain assigned to your application by Qovery (i.e. change ",Object(i.b)("inlineCode",{parentName:"li"},"p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh")," into ",Object(i.b)("inlineCode",{parentName:"li"},"my-app-domain.za8ad0657.bool.sh"),").")),Object(i.b)("p",null,"In both cases, you can assign the new custom domain to your application press the ",Object(i.b)("inlineCode",{parentName:"p"},"Add Domain")," button. "),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-16.png",alt:"Application Domains"})),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"This configuration will be ",Object(i.b)("strong",{parentName:"p"},"automatically removed")," on every cloned environment or preview environment in order to avoid domain collision.")),Object(i.b)("h4",{id:"configuring-your-own-domain"},"Configuring your own domain"),Object(i.b)("p",null,"Once the domain is added within the Qovery console (Example: mydomain.com), you need to configure within your DNS two ",Object(i.b)("inlineCode",{parentName:"p"},"CNAME")," records pointing to the domain provided by Qovery, as shown in the UI (example: mydomain.com CNAME za7cc1b71-z4b8474b3-gtw.zc531a994.rustrocks.cloud and *.mydomain.com CNAME za7cc1b71-z4b8474b3-gtw.zc531a994.rustrocks.cloud). "),Object(i.b)("p",null,"Having a wildcard domain (example: *.mydomain.com) configured on your DNS will avoid you to modify the Qovery setup every time you want to add a new subdomain. If ",Object(i.b)("inlineCode",{parentName:"p"},"wildcard")," is not supported by your DNS provider, you will have to configure each subdomain manually."),Object(i.b)("p",null,"If the service needs to expose more than one port publicly, you can define a dedicated subdomain to redirect the traffic on the right port by setting the \u201cPort Name\u201d value within the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"#ports"}),"port settings"),"."),Object(i.b)("p",null,"From this point, Qovery will automatically handle the TLS/SSL certificate creation and renewal for the configured domain."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/custom-domain.png",alt:"Custom Domain"})),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Special case - CDN in proxy mode ")),Object(i.b)("p",null,"If your service is behind a CDN using a ",Object(i.b)("inlineCode",{parentName:"p"},"proxy mode"),' (i.e. the traffic is routed through the CDN to Qovery), make sure to disable the option "Generate certificate" on the domain setup. Since the certificate of your domain is directly managed by the CDN, Qovery won\'t be able to do that for you and it will raise warnings on your application status.'),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/cdn-proxy.png",alt:"CDN Proxy"})),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/setting-custom-domain/"}),"We prepared a guide and video tutorial that explains how to set up your custom domain."))),Object(i.b)("h4",{id:"change-the-auto-assigned-sub-domain"},"Change the auto assigned sub-domain"),Object(i.b)("p",null,"You can specify a different sub-domain for your application as long as it belongs to the assigned cluster domain (see ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"#qovery-provided-domains"}),"Qovery provided domains"),").\nExample: "),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"your current domain is zdf72de71-z709e1a85-gtw.za8ad0659.bool.sh (so your assigned cluster domain is ",Object(i.b)("inlineCode",{parentName:"li"},"za8ad0659.bool.sh"),")"),Object(i.b)("li",{parentName:"ul"},"you can enter a new custom domain ",Object(i.b)("inlineCode",{parentName:"li"},"myfrontend.za8ad0659.bool.sh")," (since it is a subdomain of the cluster domain)")),Object(i.b)("p",null,"The application will now be accessible from both the default and the new custom domain."),Object(i.b)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Qovery does not check collision in the domain declaration. Make sure you assign a unique subdomain within your cluster.")),Object(i.b)("h2",{id:"connecting-from-the-internet"},"Connecting from the internet"),Object(i.b)("p",null,"Your application can be reached from the internet by publicly exposing at least one of its ports (See the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"#ports"}),"Ports")," section to know more). Once this is done, Qovery will generate for you a domain to reach your application from the internet. You can also customize the domain assigned to your application and manage by yourself this assignment via the ",Object(i.b)("inlineCode",{parentName:"p"},"Domain")," section."),Object(i.b)("h3",{id:"qovery-provided-domains"},"Qovery provided domains"),Object(i.b)("p",null,"For each port publicly exposed, a domain is automatically assigned by Qovery to your application. Qovery will manage for you the networking and the TLS configuration for these domains. "),Object(i.b)("p",null,"Example: ",Object(i.b)("inlineCode",{parentName:"p"},"p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh")," or ",Object(i.b)("inlineCode",{parentName:"p"},"-p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh")," for helm services."),Object(i.b)("p",null,"Note:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"each service deployed on the same cluster will have the same root domain assigned (example: ",Object(i.b)("inlineCode",{parentName:"li"},"za8ad0657.bool.sh"),")"),Object(i.b)("li",{parentName:"ul"},"the first characters of the domain (before the ",Object(i.b)("inlineCode",{parentName:"li"},"-"),") is based on the portName given to the port associated with this domain (See the ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#ports"}),"port section"),")"),Object(i.b)("li",{parentName:"ul"},"a default domain (without the portName) is assigned to the ",Object(i.b)("inlineCode",{parentName:"li"},"default port"),"(See the ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#ports"}),"port section"),"). Example ",Object(i.b)("inlineCode",{parentName:"li"},"zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh"))),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Special Case - Preview Environment"),"\nFor each port exposed publicly, an additional domain will be created with the following pattern ",Object(i.b)("inlineCode",{parentName:"p"},"portName-prId-srvName-envSourceName.cluster_domain"),":"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"portName: is the port name, as explained above"),Object(i.b)("li",{parentName:"ul"},"prID: is the id of the PR that has generated the preview environment"),Object(i.b)("li",{parentName:"ul"},"srvName: is the name of the service"),Object(i.b)("li",{parentName:"ul"},"envSourceName: is the name of the blueprint environment that has created the current preview environment")),Object(i.b)("p",null,"domain example: ",Object(i.b)("inlineCode",{parentName:"p"},"p80-123-frontend-blueprint.za8ad0657.bool.sh")),Object(i.b)("h3",{id:"custom-domains"},"Custom domains"),Object(i.b)("p",null,"If you prefer to assign your own domain to the application, have a look at the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"#domains"}),"Domain section")," to know more."),Object(i.b)("h2",{id:"connecting-to-a-database"},"Connecting to a database"),Object(i.b)("p",null,"To know how to access your database from your application, ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-a-database"}),"have a look at the database section"),"."),Object(i.b)("h2",{id:"connecting-to-another-application"},"Connecting to another application"),Object(i.b)("p",null,"To know how to access your database from your application, ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-another-application"}),"have a look at the database section"),"."),Object(i.b)("h2",{id:"environment-variable"},"Environment Variable"),Object(i.b)("p",null,"To learn how to set up environment variables in your projects and applications, navigate to ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Environment Variables")," section."),Object(i.b)("h2",{id:"secrets"},"Secrets"),Object(i.b)("p",null,"To learn how to set up secrets in your projects and applications, navigate to ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Secrets")," section."),Object(i.b)("h2",{id:"logs"},"Logs"),Object(i.b)("p",null,"To learn how to display your application logs, navigate to ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#live-logs"}),"logs section")),Object(i.b)("h2",{id:"ssh"},"SSH"),Object(i.b)("p",null,"To connect to your application via SSH, please use the via the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery SSH command")," available on our CLI."),Object(i.b)("h2",{id:"clone"},"Clone"),Object(i.b)("p",null,"You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/clone_service.png",alt:"Clone Service"})),Object(i.b)("p",null,"The target environment can be the same as the current environment or even another one in a completely different project."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Important information ")),Object(i.b)("p",null,"Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"same environment:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"))),Object(i.b)("li",{parentName:"ul"},"another environment:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"),Object(i.b)("li",{parentName:"ul"},"environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)"),Object(i.b)("li",{parentName:"ul"},"deployment pipeline: stage setup is not copied (since the target stage might not exist)"),Object(i.b)("li",{parentName:"ul"},"number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)")))),Object(i.b)("p",null,"Please check the configuration of the new service before deploying it."),Object(i.b)("h2",{id:"delete-an-application"},"Delete an Application"),Object(i.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Choose your application")),Object(i.b)("li",null,Object(i.b)("p",null,"In the application overview, click on the ",Object(i.b)("inlineCode",{parentName:"p"},"3 dots")," button and remove the application."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/application/app-1.png",alt:"Application"}))))))}d.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),p=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},b=function(e){var t=p(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,r=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=p(n),d=a,m=b["".concat(r,".").concat(d)]||b[d]||u[d]||i;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,r[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=r>2?arguments[2]:void 0,s=void 0===l?n:o(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var a=n(28).f,o=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in o||n(10)&&a(o,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),o=n.n(a),i=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),o=n(0),i=n.n(o),r=n(39),c=n(432),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,p=n||l,b=Object(c.a)(p),u=Object(o.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(p),function(){d&&t&&t.disconnect()}}),[p,d,b]),p&&b?i.a.createElement(r.b,Object(a.a)({},e,{onMouseEnter:function(){u.current||(window.docusaurus.preload(p),u.current=!0)},innerRef:function(e){var n,a;d&&e&&b&&(n=e,a=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:p})):i.a.createElement("a",Object(a.a)({},e,{href:p}))}},431:function(e,t,n){"use strict";var a=n(0),o=n.n(a),i=n(430),r=n(423),c=n.n(r);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,r=e.leftIcon,l=e.rightIcon,s=e.size,p=e.target,b=e.to,u=c()("jump-to","jump-to--"+s,n),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},r&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+r})),o.a.createElement("div",{className:"jump-to--main"},a?o.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return p?o.a.createElement("a",{href:b,target:p,className:u},d):o.a.createElement(i.a,{to:b,className:u},d)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},433:function(e,t,n){"use strict";var a=n(435),o=n(51);function i(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(o),i,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[i(t,e),"[",a,"]"].join(""):[i(t,e),"[",i(a,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var o=e[a];if(void 0===o)return"";if(null===o)return i(a,t);if(Array.isArray(o)){var r=[];return o.slice().forEach((function(e){void 0!==e&&r.push(n(a,e,r.length))})),r.join("&")}return i(a,t)+"="+i(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var a=n(0),o=n.n(a),i=(n(423),n(433)),r=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+r.a.stringify(l),p=Object(a.useState)(null),b=p[0],u=p[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!b&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return u("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/9107e302.d0a165fc.js.LICENSE.txt b/8d5726d6.f7ba9f14.js.LICENSE.txt similarity index 100% rename from 9107e302.d0a165fc.js.LICENSE.txt rename to 8d5726d6.f7ba9f14.js.LICENSE.txt diff --git a/8f02216a.59eeb2b1.js b/8f02216a.992fe6b6.js similarity index 90% rename from 8f02216a.59eeb2b1.js rename to 8f02216a.992fe6b6.js index ab40b52b2c..2e184d0cfe 100644 --- a/8f02216a.59eeb2b1.js +++ b/8f02216a.992fe6b6.js @@ -1,2 +1,2 @@ -/*! For license information please see 8f02216a.59eeb2b1.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[141],{293:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return l})),r.d(t,"rightToc",(function(){return u})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),o=(r(0),r(422)),c=(r(431),r(426),r(421)),i={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Helm Charts",description:"Learn how to deploy Helm charts with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: helm"]},l={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Helm Charts",description:"Learn how to deploy Helm charts with Qovery",permalink:"/guides/advanced/helm-chart",readingTime:"1 min read",source:"@site/guides/advanced/helm-chart.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: helm",permalink:"/guides/tags/technology-helm"}],title:"Helm Charts",truncated:!1,prevItem:{title:"Grafana setup with Qovery",permalink:"/guides/tutorial/grafana-install"},nextItem:{title:"How to activate SSO to connect to your EKS cluster",permalink:"/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster"}},u=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:u};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery runs on top of Kubernetes and allows you to deploy any Helm chart on your cluster. To learn more about Helm, please visit the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://helm.sh"}),"official website"),"."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to deploy your Helm Charts with Qovery."),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Helm Charts is an advanced way to deploy your applications on Qovery. If you are new to Qovery, we recommend you to start with the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"Getting Started guide"),".")),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Official"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-deploy-helm-charts/"}),"Deploy your Helm Charts")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-deploy-helm-charts/"}),"How to deploy your Helm Charts (example with Kubecost)")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Yes")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=helm%20charts"}),"Forum")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=helm%20charts"}),'List "Helm Charts" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},420:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,b=p["".concat(c,".").concat(d)]||p[d]||m[d]||o;return r?a.a.createElement(b,i({ref:t},u,{components:r})):a.a.createElement(b,i({ref:t},u))}));function b(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,c=new Array(o);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var u=2;u1?arguments[1]:void 0,r),l=c>2?arguments[2]:void 0,u=void 0===l?r:a(l,r);u>i;)t[i++]=e;return t}},425:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,r){"use strict";r(425);var n=r(0),a=r.n(n),o=r(421);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},428:function(e,t,r){"use strict";var n=r(432),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var c=[];return a.slice().forEach((function(e){void 0!==e&&c.push(r(n,e,c.length))})),c.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(420),r(428)),c=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(n.useState)(null),p=s[0],m=s[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return m("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 8f02216a.992fe6b6.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[144],{296:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return l})),r.d(t,"rightToc",(function(){return u})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),o=(r(0),r(425)),c=(r(434),r(429),r(424)),i={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Helm Charts",description:"Learn how to deploy Helm charts with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: helm"]},l={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Helm Charts",description:"Learn how to deploy Helm charts with Qovery",permalink:"/guides/advanced/helm-chart",readingTime:"1 min read",source:"@site/guides/advanced/helm-chart.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: helm",permalink:"/guides/tags/technology-helm"}],title:"Helm Charts",truncated:!1,prevItem:{title:"Grafana setup with Qovery",permalink:"/guides/tutorial/grafana-install"},nextItem:{title:"How to activate SSO to connect to your EKS cluster",permalink:"/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster"}},u=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:u};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery runs on top of Kubernetes and allows you to deploy any Helm chart on your cluster. To learn more about Helm, please visit the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://helm.sh"}),"official website"),"."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to deploy your Helm Charts with Qovery."),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Helm Charts is an advanced way to deploy your applications on Qovery. If you are new to Qovery, we recommend you to start with the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"Getting Started guide"),".")),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Official"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-deploy-helm-charts/"}),"Deploy your Helm Charts")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-deploy-helm-charts/"}),"How to deploy your Helm Charts (example with Kubecost)")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Yes")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=helm%20charts"}),"Forum")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=helm%20charts"}),'List "Helm Charts" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,b=p["".concat(c,".").concat(d)]||p[d]||m[d]||o;return r?a.a.createElement(b,i({ref:t},u,{components:r})):a.a.createElement(b,i({ref:t},u))}));function b(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,c=new Array(o);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var u=2;u1?arguments[1]:void 0,r),l=c>2?arguments[2]:void 0,u=void 0===l?r:a(l,r);u>i;)t[i++]=e;return t}},428:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,r){"use strict";r(428);var n=r(0),a=r.n(n),o=r(424);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},433:function(e,t,r){"use strict";var n=r(435),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var c=[];return a.slice().forEach((function(e){void 0!==e&&c.push(r(n,e,c.length))})),c.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(423),r(433)),c=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(n.useState)(null),p=s[0],m=s[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return m("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/91473650.416d72af.js.LICENSE.txt b/8f02216a.992fe6b6.js.LICENSE.txt similarity index 100% rename from 91473650.416d72af.js.LICENSE.txt rename to 8f02216a.992fe6b6.js.LICENSE.txt diff --git a/9107e302.d0a165fc.js b/9107e302.472e02ef.js similarity index 92% rename from 9107e302.d0a165fc.js rename to 9107e302.472e02ef.js index c9f6cc920b..ca5d210020 100644 --- a/9107e302.d0a165fc.js +++ b/9107e302.472e02ef.js @@ -1,2 +1,2 @@ -/*! For license information please see 9107e302.d0a165fc.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[142],{294:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),o=(n(0),n(422)),i=n(421),c=(n(426),n(429),{last_modified_on:"2023-04-24",$schema:"/.meta/.schemas/guides.json",title:"How to seed a Postgres database on a dev environment",description:"How to automatically inject data into your development Postgres databases",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to seed a Postgres database on a dev environment",description:"How to automatically inject data into your development Postgres databases",permalink:"/guides/tutorial/data-seeding-in-postgres",readingTime:"4 min read",source:"@site/guides/tutorial/data-seeding-in-postgres.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to seed a Postgres database on a dev environment",truncated:!1,prevItem:{title:"How to run commands before the application starts",permalink:"/guides/tutorial/how-to-run-commands-at-application-startup"},nextItem:{title:"How to use CloudFront with a React frontend application on Qovery",permalink:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery"}},l=[{value:"Seeding SQL",id:"seeding-sql",children:[]},{value:"Migration Script",id:"migration-script",children:[]},{value:"Seeding",id:"seeding",children:[]},{value:"Example",id:"example",children:[{value:"Clone Environment",id:"clone-environment",children:[]},{value:"Preview Environment",id:"preview-environment",children:[]}]}],u={rightToc:l};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Consider using ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.replibyte.com"}),"Replibyte")," to seed your development database with real data")),Object(o.b)("p",null,"The goal of this article is to go through the process of seeding data into development environments on Qovery. Seeding the data into dev environments may help you set up clean development environments and thus speed up the development lifecycle in your team. It can be extremely useful for cloning and creating new environments or using the ",Object(o.b)("inlineCode",{parentName:"p"},"Preview Environment")," feature on Qovery."),Object(o.b)("p",null,"In this guide, we\u2019ll use a ",Object(o.b)("inlineCode",{parentName:"p"},"Node.js")," backend and ",Object(o.b)("inlineCode",{parentName:"p"},"Postgres")," database."),Object(o.b)("h2",{id:"seeding-sql"},"Seeding SQL"),Object(o.b)("p",null,"In the first step, let\u2019s create an idempotent script that will seed our development databases. During the development process, we should expect that the state of the database will be synced with the content of this script."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-sql"}),"DROP TABLE IF EXISTS _USER;\n\nCREATE TABLE _USER(\n ID INT PRIMARY KEY NOT NULL,\n FIRST_NAME VARCHAR(255) NOT NULL,\n LAST_NAME VARCHAR(50) NOT NULL\n);\n\nINSERT INTO _USER (ID, FIRST_NAME, LAST_NAME)\nVALUES (1, 'John', 'Doe');\n\nINSERT INTO _USER (ID, FIRST_NAME, LAST_NAME)\nVALUES (2, 'Alice', 'Wonderland');\n")),Object(o.b)("p",null,"The example above contains only a single table - the SQL script is specific to your application, so you\u2019ll have to create your own that reflects the schema and database state you would expect in the dev environment."),Object(o.b)("p",null,"Keep in mind that the script should be idempotent as there are chances it will be executed more than once against a single database during your development process."),Object(o.b)("h2",{id:"migration-script"},"Migration Script"),Object(o.b)("p",null,"In the next step, we\u2019ll create a script that will be used to connect to the database and seed the data."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const fs = require('fs')\nconst { Pool } = require('pg')\n\nrequire(\"dotenv\").config()\nconst databaseUrl = process.env.DATABASE_URL || 'postgresql://localhost:5432/test';\nconst pool = new Pool({\n connectionString: databaseUrl,\n})\n\nif (process.env.NODE_ENV !== 'production') {\n const seedQuery = fs.readFileSync('db/seeding.sql', { encoding: 'utf8' })\n pool.query(seedQuery, (err, res) => {\n console.log(err, res)\n console.log('Seeding Completed!')\n pool.end()\n })\n}\n")),Object(o.b)("p",null,"The script connects to our Postgres instance, reads the seeding SQL, and makes the required updates. It does it only for non-prod environments thanks to the ",Object(o.b)("inlineCode",{parentName:"p"},"NODE_ENV")," environment variable."),Object(o.b)("p",null,"To make our life easier, we can declare the seeding command in our ",Object(o.b)("inlineCode",{parentName:"p"},"package.json"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{}),'...\n"seed": "node db/index.js"\n...\n')),Object(o.b)("h2",{id:"seeding"},"Seeding"),Object(o.b)("p",null,"To seed the data, we\u2019ll use ",Object(o.b)("inlineCode",{parentName:"p"},"ENTRYPOINT")," in our ",Object(o.b)("inlineCode",{parentName:"p"},"Dockerfile"),". For more details, you can read ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"our guide"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-docker"}),'FROM node:16\n\n# Create app directory\nWORKDIR /usr/src/app\n\n# Install app dependencies\n# A wildcard is used to ensure both package.json AND package-lock.json are copied\n# where available (npm@5+)\nCOPY package*.json ./\n\nRUN npm install\n# If you are building your code for production\n# RUN npm ci --only=production\n\n# Bundle app source\nCOPY . .\n\nEXPOSE 3000\n\nENTRYPOINT ["./entrypoint.sh"]\n\nCMD [ "node", "bin/www" ]\n\n')),Object(o.b)("p",null,"Add ",Object(o.b)("inlineCode",{parentName:"p"},"entrypoint.sh")," file to be executed on each environment where the app container runs:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'#! /bin/sh\n\nnode db/index.js\n\n# Execute the given or default command:\n\nexec "$@"\n')),Object(o.b)("h2",{id:"example"},"Example"),Object(o.b)("p",null,"The following examples will show the application of seeding the data in dev environments after cloning an environment and using the Preview Environment feature."),Object(o.b)("h3",{id:"clone-environment"},"Clone Environment"),Object(o.b)("p",null,"Clone environment feature allows you to make a complete clone of a chosen environment, including its all applications, services, and their configs. In the example we will clone a new environment and have our seed data injected automatically."),Object(o.b)("p",null,"First, we make a clone of our production environment:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/1.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"Then, we deploy the new environment:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/2.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"After navigating to deployment logs, we will notice our seed data inserts logged:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/3.png",alt:"Seeding Postgres Database"})),Object(o.b)("h3",{id:"preview-environment"},"Preview Environment"),Object(o.b)("p",null,"Preview Environment feature allows you to automatically create new development environments to validate new changes before merging them to your production branch."),Object(o.b)("p",null,"First, we open a pull request:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/4.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"Then, in list of environments, we get a new environment automatically created for the pull request:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/5.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"When you open the logs of the deployment, you\u2019ll see the seed data injection logs:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/6.png",alt:"Seeding Postgres Database"})))}p.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),u=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},b=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),b=a,m=p["".concat(i,".").concat(b)]||p[b]||d[b]||o;return n?r.a.createElement(m,c({ref:t},l,{components:n})):r.a.createElement(m,c({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:r(s,n);l>c;)t[c++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(430),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,p=Object(c.a)(u),d=Object(r.useRef)(!1),b=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!b&&p&&window.docusaurus.prefetch(u),function(){b&&t&&t.disconnect()}}),[u,b,p]),u&&p?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(u),d.current=!0)},innerRef:function(e){var n,a;b&&e&&p&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,d=c()("jump-to","jump-to--"+l,n),b=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:p,target:u,className:d},b):r.a.createElement(o.a,{to:p,className:d},b)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see 9107e302.472e02ef.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[145],{297:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),o=(n(0),n(425)),i=n(424),c=(n(429),n(431),{last_modified_on:"2023-04-24",$schema:"/.meta/.schemas/guides.json",title:"How to seed a Postgres database on a dev environment",description:"How to automatically inject data into your development Postgres databases",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to seed a Postgres database on a dev environment",description:"How to automatically inject data into your development Postgres databases",permalink:"/guides/tutorial/data-seeding-in-postgres",readingTime:"4 min read",source:"@site/guides/tutorial/data-seeding-in-postgres.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to seed a Postgres database on a dev environment",truncated:!1,prevItem:{title:"How to run commands before the application starts",permalink:"/guides/tutorial/how-to-run-commands-at-application-startup"},nextItem:{title:"How to use CloudFront with a React frontend application on Qovery",permalink:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery"}},l=[{value:"Seeding SQL",id:"seeding-sql",children:[]},{value:"Migration Script",id:"migration-script",children:[]},{value:"Seeding",id:"seeding",children:[]},{value:"Example",id:"example",children:[{value:"Clone Environment",id:"clone-environment",children:[]},{value:"Preview Environment",id:"preview-environment",children:[]}]}],u={rightToc:l};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Consider using ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.replibyte.com"}),"Replibyte")," to seed your development database with real data")),Object(o.b)("p",null,"The goal of this article is to go through the process of seeding data into development environments on Qovery. Seeding the data into dev environments may help you set up clean development environments and thus speed up the development lifecycle in your team. It can be extremely useful for cloning and creating new environments or using the ",Object(o.b)("inlineCode",{parentName:"p"},"Preview Environment")," feature on Qovery."),Object(o.b)("p",null,"In this guide, we\u2019ll use a ",Object(o.b)("inlineCode",{parentName:"p"},"Node.js")," backend and ",Object(o.b)("inlineCode",{parentName:"p"},"Postgres")," database."),Object(o.b)("h2",{id:"seeding-sql"},"Seeding SQL"),Object(o.b)("p",null,"In the first step, let\u2019s create an idempotent script that will seed our development databases. During the development process, we should expect that the state of the database will be synced with the content of this script."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-sql"}),"DROP TABLE IF EXISTS _USER;\n\nCREATE TABLE _USER(\n ID INT PRIMARY KEY NOT NULL,\n FIRST_NAME VARCHAR(255) NOT NULL,\n LAST_NAME VARCHAR(50) NOT NULL\n);\n\nINSERT INTO _USER (ID, FIRST_NAME, LAST_NAME)\nVALUES (1, 'John', 'Doe');\n\nINSERT INTO _USER (ID, FIRST_NAME, LAST_NAME)\nVALUES (2, 'Alice', 'Wonderland');\n")),Object(o.b)("p",null,"The example above contains only a single table - the SQL script is specific to your application, so you\u2019ll have to create your own that reflects the schema and database state you would expect in the dev environment."),Object(o.b)("p",null,"Keep in mind that the script should be idempotent as there are chances it will be executed more than once against a single database during your development process."),Object(o.b)("h2",{id:"migration-script"},"Migration Script"),Object(o.b)("p",null,"In the next step, we\u2019ll create a script that will be used to connect to the database and seed the data."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const fs = require('fs')\nconst { Pool } = require('pg')\n\nrequire(\"dotenv\").config()\nconst databaseUrl = process.env.DATABASE_URL || 'postgresql://localhost:5432/test';\nconst pool = new Pool({\n connectionString: databaseUrl,\n})\n\nif (process.env.NODE_ENV !== 'production') {\n const seedQuery = fs.readFileSync('db/seeding.sql', { encoding: 'utf8' })\n pool.query(seedQuery, (err, res) => {\n console.log(err, res)\n console.log('Seeding Completed!')\n pool.end()\n })\n}\n")),Object(o.b)("p",null,"The script connects to our Postgres instance, reads the seeding SQL, and makes the required updates. It does it only for non-prod environments thanks to the ",Object(o.b)("inlineCode",{parentName:"p"},"NODE_ENV")," environment variable."),Object(o.b)("p",null,"To make our life easier, we can declare the seeding command in our ",Object(o.b)("inlineCode",{parentName:"p"},"package.json"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{}),'...\n"seed": "node db/index.js"\n...\n')),Object(o.b)("h2",{id:"seeding"},"Seeding"),Object(o.b)("p",null,"To seed the data, we\u2019ll use ",Object(o.b)("inlineCode",{parentName:"p"},"ENTRYPOINT")," in our ",Object(o.b)("inlineCode",{parentName:"p"},"Dockerfile"),". For more details, you can read ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"our guide"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-docker"}),'FROM node:16\n\n# Create app directory\nWORKDIR /usr/src/app\n\n# Install app dependencies\n# A wildcard is used to ensure both package.json AND package-lock.json are copied\n# where available (npm@5+)\nCOPY package*.json ./\n\nRUN npm install\n# If you are building your code for production\n# RUN npm ci --only=production\n\n# Bundle app source\nCOPY . .\n\nEXPOSE 3000\n\nENTRYPOINT ["./entrypoint.sh"]\n\nCMD [ "node", "bin/www" ]\n\n')),Object(o.b)("p",null,"Add ",Object(o.b)("inlineCode",{parentName:"p"},"entrypoint.sh")," file to be executed on each environment where the app container runs:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'#! /bin/sh\n\nnode db/index.js\n\n# Execute the given or default command:\n\nexec "$@"\n')),Object(o.b)("h2",{id:"example"},"Example"),Object(o.b)("p",null,"The following examples will show the application of seeding the data in dev environments after cloning an environment and using the Preview Environment feature."),Object(o.b)("h3",{id:"clone-environment"},"Clone Environment"),Object(o.b)("p",null,"Clone environment feature allows you to make a complete clone of a chosen environment, including its all applications, services, and their configs. In the example we will clone a new environment and have our seed data injected automatically."),Object(o.b)("p",null,"First, we make a clone of our production environment:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/1.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"Then, we deploy the new environment:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/2.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"After navigating to deployment logs, we will notice our seed data inserts logged:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/3.png",alt:"Seeding Postgres Database"})),Object(o.b)("h3",{id:"preview-environment"},"Preview Environment"),Object(o.b)("p",null,"Preview Environment feature allows you to automatically create new development environments to validate new changes before merging them to your production branch."),Object(o.b)("p",null,"First, we open a pull request:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/4.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"Then, in list of environments, we get a new environment automatically created for the pull request:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/5.png",alt:"Seeding Postgres Database"})),Object(o.b)("p",null,"When you open the logs of the deployment, you\u2019ll see the seed data injection logs:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/seed-postgres/6.png",alt:"Seeding Postgres Database"})))}p.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),u=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},b=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),b=a,m=p["".concat(i,".").concat(b)]||p[b]||d[b]||o;return n?r.a.createElement(m,c({ref:t},l,{components:n})):r.a.createElement(m,c({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:r(s,n);l>c;)t[c++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(432),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,p=Object(c.a)(u),d=Object(r.useRef)(!1),b=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!b&&p&&window.docusaurus.prefetch(u),function(){b&&t&&t.disconnect()}}),[u,b,p]),u&&p?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(u),d.current=!0)},innerRef:function(e){var n,a;b&&e&&p&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,d=c()("jump-to","jump-to--"+l,n),b=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:p,target:u,className:d},b):r.a.createElement(o.a,{to:p,className:d},b)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/93701b40.5454379e.js.LICENSE.txt b/9107e302.472e02ef.js.LICENSE.txt similarity index 100% rename from 93701b40.5454379e.js.LICENSE.txt rename to 9107e302.472e02ef.js.LICENSE.txt diff --git a/91473650.416d72af.js b/91473650.91c8525e.js similarity index 92% rename from 91473650.416d72af.js rename to 91473650.91c8525e.js index 6f1dc4ec3d..c0e194cd59 100644 --- a/91473650.416d72af.js +++ b/91473650.91c8525e.js @@ -1,2 +1,2 @@ -/*! For license information please see 91473650.416d72af.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[143],{295:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return p}));var i=n(1),o=n(9),r=(n(0),n(422)),a=(n(429),n(421)),c=(n(426),{last_modified_on:"2023-06-12",title:"Application Health Checks",description:"Learn how to configure your Kubernetes health checks"}),s={id:"using-qovery/configuration/application-health-checks",title:"Application Health Checks",description:"Learn how to configure your Kubernetes health checks",source:"@site/docs/using-qovery/configuration/application-health-checks.md",permalink:"/docs/using-qovery/configuration/application-health-checks"},l=[{value:"Probes Configuration",id:"probes-configuration",children:[{value:"Type",id:"type",children:[]},{value:"Initial Delay (in seconds)",id:"initial-delay-in-seconds",children:[]},{value:"Period (in seconds)",id:"period-in-seconds",children:[]},{value:"Timeout (in seconds)",id:"timeout-in-seconds",children:[]},{value:"Success Threshold",id:"success-threshold",children:[]},{value:"Failure Threshold",id:"failure-threshold",children:[]}]},{value:"Configuiration for Long-starting application",id:"configuiration-for-long-starting-application",children:[]}],u={rightToc:l};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(i.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Health checks are automatic procedures checking the status of your application, deciding if it is ready to receive traffic or if it needs to be restarted. Since Qovery relies on Kubernetes to deploy and run your application, we use the Kubernetes probes to regularly verify the status of your application during the deployment and/or running phases."),Object(r.b)("p",null,"Kubernetes allows you to configure two probes:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"Liveness probe"),": to check if the application container is alive (passing) or dead (failing). If the check fails, the dead container is restarted to attempt to heal the application. For example, liveness probes could catch a deadlock, where an application is running, but unable to make progress. Restarting a container in such a state can help to make the application more available despite bugs."),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"Readiness probe"),": to check if the application container is ready to receive requests (as even alive containers can enter phases where they cannot handle incoming traffic). Kubernetes only routes traffic to the application if the check succeeds. One use of this signal is to control which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balancers.")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/advanced-settings/workflow.png",alt:"Kubernetes Probes Workflow"})),Object(r.b)("p",null,"During the deployment phase, the liveness and readiness probes play an important role on determining if the deployment succeeds or not. If you have both the liveness and readiness probes configured, both of them need to succeed before considering the deployment to be completed successfully. "),Object(r.b)("p",null,"Example:\nYou have a liveness probe configured on port 80 of your application. If during the deployment of your application the probes can't connect to port 80 and we reach a timeout, the deployment fails."),Object(r.b)("p",null,"Qovery allows you to manage these probes directly from within the Qovery console during the setup of your application, letting you decide their activation, configuration and check frequency."),Object(r.b)("p",null,"Probes can be configured for:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Applications"),Object(r.b)("li",{parentName:"ul"},"Cronjobs"),Object(r.b)("li",{parentName:"ul"},"Lifecycle Jobs")),Object(r.b)("h2",{id:"probes-configuration"},"Probes Configuration"),Object(r.b)("p",null,"The following configuration parameters are valid for both the Liveness and the Readiness probes."),Object(r.b)("h3",{id:"type"},"Type"),Object(r.b)("p",null,"Allows you to specify the type of probe you want to run against your application:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"NONE")," if ",Object(r.b)("inlineCode",{parentName:"li"},"NONE")," is selected, the probe is disabled and thus Kubernetes won't be able to verify the state of your application and take the right corrective actions. ")),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"We strongly advise to not disable the liveness probe.")),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("p",{parentName:"li"},Object(r.b)("strong",{parentName:"p"},"HTTP probes")," are the most common probe type. You can use them if your application is a HTTP server, or if you create a lightweight HTTP server inside your application specifically to respond to such probes. When using a HTTP probe, you need to configure: "),Object(r.b)("ul",{parentName:"li"},Object(r.b)("li",{parentName:"ul"},"a port"),Object(r.b)("li",{parentName:"ul"},"a path\nOnce configured, Kubernetes pings a path (for example: ",Object(r.b)("inlineCode",{parentName:"li"},"/healthz "),") at a given port. If it gets a response in the 200 or 300 range, the check is passed. Otherwise, it is considered as failed and Kubernetes takes the necessary corrective actions."))),Object(r.b)("li",{parentName:"ul"},Object(r.b)("p",{parentName:"li"},Object(r.b)("strong",{parentName:"p"},"TCP probes")," are most often used when HTTP or command probes aren't an option. When using a TCP Liveness probe, Kubernetes tries to establish a connection on the specified port. If the connection is successful, the application is considered healthy. Otherwise, it is considered dead and the container is restarted.")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("p",{parentName:"li"},Object(r.b)("strong",{parentName:"p"},"gRPC probes"),"\nWhen using a gRCP Liveness probe, Kubernetes tries to establish a connection on the specified port and service. If the connection is successful, the application is considered healthy. Otherwise, it is considered dead and the container is restarted.")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("p",{parentName:"li"},Object(r.b)("strong",{parentName:"p"},"EXEC probes"),"\nExec probes allow to define a command to be executed within your container. If the command execution fails, the probe is considered as failed."))),Object(r.b)("h3",{id:"initial-delay-in-seconds"},"Initial Delay (in seconds)"),Object(r.b)("p",null,"Allows you to specify an interval, in seconds, between the application container start and the first liveness check.\t"),Object(r.b)("p",null,"Allowing additional time for the application to start can be useful when boot time usually takes too long (due to long boot operations), or when the application opens the port before being ready to receive traffic on it (due to a still ongoing boot operation).\t"),Object(r.b)("h3",{id:"period-in-seconds"},"Period (in seconds)"),Object(r.b)("p",null,"Allows you to specify an interval, in seconds, between each probe.\t"),Object(r.b)("h3",{id:"timeout-in-seconds"},"Timeout (in seconds)"),Object(r.b)("p",null,"Allows you to specify the interval, in seconds, after which the probe times out.\t"),Object(r.b)("h3",{id:"success-threshold"},"Success Threshold"),Object(r.b)("p",null,"Allows you to specify how many consecutive successes are needed, as a minimum, for the probe to be considered successful after having failed previously."),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"For liveness probes, the value can only be ",Object(r.b)("inlineCode",{parentName:"p"},"1"))),Object(r.b)("h3",{id:"failure-threshold"},"Failure Threshold"),Object(r.b)("p",null,"Allows you to specify how many consecutive failures are needed, as a minimum, for the probe to be considered failed after having succeeded previously."),Object(r.b)("h2",{id:"configuiration-for-long-starting-application"},"Configuiration for Long-starting application"),Object(r.b)("p",null,"If your application has a long boot operation to run, your deployment might be marked as failed since the probe can't verify the state of your application within the specified time frame. In this case, you will find in your deployment logs a warning message ",Object(r.b)("inlineCode",{parentName:"p"},"Liveness probe failed: dial tcp xx.xx.xx.xx:xx: connect: connection refused")," , telling you that the probe is failing."),Object(r.b)("p",null,"If your application needs more time to boot, increase the ",Object(r.b)("inlineCode",{parentName:"p"},"Initial Delay in seconds")," of the probes to match the application boot time."),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Startup probes are not yet available. ")))}p.isMDXComponent=!0},420:function(e,t,n){var i;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=o.a.createContext({}),u=function(e){var t=o.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return o.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(i.forwardRef)((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,a=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),d=i,f=p["".concat(a,".").concat(d)]||p[d]||b[d]||r;return n?o.a.createElement(f,c({ref:t},l,{components:n})):o.a.createElement(f,c({ref:t},l))}));function f(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,a=new Array(r);a[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:i,a[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=a>2?arguments[2]:void 0,l=void 0===s?n:o(s,n);l>c;)t[c++]=e;return t}},425:function(e,t,n){var i=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&i(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var i=n(0),o=n.n(i),r=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var i=n(1),o=n(0),r=n.n(o),a=n(39),c=n(430),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,p=Object(c.a)(u),b=Object(o.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?r.a.createElement(a.b,Object(i.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,i;d&&e&&p&&(n=e,i=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),i())}))}))).observe(n))},to:u})):r.a.createElement("a",Object(i.a)({},e,{href:u}))}},429:function(e,t,n){"use strict";var i=n(0),o=n.n(i),r=n(427),a=n(420),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.className,i=e.badge,a=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+l,n),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},a&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+a})),o.a.createElement("div",{className:"jump-to--main"},i?o.a.createElement("span",{className:"badge badge--primary badge--right"},i):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?o.a.createElement("a",{href:p,target:u,className:b},d):o.a.createElement(r.a,{to:p,className:b},d)}},430:function(e,t,n){"use strict";function i(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return i}))}}]); \ No newline at end of file +/*! For license information please see 91473650.91c8525e.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[146],{298:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return p}));var i=n(1),o=n(9),r=(n(0),n(425)),a=(n(431),n(424)),c=(n(429),{last_modified_on:"2023-06-12",title:"Application Health Checks",description:"Learn how to configure your Kubernetes health checks"}),s={id:"using-qovery/configuration/application-health-checks",title:"Application Health Checks",description:"Learn how to configure your Kubernetes health checks",source:"@site/docs/using-qovery/configuration/application-health-checks.md",permalink:"/docs/using-qovery/configuration/application-health-checks"},l=[{value:"Probes Configuration",id:"probes-configuration",children:[{value:"Type",id:"type",children:[]},{value:"Initial Delay (in seconds)",id:"initial-delay-in-seconds",children:[]},{value:"Period (in seconds)",id:"period-in-seconds",children:[]},{value:"Timeout (in seconds)",id:"timeout-in-seconds",children:[]},{value:"Success Threshold",id:"success-threshold",children:[]},{value:"Failure Threshold",id:"failure-threshold",children:[]}]},{value:"Configuiration for Long-starting application",id:"configuiration-for-long-starting-application",children:[]}],u={rightToc:l};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(i.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Health checks are automatic procedures checking the status of your application, deciding if it is ready to receive traffic or if it needs to be restarted. Since Qovery relies on Kubernetes to deploy and run your application, we use the Kubernetes probes to regularly verify the status of your application during the deployment and/or running phases."),Object(r.b)("p",null,"Kubernetes allows you to configure two probes:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"Liveness probe"),": to check if the application container is alive (passing) or dead (failing). If the check fails, the dead container is restarted to attempt to heal the application. For example, liveness probes could catch a deadlock, where an application is running, but unable to make progress. Restarting a container in such a state can help to make the application more available despite bugs."),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"Readiness probe"),": to check if the application container is ready to receive requests (as even alive containers can enter phases where they cannot handle incoming traffic). Kubernetes only routes traffic to the application if the check succeeds. One use of this signal is to control which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balancers.")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/advanced-settings/workflow.png",alt:"Kubernetes Probes Workflow"})),Object(r.b)("p",null,"During the deployment phase, the liveness and readiness probes play an important role on determining if the deployment succeeds or not. If you have both the liveness and readiness probes configured, both of them need to succeed before considering the deployment to be completed successfully. "),Object(r.b)("p",null,"Example:\nYou have a liveness probe configured on port 80 of your application. If during the deployment of your application the probes can't connect to port 80 and we reach a timeout, the deployment fails."),Object(r.b)("p",null,"Qovery allows you to manage these probes directly from within the Qovery console during the setup of your application, letting you decide their activation, configuration and check frequency."),Object(r.b)("p",null,"Probes can be configured for:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Applications"),Object(r.b)("li",{parentName:"ul"},"Cronjobs"),Object(r.b)("li",{parentName:"ul"},"Lifecycle Jobs")),Object(r.b)("h2",{id:"probes-configuration"},"Probes Configuration"),Object(r.b)("p",null,"The following configuration parameters are valid for both the Liveness and the Readiness probes."),Object(r.b)("h3",{id:"type"},"Type"),Object(r.b)("p",null,"Allows you to specify the type of probe you want to run against your application:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"NONE")," if ",Object(r.b)("inlineCode",{parentName:"li"},"NONE")," is selected, the probe is disabled and thus Kubernetes won't be able to verify the state of your application and take the right corrective actions. ")),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"We strongly advise to not disable the liveness probe.")),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("p",{parentName:"li"},Object(r.b)("strong",{parentName:"p"},"HTTP probes")," are the most common probe type. You can use them if your application is a HTTP server, or if you create a lightweight HTTP server inside your application specifically to respond to such probes. When using a HTTP probe, you need to configure: "),Object(r.b)("ul",{parentName:"li"},Object(r.b)("li",{parentName:"ul"},"a port"),Object(r.b)("li",{parentName:"ul"},"a path\nOnce configured, Kubernetes pings a path (for example: ",Object(r.b)("inlineCode",{parentName:"li"},"/healthz "),") at a given port. If it gets a response in the 200 or 300 range, the check is passed. Otherwise, it is considered as failed and Kubernetes takes the necessary corrective actions."))),Object(r.b)("li",{parentName:"ul"},Object(r.b)("p",{parentName:"li"},Object(r.b)("strong",{parentName:"p"},"TCP probes")," are most often used when HTTP or command probes aren't an option. When using a TCP Liveness probe, Kubernetes tries to establish a connection on the specified port. If the connection is successful, the application is considered healthy. Otherwise, it is considered dead and the container is restarted.")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("p",{parentName:"li"},Object(r.b)("strong",{parentName:"p"},"gRPC probes"),"\nWhen using a gRCP Liveness probe, Kubernetes tries to establish a connection on the specified port and service. If the connection is successful, the application is considered healthy. Otherwise, it is considered dead and the container is restarted.")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("p",{parentName:"li"},Object(r.b)("strong",{parentName:"p"},"EXEC probes"),"\nExec probes allow to define a command to be executed within your container. If the command execution fails, the probe is considered as failed."))),Object(r.b)("h3",{id:"initial-delay-in-seconds"},"Initial Delay (in seconds)"),Object(r.b)("p",null,"Allows you to specify an interval, in seconds, between the application container start and the first liveness check.\t"),Object(r.b)("p",null,"Allowing additional time for the application to start can be useful when boot time usually takes too long (due to long boot operations), or when the application opens the port before being ready to receive traffic on it (due to a still ongoing boot operation).\t"),Object(r.b)("h3",{id:"period-in-seconds"},"Period (in seconds)"),Object(r.b)("p",null,"Allows you to specify an interval, in seconds, between each probe.\t"),Object(r.b)("h3",{id:"timeout-in-seconds"},"Timeout (in seconds)"),Object(r.b)("p",null,"Allows you to specify the interval, in seconds, after which the probe times out.\t"),Object(r.b)("h3",{id:"success-threshold"},"Success Threshold"),Object(r.b)("p",null,"Allows you to specify how many consecutive successes are needed, as a minimum, for the probe to be considered successful after having failed previously."),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"For liveness probes, the value can only be ",Object(r.b)("inlineCode",{parentName:"p"},"1"))),Object(r.b)("h3",{id:"failure-threshold"},"Failure Threshold"),Object(r.b)("p",null,"Allows you to specify how many consecutive failures are needed, as a minimum, for the probe to be considered failed after having succeeded previously."),Object(r.b)("h2",{id:"configuiration-for-long-starting-application"},"Configuiration for Long-starting application"),Object(r.b)("p",null,"If your application has a long boot operation to run, your deployment might be marked as failed since the probe can't verify the state of your application within the specified time frame. In this case, you will find in your deployment logs a warning message ",Object(r.b)("inlineCode",{parentName:"p"},"Liveness probe failed: dial tcp xx.xx.xx.xx:xx: connect: connection refused")," , telling you that the probe is failing."),Object(r.b)("p",null,"If your application needs more time to boot, increase the ",Object(r.b)("inlineCode",{parentName:"p"},"Initial Delay in seconds")," of the probes to match the application boot time."),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Startup probes are not yet available. ")))}p.isMDXComponent=!0},423:function(e,t,n){var i;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=o.a.createContext({}),u=function(e){var t=o.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return o.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(i.forwardRef)((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,a=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),d=i,f=p["".concat(a,".").concat(d)]||p[d]||b[d]||r;return n?o.a.createElement(f,c({ref:t},l,{components:n})):o.a.createElement(f,c({ref:t},l))}));function f(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,a=new Array(r);a[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:i,a[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=a>2?arguments[2]:void 0,l=void 0===s?n:o(s,n);l>c;)t[c++]=e;return t}},428:function(e,t,n){var i=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&i(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var i=n(0),o=n.n(i),r=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var i=n(1),o=n(0),r=n.n(o),a=n(39),c=n(432),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,p=Object(c.a)(u),b=Object(o.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?r.a.createElement(a.b,Object(i.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,i;d&&e&&p&&(n=e,i=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),i())}))}))).observe(n))},to:u})):r.a.createElement("a",Object(i.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var i=n(0),o=n.n(i),r=n(430),a=n(423),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.className,i=e.badge,a=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+l,n),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},a&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+a})),o.a.createElement("div",{className:"jump-to--main"},i?o.a.createElement("span",{className:"badge badge--primary badge--right"},i):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?o.a.createElement("a",{href:p,target:u,className:b},d):o.a.createElement(r.a,{to:p,className:b},d)}},432:function(e,t,n){"use strict";function i(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return i}))}}]); \ No newline at end of file diff --git a/9406f053.8d3cf783.js.LICENSE.txt b/91473650.91c8525e.js.LICENSE.txt similarity index 100% rename from 9406f053.8d3cf783.js.LICENSE.txt rename to 91473650.91c8525e.js.LICENSE.txt diff --git a/93701b40.5454379e.js b/93701b40.2cc191a2.js similarity index 88% rename from 93701b40.5454379e.js rename to 93701b40.2cc191a2.js index 186d32ea7f..483c421200 100644 --- a/93701b40.5454379e.js +++ b/93701b40.2cc191a2.js @@ -1,2 +1,2 @@ -/*! For license information please see 93701b40.5454379e.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[144],{296:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return f}));var r=n(1),o=n(9),a=(n(0),n(422)),i=(n(431),n(426),n(421)),c={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Production",description:"Learn how to run your Production with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Production",description:"Learn how to run your Production with Qovery",permalink:"/guides/advanced/production",readingTime:"1 min read",source:"@site/guides/advanced/production.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Production",truncated:!1,prevItem:{title:"Preview Environments",permalink:"/guides/advanced/use-preview-environments"},nextItem:{title:"Seed Database",permalink:"/guides/advanced/seed-database"}},s=[{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function f(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},"WIP"),Object(a.b)("h2",{id:"qa"},"Q&A"),Object(a.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}f.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},f=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),f=l(n),d=r,m=f["".concat(i,".").concat(d)]||f[d]||p[d]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:o(u,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),f=l[0],p=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!f&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 93701b40.2cc191a2.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[147],{299:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return f}));var r=n(1),o=n(9),a=(n(0),n(425)),i=(n(434),n(429),n(424)),c={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Production",description:"Learn how to run your Production with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Production",description:"Learn how to run your Production with Qovery",permalink:"/guides/advanced/production",readingTime:"1 min read",source:"@site/guides/advanced/production.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Production",truncated:!1,prevItem:{title:"Preview Environments",permalink:"/guides/advanced/use-preview-environments"},nextItem:{title:"Seed Database",permalink:"/guides/advanced/seed-database"}},s=[{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function f(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},"WIP"),Object(a.b)("h2",{id:"qa"},"Q&A"),Object(a.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}f.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},f=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),f=l(n),d=r,m=f["".concat(i,".").concat(d)]||f[d]||p[d]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:o(u,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),f=l[0],p=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!f&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/94a00d4e.b9117f05.js.LICENSE.txt b/93701b40.2cc191a2.js.LICENSE.txt similarity index 100% rename from 94a00d4e.b9117f05.js.LICENSE.txt rename to 93701b40.2cc191a2.js.LICENSE.txt diff --git a/9406f053.8d3cf783.js b/9406f053.8e5899b2.js similarity index 86% rename from 9406f053.8d3cf783.js rename to 9406f053.8e5899b2.js index be3c23b25e..ff00291cfa 100644 --- a/9406f053.8d3cf783.js +++ b/9406f053.8e5899b2.js @@ -1,2 +1,2 @@ -/*! For license information please see 9406f053.8d3cf783.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[145],{297:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return p}));var i=n(1),o=n(9),r=(n(0),n(422)),a=n(421),c=n(431),l=(n(429),n(426),{last_modified_on:"2023-11-03",title:"Git Repository access",description:"Learn how to manage the git repository permission access"}),s={id:"using-qovery/configuration/organization/git-repository-access",title:"Git Repository access",description:"Learn how to manage the git repository permission access",source:"@site/docs/using-qovery/configuration/organization/git-repository-access.md",permalink:"/docs/using-qovery/configuration/organization/git-repository-access",sidebar:"docs",previous:{title:"Members and RBAC",permalink:"/docs/using-qovery/configuration/organization/members-rbac"},next:{title:"Container Registry",permalink:"/docs/using-qovery/configuration/organization/container-registry"}},b=[{value:"Managing tokens on your git provider",id:"managing-tokens-on-your-git-provider",children:[{value:"Github",id:"github",children:[]},{value:"Gitlab",id:"gitlab",children:[]},{value:"Bitbucket",id:"bitbucket",children:[]},{value:"Token expiration",id:"token-expiration",children:[]}]},{value:"Managing the tokens on Qovery",id:"managing-the-tokens-on-qovery",children:[{value:"Create the token",id:"create-the-token",children:[]},{value:"Using the token",id:"using-the-token",children:[]},{value:"Update the token",id:"update-the-token",children:[]},{value:"Delete the token",id:"delete-the-token",children:[]}]},{value:"Deprecated - Qovery Github App",id:"deprecated---qovery-github-app",children:[{value:"Installing the Qovery Github App",id:"installing-the-qovery-github-app",children:[]},{value:"Managing the Github permissions",id:"managing-the-github-permissions",children:[]},{value:"Uninstalling the Qovery Github App",id:"uninstalling-the-qovery-github-app",children:[]}]}],u={rightToc:b};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(i.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"On you first sign in to the ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),", you need to login via your Git provider account. This allows you to manage the access permission within your Qovery organization but it also allows Qovery to access the repositories linked to your Git account."),Object(r.b)("p",null,"When you create an application on the repository X within the Qovery console, Qovery bounds your git account to the application and creates a webhook on your git repository X to receive the events happening on it (push, PR creation, commit etc..)."),Object(r.b)("p",null,"This is the default behaviour but if you want to manage the permission access in a centralized way and decoupled from the users belonging to your organization, you can instead use the Git Token feature."),Object(r.b)("h1",{id:"git-tokens"},"Git Tokens"),Object(r.b)("p",null,"Git tokens are configured within the Git provider interface and then added to your Qovery organization to manage the access permission to your repositories."),Object(r.b)("p",null,"In the following sections you will understand how to:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"create a token within your git provider"),Object(r.b)("li",{parentName:"ul"},"access the token configuration within the Qovery console"),Object(r.b)("li",{parentName:"ul"},"add/modify and delete the tokens within the Qovery console")),Object(r.b)("h2",{id:"managing-tokens-on-your-git-provider"},"Managing tokens on your git provider"),Object(r.b)("p",null,"The process to create a token and the permissions to assign depend on the chosen git provider"),Object(r.b)("h3",{id:"github"},"Github"),Object(r.b)("p",null,"GitHub offers two types of tokens: ",Object(r.b)("inlineCode",{parentName:"p"},"Personal access tokens (classic)")," and ",Object(r.b)("inlineCode",{parentName:"p"},"Fine-grained personal access tokens"),". You can read more about them and how to create them ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens"}),"here"),"."),Object(r.b)("p",null,"Depending on the selected token type, the required permission is slightly different."),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"}," Personal access tokens (classic) ")),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Repository: full control of private repositories"),Object(r.b)("li",{parentName:"ul"},"Admin:repo_hook: read + write")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/github_classic.png",alt:"Github Classic"})),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"}," Fine-grained Personal access tokens ")),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Contents: Read-only"),Object(r.b)("li",{parentName:"ul"},"Webhooks: Read and write"),Object(r.b)("li",{parentName:"ul"},"Pull requests: Read and write")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/github_fine_grained.png",alt:"Github fine grained"})),Object(r.b)("h3",{id:"gitlab"},"Gitlab"),Object(r.b)("p",null,"GitLab provides multiple types of tokens but Qovery supports two: ",Object(r.b)("inlineCode",{parentName:"p"},"Project Tokens")," and ",Object(r.b)("inlineCode",{parentName:"p"},"Group Tokens"),". You can find how to create them within these sections:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(i.a)({parentName:"li"},{href:"https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html"}),"Project Tokens")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(i.a)({parentName:"li"},{href:"https://docs.gitlab.com/ee/user/group/settings/group_access_tokens.html"}),"Group Tokens"))),Object(r.b)("p",null,"The permission configuration is the same for the two types:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Role: Maintainer or Owner "),Object(r.b)("li",{parentName:"ul"},"scopes: api, read_repository")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/gitlab_token.png",alt:"Gitlab token"})),Object(r.b)("h3",{id:"bitbucket"},"Bitbucket"),Object(r.b)("p",null,"Bitbucket offers two types of tokens: ",Object(r.b)("inlineCode",{parentName:"p"},"Repository access tokens")," and ",Object(r.b)("inlineCode",{parentName:"p"},"Workspace access tokens")," (only with Bitbucket Cloud Premium plan). You can read more about them and how to create them here:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(i.a)({parentName:"li"},{href:"https://support.atlassian.com/bitbucket-cloud/docs/create-a-repository-access-token/"}),"Repository access tokens")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(i.a)({parentName:"li"},{href:"https://support.atlassian.com/bitbucket-cloud/docs/workspace-access-tokens/"}),"Workspace access tokens"))),Object(r.b)("p",null,"The permission configuration is the same for the two types:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Repositories: Read (Write auto set by Pull requests Write)"),Object(r.b)("li",{parentName:"ul"},"Pull requests: Read & Write"),Object(r.b)("li",{parentName:"ul"},"Webhooks: Read and write")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/bitbucket_token.png",alt:"Bitbucket token"})),Object(r.b)("h3",{id:"token-expiration"},"Token expiration"),Object(r.b)("p",null,"Most of the time, the tokens created within your git provider have an associated expiration date. Once the expiration date is reached, Qovery will lose access to your git account so be sure to renovate your git token before its expiration (usually the git provider sends you a reminder email). "),Object(r.b)("p",null,"If your token reaches its expiration date but your git provider account does not support the expiration date extension, you can:\n1. Create a new token on your git account\n2. Modify the existing token on the Qovery console by updating its value with the token created in step 1."),Object(r.b)("h2",{id:"managing-the-tokens-on-qovery"},"Managing the tokens on Qovery"),Object(r.b)("p",null,"Tokens are centrally managed within your organization settings under the ",Object(r.b)("inlineCode",{parentName:"p"},"Git repository access")," section:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Open your ",Object(r.b)("a",Object(i.a)({parentName:"li"},{href:"https://console.qovery.com"}),"Qovery Console")," and access your organization settings:")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/access_settings.png",alt:"How to access your organization settings"})),Object(r.b)("ol",{start:2},Object(r.b)("li",{parentName:"ol"},"In the ",Object(r.b)("inlineCode",{parentName:"li"},"Organization settings")," menu, click ",Object(r.b)("inlineCode",{parentName:"li"},"Git Repositories Access"),":")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/git_repository_access.png",alt:"Git Repositories Access"})),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Only users with the organization role Owner, Admin and Devops can manage the git tokens of your organization.")),Object(r.b)("h3",{id:"create-the-token"},"Create the token"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Press the ",Object(r.b)("inlineCode",{parentName:"li"},"Add new Token")," button"),Object(r.b)("li",{parentName:"ol"},"Fill the form with:")),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"your git provider"),Object(r.b)("li",{parentName:"ul"},"Token name: this is the display name used in every Qovery interface."),Object(r.b)("li",{parentName:"ul"},"Description (optional)"),Object(r.b)("li",{parentName:"ul"},"Token Value: the token value as returned by your git provider."),Object(r.b)("li",{parentName:"ul"},"Workspace: Only for bitbucket, provide the workspace where the token has been created.")),Object(r.b)("ol",{start:3},Object(r.b)("li",{parentName:"ol"},"Press the ",Object(r.b)("inlineCode",{parentName:"li"},"Create")," button.")),Object(r.b)("h3",{id:"using-the-token"},"Using the token"),Object(r.b)("p",null,"Once the token is created, you can configure your Qovery services."),Object(r.b)("p",null,"In the creation flow of your service, you will be able to either select your own git account or one of the git tokens configured within your organization."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/git_source_selection.png",alt:"Git Source Selection"})),Object(r.b)("p",null,"If a git token is selected, Qovery will use that token to access the git repository as long as the token does not expire (see the ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"#token-expiration"}),"Token expiration")," section)"),Object(r.b)("h3",{id:"update-the-token"},"Update the token"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Press the ",Object(r.b)("inlineCode",{parentName:"li"},"wheel")," button on the token you want to modify. "),Object(r.b)("li",{parentName:"ol"},"Modify the token."),Object(r.b)("li",{parentName:"ol"},"Press the ",Object(r.b)("inlineCode",{parentName:"li"},"Save")," button.")),Object(r.b)("p",null,"Note: If you want to modify the git token configured in Qovery, you can directly edit the token value. It will prevent you from manually updating every application using the old token."),Object(r.b)("h3",{id:"delete-the-token"},"Delete the token"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Press the ",Object(r.b)("inlineCode",{parentName:"li"},"bin")," button next to the token you want to delete"),Object(r.b)("li",{parentName:"ol"},"Confirm the operation by writing ",Object(r.b)("inlineCode",{parentName:"li"},"delete"))),Object(r.b)("h2",{id:"deprecated---qovery-github-app"},"Deprecated - Qovery Github App"),Object(r.b)(a.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"The Qovery GitHub app is being deprecated and it will be replaced by the git tokens. If you are using the Qovery Github app today, please start migrating to the new Git token system.")),Object(r.b)("p",null,"For better control, as a GitHub user, you can install the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App"),", and define which Github repositories Qovery can access."),Object(r.b)("h3",{id:"installing-the-qovery-github-app"},"Installing the Qovery Github App"),Object(r.b)(a.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"If you have already one or more applications running on your Qovery Organization, please make sure to give the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App")," access to their repositories. If a repository is missing, you might experience a loss of functionalities for those applications (update, auto-deploy, preview environments, etc.).")),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can only link one Github Organization to your Qovery Organization through the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App"),".\nAlso, once the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App")," is installed, all the members of your Qovery Organization will only have access to the repositories linked to your ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App"),".")),Object(r.b)("p",null,"To install the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App"),":"),Object(r.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,Object(r.b)("p",null,"Open your ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console")," and access your organization settings:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/access_settings.png",alt:"How to access your organization settings"}))),Object(r.b)("li",null,Object(r.b)("p",null,"In the ",Object(r.b)("inlineCode",{parentName:"p"},"Organization settings")," menu, click ",Object(r.b)("inlineCode",{parentName:"p"},"Git Repository Access"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/git_repository_access.png",alt:"Git Repository Access"}))),Object(r.b)("li",null,Object(r.b)("p",null,"To start the installation process click ",Object(r.b)("inlineCode",{parentName:"p"},"Install"),":"),Object(r.b)("p",null,"A new window opens in your browser so you can install the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App")," on your Github account.")),Object(r.b)("li",null,Object(r.b)("p",null,"Click the Github account on which you want to install the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Install_GithubApp_Access.png",alt:"Application"}))),Object(r.b)("li",null,Object(r.b)("p",null,"Click ",Object(r.b)("inlineCode",{parentName:"p"},"Only select repositories")," and, in the dropdown menu, define which Github repositories you want to give Qovery access to:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Repositories_Selection.png",alt:"Application"})),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You must give Qovery access to any Github repository linked to an existing Qovery application.\nFailure to do so will result in the loss of some functionalities (update, auto-deploy, preview environments, etc.)."))),Object(r.b)("li",null,Object(r.b)("p",null,"To confirm, click ",Object(r.b)("inlineCode",{parentName:"p"},"Install & Authorize"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Confirmation_Window_GithubApp.png",alt:"Application"})),Object(r.b)("p",null,"You are redirected to your Qovery Console, where the list of authorized Github repositories is updated."),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can update or revoke access to one or multiple Github repositories at any time. To do so, in the ",Object(r.b)("inlineCode",{parentName:"p"},"Git Repository Access")," section, click ",Object(r.b)("inlineCode",{parentName:"p"},"Manage Permission")," below your Git provider account, and repeat the selection process on the Github website.\nPlease note that the repositories must belong to the same Github organization, we do not support yet a multi-github organization setup"))))),Object(r.b)("h3",{id:"managing-the-github-permissions"},"Managing the Github permissions"),Object(r.b)("p",null,"To add or remove access to one of your repositories:"),Object(r.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,Object(r.b)("p",null,"Open your ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console")," and access your organization settings:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/clusters/Organization_Settings_Access_Button.png",alt:"Qovery - delete organization"}))),Object(r.b)("li",null,Object(r.b)("p",null,"In the ",Object(r.b)("inlineCode",{parentName:"p"},"Organization settings")," menu, click ",Object(r.b)("inlineCode",{parentName:"p"},"Git Permission"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Git_Permissions_Tab.png",alt:"Application"}))),Object(r.b)("li",null,Object(r.b)("p",null,"Next to your Git provider account, click ",Object(r.b)("inlineCode",{parentName:"p"},"Manage permission"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Github_App_Disconnect.png",alt:"Application"}))),Object(r.b)("li",null,Object(r.b)("p",null,"Click the Github account on which you want to manage the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App")," access:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Install_GithubApp_Access.png",alt:"Application"}))),Object(r.b)("li",null,Object(r.b)("p",null,"Add or remove the repositories you want to give Qovery access to:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Repositories_Selection.png",alt:"Application"})),Object(r.b)(a.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Rremoving access to a Github repository linked to an existing Qovery application will result in the loss of some functionalities for that application (update, auto-deploy, preview environments, etc.)."))))),Object(r.b)("h3",{id:"uninstalling-the-qovery-github-app"},"Uninstalling the Qovery Github App"),Object(r.b)(a.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Uninstalling the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App")," will result in a loss of some functionalities for all your applications (update, auto-deploy, preview environments, etc.).")),Object(r.b)("p",null,"To uninstall the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App"),":"),Object(r.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,Object(r.b)("p",null,"Open your ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console")," and access your organization settings:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/clusters/Organization_Settings_Access_Button.png",alt:"Qovery - delete organization"}))),Object(r.b)("li",null,Object(r.b)("p",null,"In the ",Object(r.b)("inlineCode",{parentName:"p"},"Organization settings")," menu, click ",Object(r.b)("inlineCode",{parentName:"p"},"Git Permission"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Git_Permissions_Tab.png",alt:"Application"}))),Object(r.b)("li",null,Object(r.b)("p",null,"Next to your Git provider account, click ",Object(r.b)("inlineCode",{parentName:"p"},"Disconnect"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Github_App_Disconnect.png",alt:"Application"})),Object(r.b)("p",null,"The list of authorized Github repositories is updated, meaning Qovery now has access to all of your Github repositories again.")),Object(r.b)("li",null,Object(r.b)("p",null,"From your browser, access your Github account and open your ",Object(r.b)("inlineCode",{parentName:"p"},"Settings"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Github_Settings.png",alt:"Application"}))),Object(r.b)("li",null,Object(r.b)("p",null,"In the navigation menu, click ",Object(r.b)("inlineCode",{parentName:"p"},"Applications"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Github_Applications_Menu.png",alt:"Application"}))),Object(r.b)("li",null,Object(r.b)("p",null,"At the bottom of the page, click ",Object(r.b)("inlineCode",{parentName:"p"},"Uninstall"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/GithubApp_Uninstall_Finalize.png",alt:"Application"})),Object(r.b)("p",null,"A confirmation pop-up window opens.")),Object(r.b)("li",null,Object(r.b)("p",null,"Click ",Object(r.b)("inlineCode",{parentName:"p"},"OK"),":"),Object(r.b)("p",null,"The ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App")," is uninstalled.")))))}p.isMDXComponent=!0},420:function(e,t,n){var i;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),b=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=b(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},g=Object(i.forwardRef)((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,a=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=b(n),g=i,h=u["".concat(a,".").concat(g)]||u[g]||p[g]||r;return n?o.a.createElement(h,c({ref:t},s,{components:n})):o.a.createElement(h,c({ref:t},s))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,a=new Array(r);a[0]=g;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:i,a[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=a>2?arguments[2]:void 0,s=void 0===l?n:o(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var i=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&i(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var i=n(0),o=n.n(i),r=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var i=n(1),o=n(0),r=n.n(o),a=n(39),c=n(430),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,u=Object(c.a)(b),p=Object(o.useRef)(!1),g=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!g&&u&&window.docusaurus.prefetch(b),function(){g&&t&&t.disconnect()}}),[b,g,u]),b&&u?r.a.createElement(a.b,Object(i.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var n,i;g&&e&&u&&(n=e,i=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),i())}))}))).observe(n))},to:b})):r.a.createElement("a",Object(i.a)({},e,{href:b}))}},428:function(e,t,n){"use strict";var i=n(432),o=n(51);function r(e,t){return t.encode?t.strict?i(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,i){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===i[e]&&(i[e]={}),i[e][t[1]]=n):i[e]=n};case"bracket":return function(e,n,i){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==i[e]?i[e]=[].concat(i[e],n):i[e]=[n]:i[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),i=Object.create(null);return"string"!=typeof e?i:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),r=t.length>0?t.join("="):void 0;r=void 0===r?null:decodeURIComponent(r),n(decodeURIComponent(o),r,i)})),Object.keys(i).sort().reduce((function(e,t){var n=i[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):i},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,i){return null===n?[r(t,e),"[",i,"]"].join(""):[r(t,e),"[",r(i,e),"]=",r(n,e)].join("")};case"bracket":return function(t,n){return null===n?r(t,e):[r(t,e),"[]=",r(n,e)].join("")};default:return function(t,n){return null===n?r(t,e):[r(t,e),"=",r(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(i){var o=e[i];if(void 0===o)return"";if(null===o)return r(i,t);if(Array.isArray(o)){var a=[];return o.slice().forEach((function(e){void 0!==e&&a.push(n(i,e,a.length))})),a.join("&")}return r(i,t)+"="+r(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var i=n(0),o=n.n(i),r=n(427),a=n(420),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.className,i=e.badge,a=e.leftIcon,l=e.rightIcon,s=e.size,b=e.target,u=e.to,p=c()("jump-to","jump-to--"+s,n),g=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},a&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+a})),o.a.createElement("div",{className:"jump-to--main"},i?o.a.createElement("span",{className:"badge badge--primary badge--right"},i):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return b?o.a.createElement("a",{href:u,target:b,className:p},g):o.a.createElement(r.a,{to:u,className:p},g)}},430:function(e,t,n){"use strict";function i(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return i}))},431:function(e,t,n){"use strict";var i=n(0),o=n.n(i),r=(n(420),n(428)),a=n.n(r);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,r=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(l),b=Object(i.useState)(null),u=b[0],p=b[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!r&&!u&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 9406f053.8e5899b2.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[148],{300:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return p}));var i=n(1),o=n(9),r=(n(0),n(425)),a=n(424),c=n(434),l=(n(431),n(429),{last_modified_on:"2023-11-03",title:"Git Repository access",description:"Learn how to manage the git repository permission access"}),s={id:"using-qovery/configuration/organization/git-repository-access",title:"Git Repository access",description:"Learn how to manage the git repository permission access",source:"@site/docs/using-qovery/configuration/organization/git-repository-access.md",permalink:"/docs/using-qovery/configuration/organization/git-repository-access",sidebar:"docs",previous:{title:"Members and RBAC",permalink:"/docs/using-qovery/configuration/organization/members-rbac"},next:{title:"Container Registry",permalink:"/docs/using-qovery/configuration/organization/container-registry"}},b=[{value:"Managing tokens on your git provider",id:"managing-tokens-on-your-git-provider",children:[{value:"Github",id:"github",children:[]},{value:"Gitlab",id:"gitlab",children:[]},{value:"Bitbucket",id:"bitbucket",children:[]},{value:"Token expiration",id:"token-expiration",children:[]}]},{value:"Managing the tokens on Qovery",id:"managing-the-tokens-on-qovery",children:[{value:"Create the token",id:"create-the-token",children:[]},{value:"Using the token",id:"using-the-token",children:[]},{value:"Update the token",id:"update-the-token",children:[]},{value:"Delete the token",id:"delete-the-token",children:[]}]},{value:"Deprecated - Qovery Github App",id:"deprecated---qovery-github-app",children:[{value:"Installing the Qovery Github App",id:"installing-the-qovery-github-app",children:[]},{value:"Managing the Github permissions",id:"managing-the-github-permissions",children:[]},{value:"Uninstalling the Qovery Github App",id:"uninstalling-the-qovery-github-app",children:[]}]}],u={rightToc:b};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(i.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"On you first sign in to the ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),", you need to login via your Git provider account. This allows you to manage the access permission within your Qovery organization but it also allows Qovery to access the repositories linked to your Git account."),Object(r.b)("p",null,"When you create an application on the repository X within the Qovery console, Qovery bounds your git account to the application and creates a webhook on your git repository X to receive the events happening on it (push, PR creation, commit etc..)."),Object(r.b)("p",null,"This is the default behaviour but if you want to manage the permission access in a centralized way and decoupled from the users belonging to your organization, you can instead use the Git Token feature."),Object(r.b)("h1",{id:"git-tokens"},"Git Tokens"),Object(r.b)("p",null,"Git tokens are configured within the Git provider interface and then added to your Qovery organization to manage the access permission to your repositories."),Object(r.b)("p",null,"In the following sections you will understand how to:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"create a token within your git provider"),Object(r.b)("li",{parentName:"ul"},"access the token configuration within the Qovery console"),Object(r.b)("li",{parentName:"ul"},"add/modify and delete the tokens within the Qovery console")),Object(r.b)("h2",{id:"managing-tokens-on-your-git-provider"},"Managing tokens on your git provider"),Object(r.b)("p",null,"The process to create a token and the permissions to assign depend on the chosen git provider"),Object(r.b)("h3",{id:"github"},"Github"),Object(r.b)("p",null,"GitHub offers two types of tokens: ",Object(r.b)("inlineCode",{parentName:"p"},"Personal access tokens (classic)")," and ",Object(r.b)("inlineCode",{parentName:"p"},"Fine-grained personal access tokens"),". You can read more about them and how to create them ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens"}),"here"),"."),Object(r.b)("p",null,"Depending on the selected token type, the required permission is slightly different."),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"}," Personal access tokens (classic) ")),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Repository: full control of private repositories"),Object(r.b)("li",{parentName:"ul"},"Admin:repo_hook: read + write")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/github_classic.png",alt:"Github Classic"})),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"}," Fine-grained Personal access tokens ")),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Contents: Read-only"),Object(r.b)("li",{parentName:"ul"},"Webhooks: Read and write"),Object(r.b)("li",{parentName:"ul"},"Pull requests: Read and write")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/github_fine_grained.png",alt:"Github fine grained"})),Object(r.b)("h3",{id:"gitlab"},"Gitlab"),Object(r.b)("p",null,"GitLab provides multiple types of tokens but Qovery supports two: ",Object(r.b)("inlineCode",{parentName:"p"},"Project Tokens")," and ",Object(r.b)("inlineCode",{parentName:"p"},"Group Tokens"),". You can find how to create them within these sections:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(i.a)({parentName:"li"},{href:"https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html"}),"Project Tokens")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(i.a)({parentName:"li"},{href:"https://docs.gitlab.com/ee/user/group/settings/group_access_tokens.html"}),"Group Tokens"))),Object(r.b)("p",null,"The permission configuration is the same for the two types:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Role: Maintainer or Owner "),Object(r.b)("li",{parentName:"ul"},"scopes: api, read_repository")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/gitlab_token.png",alt:"Gitlab token"})),Object(r.b)("h3",{id:"bitbucket"},"Bitbucket"),Object(r.b)("p",null,"Bitbucket offers two types of tokens: ",Object(r.b)("inlineCode",{parentName:"p"},"Repository access tokens")," and ",Object(r.b)("inlineCode",{parentName:"p"},"Workspace access tokens")," (only with Bitbucket Cloud Premium plan). You can read more about them and how to create them here:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(i.a)({parentName:"li"},{href:"https://support.atlassian.com/bitbucket-cloud/docs/create-a-repository-access-token/"}),"Repository access tokens")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(i.a)({parentName:"li"},{href:"https://support.atlassian.com/bitbucket-cloud/docs/workspace-access-tokens/"}),"Workspace access tokens"))),Object(r.b)("p",null,"The permission configuration is the same for the two types:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Repositories: Read (Write auto set by Pull requests Write)"),Object(r.b)("li",{parentName:"ul"},"Pull requests: Read & Write"),Object(r.b)("li",{parentName:"ul"},"Webhooks: Read and write")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/bitbucket_token.png",alt:"Bitbucket token"})),Object(r.b)("h3",{id:"token-expiration"},"Token expiration"),Object(r.b)("p",null,"Most of the time, the tokens created within your git provider have an associated expiration date. Once the expiration date is reached, Qovery will lose access to your git account so be sure to renovate your git token before its expiration (usually the git provider sends you a reminder email). "),Object(r.b)("p",null,"If your token reaches its expiration date but your git provider account does not support the expiration date extension, you can:\n1. Create a new token on your git account\n2. Modify the existing token on the Qovery console by updating its value with the token created in step 1."),Object(r.b)("h2",{id:"managing-the-tokens-on-qovery"},"Managing the tokens on Qovery"),Object(r.b)("p",null,"Tokens are centrally managed within your organization settings under the ",Object(r.b)("inlineCode",{parentName:"p"},"Git repository access")," section:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Open your ",Object(r.b)("a",Object(i.a)({parentName:"li"},{href:"https://console.qovery.com"}),"Qovery Console")," and access your organization settings:")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/access_settings.png",alt:"How to access your organization settings"})),Object(r.b)("ol",{start:2},Object(r.b)("li",{parentName:"ol"},"In the ",Object(r.b)("inlineCode",{parentName:"li"},"Organization settings")," menu, click ",Object(r.b)("inlineCode",{parentName:"li"},"Git Repositories Access"),":")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/git_repository_access.png",alt:"Git Repositories Access"})),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Only users with the organization role Owner, Admin and Devops can manage the git tokens of your organization.")),Object(r.b)("h3",{id:"create-the-token"},"Create the token"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Press the ",Object(r.b)("inlineCode",{parentName:"li"},"Add new Token")," button"),Object(r.b)("li",{parentName:"ol"},"Fill the form with:")),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"your git provider"),Object(r.b)("li",{parentName:"ul"},"Token name: this is the display name used in every Qovery interface."),Object(r.b)("li",{parentName:"ul"},"Description (optional)"),Object(r.b)("li",{parentName:"ul"},"Token Value: the token value as returned by your git provider."),Object(r.b)("li",{parentName:"ul"},"Workspace: Only for bitbucket, provide the workspace where the token has been created.")),Object(r.b)("ol",{start:3},Object(r.b)("li",{parentName:"ol"},"Press the ",Object(r.b)("inlineCode",{parentName:"li"},"Create")," button.")),Object(r.b)("h3",{id:"using-the-token"},"Using the token"),Object(r.b)("p",null,"Once the token is created, you can configure your Qovery services."),Object(r.b)("p",null,"In the creation flow of your service, you will be able to either select your own git account or one of the git tokens configured within your organization."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/git_source_selection.png",alt:"Git Source Selection"})),Object(r.b)("p",null,"If a git token is selected, Qovery will use that token to access the git repository as long as the token does not expire (see the ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"#token-expiration"}),"Token expiration")," section)"),Object(r.b)("h3",{id:"update-the-token"},"Update the token"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Press the ",Object(r.b)("inlineCode",{parentName:"li"},"wheel")," button on the token you want to modify. "),Object(r.b)("li",{parentName:"ol"},"Modify the token."),Object(r.b)("li",{parentName:"ol"},"Press the ",Object(r.b)("inlineCode",{parentName:"li"},"Save")," button.")),Object(r.b)("p",null,"Note: If you want to modify the git token configured in Qovery, you can directly edit the token value. It will prevent you from manually updating every application using the old token."),Object(r.b)("h3",{id:"delete-the-token"},"Delete the token"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Press the ",Object(r.b)("inlineCode",{parentName:"li"},"bin")," button next to the token you want to delete"),Object(r.b)("li",{parentName:"ol"},"Confirm the operation by writing ",Object(r.b)("inlineCode",{parentName:"li"},"delete"))),Object(r.b)("h2",{id:"deprecated---qovery-github-app"},"Deprecated - Qovery Github App"),Object(r.b)(a.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"The Qovery GitHub app is being deprecated and it will be replaced by the git tokens. If you are using the Qovery Github app today, please start migrating to the new Git token system.")),Object(r.b)("p",null,"For better control, as a GitHub user, you can install the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App"),", and define which Github repositories Qovery can access."),Object(r.b)("h3",{id:"installing-the-qovery-github-app"},"Installing the Qovery Github App"),Object(r.b)(a.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"If you have already one or more applications running on your Qovery Organization, please make sure to give the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App")," access to their repositories. If a repository is missing, you might experience a loss of functionalities for those applications (update, auto-deploy, preview environments, etc.).")),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can only link one Github Organization to your Qovery Organization through the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App"),".\nAlso, once the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App")," is installed, all the members of your Qovery Organization will only have access to the repositories linked to your ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App"),".")),Object(r.b)("p",null,"To install the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App"),":"),Object(r.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,Object(r.b)("p",null,"Open your ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console")," and access your organization settings:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/access_settings.png",alt:"How to access your organization settings"}))),Object(r.b)("li",null,Object(r.b)("p",null,"In the ",Object(r.b)("inlineCode",{parentName:"p"},"Organization settings")," menu, click ",Object(r.b)("inlineCode",{parentName:"p"},"Git Repository Access"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/git_repository_access.png",alt:"Git Repository Access"}))),Object(r.b)("li",null,Object(r.b)("p",null,"To start the installation process click ",Object(r.b)("inlineCode",{parentName:"p"},"Install"),":"),Object(r.b)("p",null,"A new window opens in your browser so you can install the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App")," on your Github account.")),Object(r.b)("li",null,Object(r.b)("p",null,"Click the Github account on which you want to install the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Install_GithubApp_Access.png",alt:"Application"}))),Object(r.b)("li",null,Object(r.b)("p",null,"Click ",Object(r.b)("inlineCode",{parentName:"p"},"Only select repositories")," and, in the dropdown menu, define which Github repositories you want to give Qovery access to:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Repositories_Selection.png",alt:"Application"})),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You must give Qovery access to any Github repository linked to an existing Qovery application.\nFailure to do so will result in the loss of some functionalities (update, auto-deploy, preview environments, etc.)."))),Object(r.b)("li",null,Object(r.b)("p",null,"To confirm, click ",Object(r.b)("inlineCode",{parentName:"p"},"Install & Authorize"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Confirmation_Window_GithubApp.png",alt:"Application"})),Object(r.b)("p",null,"You are redirected to your Qovery Console, where the list of authorized Github repositories is updated."),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can update or revoke access to one or multiple Github repositories at any time. To do so, in the ",Object(r.b)("inlineCode",{parentName:"p"},"Git Repository Access")," section, click ",Object(r.b)("inlineCode",{parentName:"p"},"Manage Permission")," below your Git provider account, and repeat the selection process on the Github website.\nPlease note that the repositories must belong to the same Github organization, we do not support yet a multi-github organization setup"))))),Object(r.b)("h3",{id:"managing-the-github-permissions"},"Managing the Github permissions"),Object(r.b)("p",null,"To add or remove access to one of your repositories:"),Object(r.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,Object(r.b)("p",null,"Open your ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console")," and access your organization settings:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/clusters/Organization_Settings_Access_Button.png",alt:"Qovery - delete organization"}))),Object(r.b)("li",null,Object(r.b)("p",null,"In the ",Object(r.b)("inlineCode",{parentName:"p"},"Organization settings")," menu, click ",Object(r.b)("inlineCode",{parentName:"p"},"Git Permission"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Git_Permissions_Tab.png",alt:"Application"}))),Object(r.b)("li",null,Object(r.b)("p",null,"Next to your Git provider account, click ",Object(r.b)("inlineCode",{parentName:"p"},"Manage permission"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Github_App_Disconnect.png",alt:"Application"}))),Object(r.b)("li",null,Object(r.b)("p",null,"Click the Github account on which you want to manage the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App")," access:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Install_GithubApp_Access.png",alt:"Application"}))),Object(r.b)("li",null,Object(r.b)("p",null,"Add or remove the repositories you want to give Qovery access to:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Repositories_Selection.png",alt:"Application"})),Object(r.b)(a.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Rremoving access to a Github repository linked to an existing Qovery application will result in the loss of some functionalities for that application (update, auto-deploy, preview environments, etc.)."))))),Object(r.b)("h3",{id:"uninstalling-the-qovery-github-app"},"Uninstalling the Qovery Github App"),Object(r.b)(a.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Uninstalling the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App")," will result in a loss of some functionalities for all your applications (update, auto-deploy, preview environments, etc.).")),Object(r.b)("p",null,"To uninstall the ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App"),":"),Object(r.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,Object(r.b)("p",null,"Open your ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console")," and access your organization settings:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/clusters/Organization_Settings_Access_Button.png",alt:"Qovery - delete organization"}))),Object(r.b)("li",null,Object(r.b)("p",null,"In the ",Object(r.b)("inlineCode",{parentName:"p"},"Organization settings")," menu, click ",Object(r.b)("inlineCode",{parentName:"p"},"Git Permission"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Git_Permissions_Tab.png",alt:"Application"}))),Object(r.b)("li",null,Object(r.b)("p",null,"Next to your Git provider account, click ",Object(r.b)("inlineCode",{parentName:"p"},"Disconnect"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Github_App_Disconnect.png",alt:"Application"})),Object(r.b)("p",null,"The list of authorized Github repositories is updated, meaning Qovery now has access to all of your Github repositories again.")),Object(r.b)("li",null,Object(r.b)("p",null,"From your browser, access your Github account and open your ",Object(r.b)("inlineCode",{parentName:"p"},"Settings"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Github_Settings.png",alt:"Application"}))),Object(r.b)("li",null,Object(r.b)("p",null,"In the navigation menu, click ",Object(r.b)("inlineCode",{parentName:"p"},"Applications"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Github_Applications_Menu.png",alt:"Application"}))),Object(r.b)("li",null,Object(r.b)("p",null,"At the bottom of the page, click ",Object(r.b)("inlineCode",{parentName:"p"},"Uninstall"),":"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/GithubApp_Uninstall_Finalize.png",alt:"Application"})),Object(r.b)("p",null,"A confirmation pop-up window opens.")),Object(r.b)("li",null,Object(r.b)("p",null,"Click ",Object(r.b)("inlineCode",{parentName:"p"},"OK"),":"),Object(r.b)("p",null,"The ",Object(r.b)("strong",{parentName:"p"},"Qovery Github App")," is uninstalled.")))))}p.isMDXComponent=!0},423:function(e,t,n){var i;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),b=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=b(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},g=Object(i.forwardRef)((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,a=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=b(n),g=i,h=u["".concat(a,".").concat(g)]||u[g]||p[g]||r;return n?o.a.createElement(h,c({ref:t},s,{components:n})):o.a.createElement(h,c({ref:t},s))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,a=new Array(r);a[0]=g;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:i,a[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=a>2?arguments[2]:void 0,s=void 0===l?n:o(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var i=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&i(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var i=n(0),o=n.n(i),r=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var i=n(1),o=n(0),r=n.n(o),a=n(39),c=n(432),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,u=Object(c.a)(b),p=Object(o.useRef)(!1),g=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!g&&u&&window.docusaurus.prefetch(b),function(){g&&t&&t.disconnect()}}),[b,g,u]),b&&u?r.a.createElement(a.b,Object(i.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var n,i;g&&e&&u&&(n=e,i=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),i())}))}))).observe(n))},to:b})):r.a.createElement("a",Object(i.a)({},e,{href:b}))}},431:function(e,t,n){"use strict";var i=n(0),o=n.n(i),r=n(430),a=n(423),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.className,i=e.badge,a=e.leftIcon,l=e.rightIcon,s=e.size,b=e.target,u=e.to,p=c()("jump-to","jump-to--"+s,n),g=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},a&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+a})),o.a.createElement("div",{className:"jump-to--main"},i?o.a.createElement("span",{className:"badge badge--primary badge--right"},i):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return b?o.a.createElement("a",{href:u,target:b,className:p},g):o.a.createElement(r.a,{to:u,className:p},g)}},432:function(e,t,n){"use strict";function i(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return i}))},433:function(e,t,n){"use strict";var i=n(435),o=n(51);function r(e,t){return t.encode?t.strict?i(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,i){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===i[e]&&(i[e]={}),i[e][t[1]]=n):i[e]=n};case"bracket":return function(e,n,i){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==i[e]?i[e]=[].concat(i[e],n):i[e]=[n]:i[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),i=Object.create(null);return"string"!=typeof e?i:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),r=t.length>0?t.join("="):void 0;r=void 0===r?null:decodeURIComponent(r),n(decodeURIComponent(o),r,i)})),Object.keys(i).sort().reduce((function(e,t){var n=i[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):i},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,i){return null===n?[r(t,e),"[",i,"]"].join(""):[r(t,e),"[",r(i,e),"]=",r(n,e)].join("")};case"bracket":return function(t,n){return null===n?r(t,e):[r(t,e),"[]=",r(n,e)].join("")};default:return function(t,n){return null===n?r(t,e):[r(t,e),"=",r(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(i){var o=e[i];if(void 0===o)return"";if(null===o)return r(i,t);if(Array.isArray(o)){var a=[];return o.slice().forEach((function(e){void 0!==e&&a.push(n(i,e,a.length))})),a.join("&")}return r(i,t)+"="+r(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var i=n(0),o=n.n(i),r=(n(423),n(433)),a=n.n(r);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,r=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(l),b=Object(i.useState)(null),u=b[0],p=b[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!r&&!u&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/97f5d064.b0e4137c.js.LICENSE.txt b/9406f053.8e5899b2.js.LICENSE.txt similarity index 100% rename from 97f5d064.b0e4137c.js.LICENSE.txt rename to 9406f053.8e5899b2.js.LICENSE.txt diff --git a/94a00d4e.b9117f05.js b/94a00d4e.03820917.js similarity index 95% rename from 94a00d4e.b9117f05.js rename to 94a00d4e.03820917.js index f66bc7da15..a5e8075fea 100644 --- a/94a00d4e.b9117f05.js +++ b/94a00d4e.03820917.js @@ -1,2 +1,2 @@ -/*! For license information please see 94a00d4e.b9117f05.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[146],{298:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return o})),t.d(n,"metadata",(function(){return l})),t.d(n,"rightToc",(function(){return s})),t.d(n,"default",(function(){return p}));var a=t(1),r=t(9),i=(t(0),t(422)),o=(t(421),t(426),t(429),{last_modified_on:"2022-04-22",$schema:"/.meta/.schemas/guides.json",title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",description:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",description:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",permalink:"/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws",readingTime:"10 min read",source:"@site/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",truncated:!1,prevItem:{title:"Debugging",permalink:"/guides/getting-started/debugging"},nextItem:{title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",permalink:"/guides/tutorial/build-e2e-testing-ephemeral-environments"}},s=[{value:"Qovery Deployment Platform",id:"qovery-deployment-platform",children:[]},{value:"Previ1ew Environments",id:"previ1ew-environments",children:[]},{value:"Preview environments benefits",id:"preview-environments-benefits",children:[]},{value:"Demo",id:"demo",children:[{value:"AWS Infrastructure",id:"aws-infrastructure",children:[]},{value:"Full Stack Application",id:"full-stack-application",children:[]},{value:"Frontend",id:"frontend",children:[]},{value:"Backend",id:"backend",children:[]},{value:"Deployment",id:"deployment",children:[]},{value:"Enable Preview Environments",id:"enable-preview-environments",children:[]},{value:"Testing Preview Environments",id:"testing-preview-environments",children:[]},{value:"Preview Environment Explained",id:"preview-environment-explained",children:[]},{value:"Testing Preview Environments PT II",id:"testing-preview-environments-pt-ii",children:[]},{value:"Conclusion",id:"conclusion",children:[]}]}],c={rightToc:s};function p(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},c,t,{components:n,mdxType:"MDXLayout"}),Object(i.b)("h3",{id:"qovery-deployment-platform"},"Qovery Deployment Platform"),Object(i.b)("p",null,"Have you ever dreamed of deploying your applications on the cloud without any hassle? Imagine a platform where all you need to do is to sign in with your AWS credentials, and automagically the platform does all the hard work of configuration of the cloud for you, and, on top of that, provides some extra features that do not exist out of the box anywhere else."),Object(i.b)("p",null,"Qovery is this platform - not only does it allow you to deploy your infrastructure and applications on your own cloud account, but also provides extra cool features, one of which we will see in this article."),Object(i.b)("p",null,Object(i.b)("em",{parentName:"p"},"Don't take our words for granted - 14000 developers from more than 100 countries use Qovery to deploy their apps on AWS.")),Object(i.b)("h3",{id:"previ1ew-environments"},"Previ1ew Environments"),Object(i.b)("p",null,"Imagine working on a new feature. You're dealing with a full-stack application - you have a frontend, backend, and a database. You introduce a change to your backend app - how do you test all of it? It would be great if there was a service that could deploy everything for you so you can test your changes quickly and in separation with all the components..."),Object(i.b)("p",null,"Qovery Preview Environments are designed to help you with exactly this."),Object(i.b)("p",null,"It not only deploys the app you changed but all other related applications and databases as well in the cloud so that you can test your new features and collaborate with reviewers of your code."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/1.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Preview environments feature is available on other platforms as well. Vercel and Netlify allows you to test your changes before merging code into production. It\u2019s perfect for single frontend applications, but the concept of Preview Environments on Qovery goes far beyond this."),Object(i.b)("p",null,"Qovery is able not only to create a preview environment for your frontend, but also for the backend and databases - the whole stack is supported. Running a set of backend microservices? No worries, Qovery got you covered. All services will be replicated in the new environment."),Object(i.b)("h3",{id:"preview-environments-benefits"},"Preview environments benefits"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Time-saving")," - You don't have to set up a fresh environment to test changes in isolation - Qovery does it all for you"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Productivity")," - Faster changes, quicker review, better feedback loop - the productivity and quality of your application increases dramatically"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Better tests")," - It's best to test apps in isolation, but it's almost impossible with a complicated stack if you have to prepare the testing environment manually - Qovery does it all \"automagically\" for you"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Independence")," - Each environment is completely separate, meaning more people can work flawlessly on the project, testing the changes they introduce in parallel, not blocking each other"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Deliver quickly")," - Faster feedback loop, independent developers, fewer bugs, meaning the product is delivered more quickly"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Reduce friction")," - Waiting for others to test your changes is frustrating - with preview envs everyone has his own testing environment")),Object(i.b)("h2",{id:"demo"},"Demo"),Object(i.b)("h3",{id:"aws-infrastructure"},"AWS Infrastructure"),Object(i.b)("p",null,"Before we start with the deployments, we need to have our AWS infrastructure ready and deployed. It can be done as simply as by providing credentials to your cloud account, you can see how to configure the credentials in this article - ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/"}),"https://hub.qovery.com/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/2.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"The initial setup takes about 15 min, and your cluster is ready to host your applications."),Object(i.b)("h3",{id:"full-stack-application"},"Full Stack Application"),Object(i.b)("p",null,"In this example, we will use a Next.js frontend, Node.js backend, and MongoDB as a database. The app will display an image gallery with images fetched from the backend. Preview Environments feature will help us introduce a new change in the backend - moving away from a hardcoded POC list of images to a list fetched from our database."),Object(i.b)("h3",{id:"frontend"},"Frontend"),Object(i.b)("p",null,"Our simple image gallery will look like this"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/3.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"To generate the application, we used ",Object(i.b)("inlineCode",{parentName:"p"},"npx create-next-app@latest"),", but the source code can be found here - ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/gallery-demo/tree/master/frontend"}),"https://github.com/pjeziorowski/gallery-demo/tree/master/frontend")),Object(i.b)("p",null,"The main changes introduced to the generated application scaffolding are:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Adding a ",Object(i.b)("inlineCode",{parentName:"li"},"Dockerfile"))),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-docker"}),"FROM node:alpine\n\nRUN mkdir -p /usr/src\nWORKDIR /usr/src\n\nCOPY . /usr/src\nRUN npm install\nRUN npm run build\n\nEXPOSE 3000\nCMD npm run start\n")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Adding a query to our backend (which we will be built soon in the next steps) that fetches a list of images to display in our gallery"),Object(i.b)("pre",{parentName:"li"},Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'function useImages() {\n return useQuery("images", async () => {\n const { data } = await axios.get(\n `${apiRoot}/api/v1/images`\n );\n return data;\n });\n}\n'))),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Plus, we adjusted the HTML and styling for the demo purpose of showing a list of images"))),Object(i.b)("h3",{id:"backend"},"Backend"),Object(i.b)("p",null,"Our backend is the main star of the demo. In its first version, the backend is displaying a hardcoded list of images. In the next step, we will gradually expand its capabilities. It will connect to a database and fetch the list from MongoDB instead. To make sure the changes are correct, we will use ",Object(i.b)("inlineCode",{parentName:"p"},"Preview Environment")," feature before merging the pull request to our production environment"),Object(i.b)("p",null,"The backend was generated using Express ",Object(i.b)("inlineCode",{parentName:"p"},"npx express-generator --no-view"),", and the source code can be found here - ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/gallery-demo/tree/master/frontend"}),"https://github.com/pjeziorowski/gallery-demo/tree/master/backend")),Object(i.b)("p",null,"Changes that we introduced to the generated app scaffolding are the following:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Adding a Dockerfile"),Object(i.b)("pre",{parentName:"li"},Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-docker"}),'FROM node:16\n\nWORKDIR /usr/src/app\n\nCOPY package*.json ./\nRUN npm install\nCOPY . .\n\nEXPOSE 8080\nCMD [ "node", "src/index.js" ]\n'))),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Creating a ",Object(i.b)("inlineCode",{parentName:"p"},"/api/v1/images")," endpoint that returns a hardcoded array of images"),Object(i.b)("pre",{parentName:"li"},Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"router.get('/images', (req, res) => {\n res.json([\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n }\n });\n});\n")),Object(i.b)("p",{parentName:"li"}," In the next step we will improve the function to use a Mongo database instead."))),Object(i.b)("h3",{id:"deployment"},"Deployment"),Object(i.b)("p",null,"After creating a new project, let's now set up our ",Object(i.b)("inlineCode",{parentName:"p"},"production")," environment."),Object(i.b)("p",null,"First, let's deploy our frontend. Click ",Object(i.b)("inlineCode",{parentName:"p"},"Add my first application"),", select a correct repository, ",Object(i.b)("inlineCode",{parentName:"p"},"Docker")," as build mode and expose port ",Object(i.b)("inlineCode",{parentName:"p"},"3000"),". The application root path is ",Object(i.b)("inlineCode",{parentName:"p"},"/frontend"),"."),Object(i.b)("p",null,"Next step: add a ",Object(i.b)("inlineCode",{parentName:"p"},"MongoDB")," database - it will be used by our backend later on. You can do so by clicking on ",Object(i.b)("inlineCode",{parentName:"p"},"Add")," button in Qovery Console in Environment."),Object(i.b)("p",null,"Now let's deploy our backend. Click ",Object(i.b)("inlineCode",{parentName:"p"},"Add")," \u2192 ",Object(i.b)("inlineCode",{parentName:"p"},"Application"),", pick up ",Object(i.b)("inlineCode",{parentName:"p"},"/backend")," as application root path, ",Object(i.b)("inlineCode",{parentName:"p"},"8080")," port, and ",Object(i.b)("inlineCode",{parentName:"p"},"Docker")," build mode."),Object(i.b)("p",null,"For the future connection to DB, let's add an alias named ",Object(i.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," that points to our Mongo database internal URL in our backend ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variable")," settings:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/4.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Additionally, let's create an alias called ",Object(i.b)("inlineCode",{parentName:"p"},"API_ROOT")," in our frontend application that points to our backend external URL:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/5.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"This is it! Now we can deploy our production environment. After a few minutes, navigate to the frontend app, click on ",Object(i.b)("inlineCode",{parentName:"p"},"Open")," - you should be redirected to the image gallery"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/6.png",alt:"AWS Preview Environments"})),Object(i.b)("h3",{id:"enable-preview-environments"},"Enable Preview Environments"),Object(i.b)("p",null,"The next step to see the preview environment feature in action is to enable it for our backend application."),Object(i.b)("p",null,"To do so, navigate to ",Object(i.b)("inlineCode",{parentName:"p"},"Environment")," \u2192 ",Object(i.b)("inlineCode",{parentName:"p"},"Settings")," \u2192 ",Object(i.b)("inlineCode",{parentName:"p"},"Preview Env")," and tick it for the backend app"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/7.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Great! The feature is enabled. To see it in action, let's edit our code in the backend app so that the list of images is fetched from the database instead."),Object(i.b)("h3",{id:"testing-preview-environments"},"Testing Preview Environments"),Object(i.b)("p",null,"Let's make a small update of our backend - let's connect to MongoDB and fetch images from there. Here are changes to the function we could introduce to make it happen:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const databaseUrl = process.env.DATABASE_URL\n || 'mongodb://localhost:27017/test';\n\nconst imageSchema = new mongoose.Schema({\n title: String,\n size: String,\n source: String\n});\n\nmongoose.connect(databaseUrl);\n\nrouter.get('/', (req, res) => {\n imageSchema.find().then((data) => {\n res.json(\n data\n )\n });\n});\n")),Object(i.b)("p",null,"Let's now create a new branch in our repository and create a pull request to our production (master branch) environment. Preview Environments feature will spin up a new environment for us so that we can safely test changes we just introduced!"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/8.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Once the PR is created, an automatic comment has been dropped on our PR to let us know that the new preview environment has been created."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/14.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Now, when we display environments in our project, we will see that a new environment for the pull request is being deployed:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/9.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"with all the resources we need! A database, backend, frontend - we can now test our changes in complete separation from the production without any manual setting up work:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/10.png",alt:"AWS Preview Environments"})),Object(i.b)("h3",{id:"preview-environment-explained"},"Preview Environment Explained"),Object(i.b)("p",null,"The Preview Environment feature can be enabled or disabled per app. It creates a complete copy of your environment so that you can test new changes from pull requests in separation. It deploys your databases, backend, and frontend applications to a completely new environment once a pull request is opened. If you update your pull request, all new changes are also reflected in the new environment so that you can test them or fix problems during the review. What is great is that Qovery takes care of managing all environment variables for you as well, creates new aliases just as you had in your prod environment, so that everything is really tested separately and it all happens automagically. After the pull request is merged, Qovery automatically cleans up the preview environment to save your money."),Object(i.b)("h3",{id:"testing-preview-environments-pt-ii"},"Testing Preview Environments PT II"),Object(i.b)("p",null,"After a few minutes, your preview environment should be up and running. You can now navigate to the frontend app and click ",Object(i.b)("inlineCode",{parentName:"p"},"Open")," - in the image gallery, you will see an empty list because we don't yet have any images in the database."),Object(i.b)("p",null,"You can add a few images manually by connecting to your mongo instance via CLI. The credentials can be found in the database overview:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/11.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"After connecting, let's add images by executing the following:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"db.createCollection(\"images\")\n\ndb.images.insert([\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n },\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n },\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n }\n ])\n")),Object(i.b)("p",null,"Now, after opening the frontend app in our preview environment, we will see all the images we put in the database! It looks like the feature is working well, so let's merge the PR:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/12.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"What now happens is automatically after the PR merge, the preview environment is automatically cleaned up:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/13.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Great job! Thanks to Qovery Preview Environments, we managed to develop a new feature in a complete separation from our production, we tested it in a real environment deployed in the cloud, and we didn't have to spend any time preparing our environment for tests at all."),Object(i.b)("h3",{id:"conclusion"},"Conclusion"),Object(i.b)("p",null,"In the article, we quickly went through the process of creating a full-stack application with frontend, backend, and database. We enabled the Preview Environment feature to develop new features more quickly. We learned what the benefits of Preview Environments are, how to use them, and how to integrate them to day to day development workflow."))}p.isMDXComponent=!0},420:function(e,n,t){var a;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var c=r.a.createContext({}),p=function(e){var n=r.a.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):l({},n,{},e)),t},u=function(e){var n=p(e.components);return r.a.createElement(c.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},b=Object(a.forwardRef)((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,o=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=p(t),b=a,m=u["".concat(o,".").concat(b)]||u[b]||d[b]||i;return t?r.a.createElement(m,l({ref:n},c,{components:t})):r.a.createElement(m,l({ref:n},c))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=b;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var c=2;c1?arguments[1]:void 0,t),s=o>2?arguments[2]:void 0,c=void 0===s?t:r(s,t);c>l;)n[l++]=e;return n}},425:function(e,n,t){var a=t(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||t(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},426:function(e,n,t){"use strict";t(425);var a=t(0),r=t.n(a),i=t(421);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},427:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),l=t(430),s=t(20),c=t.n(s);n.a=function(e){var n,t=e.to,s=e.href,p=t||s,u=Object(l.a)(p),d=Object(r.useRef)(!1),b=c.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!b&&u&&window.docusaurus.prefetch(p),function(){b&&n&&n.disconnect()}}),[p,b,u]),p&&u?i.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(p),d.current=!0)},innerRef:function(e){var t,a;b&&e&&u&&(t=e,a=function(){window.docusaurus.prefetch(p)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),a())}))}))).observe(t))},to:p})):i.a.createElement("a",Object(a.a)({},e,{href:p}))}},429:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(427),o=t(420),l=t.n(o);t(133);n.a=function(e){var n=e.children,t=e.className,a=e.badge,o=e.leftIcon,s=e.rightIcon,c=e.size,p=e.target,u=e.to,d=l()("jump-to","jump-to--"+c,t),b=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},o&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+o})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",n),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:u,target:p,className:d},b):r.a.createElement(i.a,{to:u,className:d},b)}},430:function(e,n,t){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see 94a00d4e.03820917.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[149],{301:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return o})),t.d(n,"metadata",(function(){return l})),t.d(n,"rightToc",(function(){return s})),t.d(n,"default",(function(){return p}));var a=t(1),r=t(9),i=(t(0),t(425)),o=(t(424),t(429),t(431),{last_modified_on:"2022-04-22",$schema:"/.meta/.schemas/guides.json",title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",description:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",description:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",permalink:"/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws",readingTime:"10 min read",source:"@site/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",truncated:!1,prevItem:{title:"Debugging",permalink:"/guides/getting-started/debugging"},nextItem:{title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",permalink:"/guides/tutorial/build-e2e-testing-ephemeral-environments"}},s=[{value:"Qovery Deployment Platform",id:"qovery-deployment-platform",children:[]},{value:"Previ1ew Environments",id:"previ1ew-environments",children:[]},{value:"Preview environments benefits",id:"preview-environments-benefits",children:[]},{value:"Demo",id:"demo",children:[{value:"AWS Infrastructure",id:"aws-infrastructure",children:[]},{value:"Full Stack Application",id:"full-stack-application",children:[]},{value:"Frontend",id:"frontend",children:[]},{value:"Backend",id:"backend",children:[]},{value:"Deployment",id:"deployment",children:[]},{value:"Enable Preview Environments",id:"enable-preview-environments",children:[]},{value:"Testing Preview Environments",id:"testing-preview-environments",children:[]},{value:"Preview Environment Explained",id:"preview-environment-explained",children:[]},{value:"Testing Preview Environments PT II",id:"testing-preview-environments-pt-ii",children:[]},{value:"Conclusion",id:"conclusion",children:[]}]}],c={rightToc:s};function p(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},c,t,{components:n,mdxType:"MDXLayout"}),Object(i.b)("h3",{id:"qovery-deployment-platform"},"Qovery Deployment Platform"),Object(i.b)("p",null,"Have you ever dreamed of deploying your applications on the cloud without any hassle? Imagine a platform where all you need to do is to sign in with your AWS credentials, and automagically the platform does all the hard work of configuration of the cloud for you, and, on top of that, provides some extra features that do not exist out of the box anywhere else."),Object(i.b)("p",null,"Qovery is this platform - not only does it allow you to deploy your infrastructure and applications on your own cloud account, but also provides extra cool features, one of which we will see in this article."),Object(i.b)("p",null,Object(i.b)("em",{parentName:"p"},"Don't take our words for granted - 14000 developers from more than 100 countries use Qovery to deploy their apps on AWS.")),Object(i.b)("h3",{id:"previ1ew-environments"},"Previ1ew Environments"),Object(i.b)("p",null,"Imagine working on a new feature. You're dealing with a full-stack application - you have a frontend, backend, and a database. You introduce a change to your backend app - how do you test all of it? It would be great if there was a service that could deploy everything for you so you can test your changes quickly and in separation with all the components..."),Object(i.b)("p",null,"Qovery Preview Environments are designed to help you with exactly this."),Object(i.b)("p",null,"It not only deploys the app you changed but all other related applications and databases as well in the cloud so that you can test your new features and collaborate with reviewers of your code."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/1.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Preview environments feature is available on other platforms as well. Vercel and Netlify allows you to test your changes before merging code into production. It\u2019s perfect for single frontend applications, but the concept of Preview Environments on Qovery goes far beyond this."),Object(i.b)("p",null,"Qovery is able not only to create a preview environment for your frontend, but also for the backend and databases - the whole stack is supported. Running a set of backend microservices? No worries, Qovery got you covered. All services will be replicated in the new environment."),Object(i.b)("h3",{id:"preview-environments-benefits"},"Preview environments benefits"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Time-saving")," - You don't have to set up a fresh environment to test changes in isolation - Qovery does it all for you"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Productivity")," - Faster changes, quicker review, better feedback loop - the productivity and quality of your application increases dramatically"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Better tests")," - It's best to test apps in isolation, but it's almost impossible with a complicated stack if you have to prepare the testing environment manually - Qovery does it all \"automagically\" for you"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Independence")," - Each environment is completely separate, meaning more people can work flawlessly on the project, testing the changes they introduce in parallel, not blocking each other"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Deliver quickly")," - Faster feedback loop, independent developers, fewer bugs, meaning the product is delivered more quickly"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Reduce friction")," - Waiting for others to test your changes is frustrating - with preview envs everyone has his own testing environment")),Object(i.b)("h2",{id:"demo"},"Demo"),Object(i.b)("h3",{id:"aws-infrastructure"},"AWS Infrastructure"),Object(i.b)("p",null,"Before we start with the deployments, we need to have our AWS infrastructure ready and deployed. It can be done as simply as by providing credentials to your cloud account, you can see how to configure the credentials in this article - ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/"}),"https://hub.qovery.com/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/2.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"The initial setup takes about 15 min, and your cluster is ready to host your applications."),Object(i.b)("h3",{id:"full-stack-application"},"Full Stack Application"),Object(i.b)("p",null,"In this example, we will use a Next.js frontend, Node.js backend, and MongoDB as a database. The app will display an image gallery with images fetched from the backend. Preview Environments feature will help us introduce a new change in the backend - moving away from a hardcoded POC list of images to a list fetched from our database."),Object(i.b)("h3",{id:"frontend"},"Frontend"),Object(i.b)("p",null,"Our simple image gallery will look like this"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/3.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"To generate the application, we used ",Object(i.b)("inlineCode",{parentName:"p"},"npx create-next-app@latest"),", but the source code can be found here - ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/gallery-demo/tree/master/frontend"}),"https://github.com/pjeziorowski/gallery-demo/tree/master/frontend")),Object(i.b)("p",null,"The main changes introduced to the generated application scaffolding are:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Adding a ",Object(i.b)("inlineCode",{parentName:"li"},"Dockerfile"))),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-docker"}),"FROM node:alpine\n\nRUN mkdir -p /usr/src\nWORKDIR /usr/src\n\nCOPY . /usr/src\nRUN npm install\nRUN npm run build\n\nEXPOSE 3000\nCMD npm run start\n")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Adding a query to our backend (which we will be built soon in the next steps) that fetches a list of images to display in our gallery"),Object(i.b)("pre",{parentName:"li"},Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'function useImages() {\n return useQuery("images", async () => {\n const { data } = await axios.get(\n `${apiRoot}/api/v1/images`\n );\n return data;\n });\n}\n'))),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Plus, we adjusted the HTML and styling for the demo purpose of showing a list of images"))),Object(i.b)("h3",{id:"backend"},"Backend"),Object(i.b)("p",null,"Our backend is the main star of the demo. In its first version, the backend is displaying a hardcoded list of images. In the next step, we will gradually expand its capabilities. It will connect to a database and fetch the list from MongoDB instead. To make sure the changes are correct, we will use ",Object(i.b)("inlineCode",{parentName:"p"},"Preview Environment")," feature before merging the pull request to our production environment"),Object(i.b)("p",null,"The backend was generated using Express ",Object(i.b)("inlineCode",{parentName:"p"},"npx express-generator --no-view"),", and the source code can be found here - ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/gallery-demo/tree/master/frontend"}),"https://github.com/pjeziorowski/gallery-demo/tree/master/backend")),Object(i.b)("p",null,"Changes that we introduced to the generated app scaffolding are the following:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Adding a Dockerfile"),Object(i.b)("pre",{parentName:"li"},Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-docker"}),'FROM node:16\n\nWORKDIR /usr/src/app\n\nCOPY package*.json ./\nRUN npm install\nCOPY . .\n\nEXPOSE 8080\nCMD [ "node", "src/index.js" ]\n'))),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Creating a ",Object(i.b)("inlineCode",{parentName:"p"},"/api/v1/images")," endpoint that returns a hardcoded array of images"),Object(i.b)("pre",{parentName:"li"},Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"router.get('/images', (req, res) => {\n res.json([\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n }\n });\n});\n")),Object(i.b)("p",{parentName:"li"}," In the next step we will improve the function to use a Mongo database instead."))),Object(i.b)("h3",{id:"deployment"},"Deployment"),Object(i.b)("p",null,"After creating a new project, let's now set up our ",Object(i.b)("inlineCode",{parentName:"p"},"production")," environment."),Object(i.b)("p",null,"First, let's deploy our frontend. Click ",Object(i.b)("inlineCode",{parentName:"p"},"Add my first application"),", select a correct repository, ",Object(i.b)("inlineCode",{parentName:"p"},"Docker")," as build mode and expose port ",Object(i.b)("inlineCode",{parentName:"p"},"3000"),". The application root path is ",Object(i.b)("inlineCode",{parentName:"p"},"/frontend"),"."),Object(i.b)("p",null,"Next step: add a ",Object(i.b)("inlineCode",{parentName:"p"},"MongoDB")," database - it will be used by our backend later on. You can do so by clicking on ",Object(i.b)("inlineCode",{parentName:"p"},"Add")," button in Qovery Console in Environment."),Object(i.b)("p",null,"Now let's deploy our backend. Click ",Object(i.b)("inlineCode",{parentName:"p"},"Add")," \u2192 ",Object(i.b)("inlineCode",{parentName:"p"},"Application"),", pick up ",Object(i.b)("inlineCode",{parentName:"p"},"/backend")," as application root path, ",Object(i.b)("inlineCode",{parentName:"p"},"8080")," port, and ",Object(i.b)("inlineCode",{parentName:"p"},"Docker")," build mode."),Object(i.b)("p",null,"For the future connection to DB, let's add an alias named ",Object(i.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," that points to our Mongo database internal URL in our backend ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variable")," settings:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/4.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Additionally, let's create an alias called ",Object(i.b)("inlineCode",{parentName:"p"},"API_ROOT")," in our frontend application that points to our backend external URL:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/5.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"This is it! Now we can deploy our production environment. After a few minutes, navigate to the frontend app, click on ",Object(i.b)("inlineCode",{parentName:"p"},"Open")," - you should be redirected to the image gallery"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/6.png",alt:"AWS Preview Environments"})),Object(i.b)("h3",{id:"enable-preview-environments"},"Enable Preview Environments"),Object(i.b)("p",null,"The next step to see the preview environment feature in action is to enable it for our backend application."),Object(i.b)("p",null,"To do so, navigate to ",Object(i.b)("inlineCode",{parentName:"p"},"Environment")," \u2192 ",Object(i.b)("inlineCode",{parentName:"p"},"Settings")," \u2192 ",Object(i.b)("inlineCode",{parentName:"p"},"Preview Env")," and tick it for the backend app"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/7.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Great! The feature is enabled. To see it in action, let's edit our code in the backend app so that the list of images is fetched from the database instead."),Object(i.b)("h3",{id:"testing-preview-environments"},"Testing Preview Environments"),Object(i.b)("p",null,"Let's make a small update of our backend - let's connect to MongoDB and fetch images from there. Here are changes to the function we could introduce to make it happen:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const databaseUrl = process.env.DATABASE_URL\n || 'mongodb://localhost:27017/test';\n\nconst imageSchema = new mongoose.Schema({\n title: String,\n size: String,\n source: String\n});\n\nmongoose.connect(databaseUrl);\n\nrouter.get('/', (req, res) => {\n imageSchema.find().then((data) => {\n res.json(\n data\n )\n });\n});\n")),Object(i.b)("p",null,"Let's now create a new branch in our repository and create a pull request to our production (master branch) environment. Preview Environments feature will spin up a new environment for us so that we can safely test changes we just introduced!"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/8.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Once the PR is created, an automatic comment has been dropped on our PR to let us know that the new preview environment has been created."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/14.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Now, when we display environments in our project, we will see that a new environment for the pull request is being deployed:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/9.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"with all the resources we need! A database, backend, frontend - we can now test our changes in complete separation from the production without any manual setting up work:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/10.png",alt:"AWS Preview Environments"})),Object(i.b)("h3",{id:"preview-environment-explained"},"Preview Environment Explained"),Object(i.b)("p",null,"The Preview Environment feature can be enabled or disabled per app. It creates a complete copy of your environment so that you can test new changes from pull requests in separation. It deploys your databases, backend, and frontend applications to a completely new environment once a pull request is opened. If you update your pull request, all new changes are also reflected in the new environment so that you can test them or fix problems during the review. What is great is that Qovery takes care of managing all environment variables for you as well, creates new aliases just as you had in your prod environment, so that everything is really tested separately and it all happens automagically. After the pull request is merged, Qovery automatically cleans up the preview environment to save your money."),Object(i.b)("h3",{id:"testing-preview-environments-pt-ii"},"Testing Preview Environments PT II"),Object(i.b)("p",null,"After a few minutes, your preview environment should be up and running. You can now navigate to the frontend app and click ",Object(i.b)("inlineCode",{parentName:"p"},"Open")," - in the image gallery, you will see an empty list because we don't yet have any images in the database."),Object(i.b)("p",null,"You can add a few images manually by connecting to your mongo instance via CLI. The credentials can be found in the database overview:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/11.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"After connecting, let's add images by executing the following:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"db.createCollection(\"images\")\n\ndb.images.insert([\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n },\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n },\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n }\n ])\n")),Object(i.b)("p",null,"Now, after opening the frontend app in our preview environment, we will see all the images we put in the database! It looks like the feature is working well, so let's merge the PR:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/12.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"What now happens is automatically after the PR merge, the preview environment is automatically cleaned up:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/13.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Great job! Thanks to Qovery Preview Environments, we managed to develop a new feature in a complete separation from our production, we tested it in a real environment deployed in the cloud, and we didn't have to spend any time preparing our environment for tests at all."),Object(i.b)("h3",{id:"conclusion"},"Conclusion"),Object(i.b)("p",null,"In the article, we quickly went through the process of creating a full-stack application with frontend, backend, and database. We enabled the Preview Environment feature to develop new features more quickly. We learned what the benefits of Preview Environments are, how to use them, and how to integrate them to day to day development workflow."))}p.isMDXComponent=!0},423:function(e,n,t){var a;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var c=r.a.createContext({}),p=function(e){var n=r.a.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):l({},n,{},e)),t},u=function(e){var n=p(e.components);return r.a.createElement(c.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},b=Object(a.forwardRef)((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,o=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=p(t),b=a,m=u["".concat(o,".").concat(b)]||u[b]||d[b]||i;return t?r.a.createElement(m,l({ref:n},c,{components:t})):r.a.createElement(m,l({ref:n},c))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=b;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var c=2;c1?arguments[1]:void 0,t),s=o>2?arguments[2]:void 0,c=void 0===s?t:r(s,t);c>l;)n[l++]=e;return n}},428:function(e,n,t){var a=t(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||t(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,n,t){"use strict";t(428);var a=t(0),r=t.n(a),i=t(424);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},430:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),l=t(432),s=t(20),c=t.n(s);n.a=function(e){var n,t=e.to,s=e.href,p=t||s,u=Object(l.a)(p),d=Object(r.useRef)(!1),b=c.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!b&&u&&window.docusaurus.prefetch(p),function(){b&&n&&n.disconnect()}}),[p,b,u]),p&&u?i.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(p),d.current=!0)},innerRef:function(e){var t,a;b&&e&&u&&(t=e,a=function(){window.docusaurus.prefetch(p)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),a())}))}))).observe(t))},to:p})):i.a.createElement("a",Object(a.a)({},e,{href:p}))}},431:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(430),o=t(423),l=t.n(o);t(133);n.a=function(e){var n=e.children,t=e.className,a=e.badge,o=e.leftIcon,s=e.rightIcon,c=e.size,p=e.target,u=e.to,d=l()("jump-to","jump-to--"+c,t),b=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},o&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+o})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",n),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:u,target:p,className:d},b):r.a.createElement(i.a,{to:u,className:d},b)}},432:function(e,n,t){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/9ab61bc5.d5def6ed.js.LICENSE.txt b/94a00d4e.03820917.js.LICENSE.txt similarity index 100% rename from 9ab61bc5.d5def6ed.js.LICENSE.txt rename to 94a00d4e.03820917.js.LICENSE.txt diff --git a/967beaa8.3a31bcc4.js b/967beaa8.11f606ea.js similarity index 93% rename from 967beaa8.3a31bcc4.js rename to 967beaa8.11f606ea.js index 6b031f1f97..5a8339c0ee 100644 --- a/967beaa8.3a31bcc4.js +++ b/967beaa8.11f606ea.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[147],{299:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return d}));var a=n(1),r=n(9),o=(n(0),n(422)),l=n(421),i=(n(434),n(426)),c={last_modified_on:"2023-07-29",$schema:"/.meta/.schemas/guides.json",title:"Create a Playground Environment on AWS",description:"Step-by-step guide to create a Playground environment on AWS",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},u={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Create a Playground Environment on AWS",description:"Step-by-step guide to create a Playground environment on AWS",permalink:"/guides/tutorial/create-a-playground-environment-on-aws",readingTime:"3 min read",source:"@site/guides/tutorial/create-a-playground-environment-on-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Create a Playground Environment on AWS",truncated:!1,prevItem:{title:"Create a blazingly fast REST API in Rust (Part 1/2)",permalink:"/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1"},nextItem:{title:"Create your Staging environment from your Production environment on AWS",permalink:"/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws"}},s=[{value:"Create your Playground Environment",id:"create-your-playground-environment",children:[]},{value:"Delete your Playground Environment",id:"delete-your-playground-environment",children:[]},{value:"Optional: Create a Playground Cluster",id:"optional-create-a-playground-cluster",children:[]},{value:"Wrapping up",id:"wrapping-up",children:[]}],b={rightToc:s};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)(l.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"The Qovery Playground is another concept than creating a Playground Environment. ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/blog/discover-learn-and-experience-the-qovery-playground-is-now-open"}),"Read more about the Qovery Playground"),".")),Object(o.b)("p",null,"A Playground Environment is an environment where you can do all your testing without impacting an existing environment."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/playground_environments.jpg",alt:"Playground environments"})),Object(o.b)("p",null,"Here are some use cases where a playground environment is helpful for:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Experimenting"),": Test your code without the fear to break anything from your original environment."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Benchmarking"),": You want to stress your application without affecting the original environment."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Debugging"),": You have a bug in production that you want to reproduce but without impacting the production environment."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Product Demo"),": Your Sales or Product Manager needs to make an important demo and want to be sure it will work.")),Object(o.b)(i.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You already have a production environment deployed with Qovery."))),Object(o.b)("p",null,"In this guide, we will create a playground environment on AWS."),Object(o.b)(l.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"Quick Tip: Creating a playground environment results in using the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#clone-environment"}),"Environment Clone")," feature to duplicate it! Nothing more.")),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/90cc74349adb42bc9630fb546886b586",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("h2",{id:"create-your-playground-environment"},"Create your Playground Environment"),Object(o.b)("p",null,"To create your Playground Environment you simply need to:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Go into the base environment that you want to clone"),Object(o.b)("li",{parentName:"ol"},"Click on the ",Object(o.b)("inlineCode",{parentName:"li"},"Actions")," and ",Object(o.b)("inlineCode",{parentName:"li"},"Clone")," button"),Object(o.b)("li",{parentName:"ol"},"Enter a name for your playground environment"),Object(o.b)("li",{parentName:"ol"},"Select the cluster where you want to deploy it"),Object(o.b)("li",{parentName:"ol"},"Set the Environment mode to ",Object(o.b)("inlineCode",{parentName:"li"},"Development")),Object(o.b)("li",{parentName:"ol"},"Click on the Create button"),Object(o.b)("li",{parentName:"ol"},"Deploy your Playground Environment")),Object(o.b)("p",null,"Once deployed, your applications within this environment will have dedicated URLs to get access to. You can use these URLs to test your application."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/48290a88f2294b6f9c371879c2d25cdc",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("p",null,"Then you can check that your playground environment is working by visiting the temporary URL."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/3531b538f4ed47b49a1078303210da83",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("h2",{id:"delete-your-playground-environment"},"Delete your Playground Environment"),Object(o.b)("p",null,"To delete your Playground Environment you simply need to:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Go into the playground environment"),Object(o.b)("li",{parentName:"ol"},"Click on the ",Object(o.b)("inlineCode",{parentName:"li"},"Actions")," and ",Object(o.b)("inlineCode",{parentName:"li"},"Delete")," button"),Object(o.b)("li",{parentName:"ol"},"Confirm and Delete the environment")),Object(o.b)("p",null,"All the resources will be freed."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/951d93f22bbb45aba4a2162104fcdcd9",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("h2",{id:"optional-create-a-playground-cluster"},"Optional: Create a Playground Cluster"),Object(o.b)("p",null,"To prevent your playground environment from impacting your production environment, you can create a dedicated cluster. So every playground environments will be on the same cluster and will not disturb your production."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/playground_environments_with_2_clusters.jpg",alt:"Playground environments with 2 clusters"})),Object(o.b)("p",null,"Here is how to create a playground cluster."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/7cea821edfb7447a928dd707a7d428b5",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("p",null,"And how to create a playground environment on our ",Object(o.b)("inlineCode",{parentName:"p"},"playground cluster"),"."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/82ccf107e3374c08a9f6b629451ef736",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(o.b)("p",null,"In this guide, we have covered everything you need to know to create a secure staging environment from your production. Now, you can take a look at ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/data-seeding-in-postgres/"}),"how to seed your Staging database")," (Guide for Postgres but applicable for most databases)."))}d.isMDXComponent=!0},421:function(e,t,n){"use strict";n(423);var a=n(0),r=n.n(a),o=n(420),l=n.n(o);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,o=e.icon,i=e.type,c=null;switch(i){case"danger":c="alert-triangle";break;case"success":c="check-circle";break;case"warning":c="alert-triangle";break;default:c="info"}return r.a.createElement("div",{className:l()(n,"alert","alert--"+i,{"alert--fill":a,"alert--icon":!1!==o}),role:"alert"},!1!==o&&r.a.createElement("i",{className:l()("feather","icon-"+(o||c))}),t)}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},434:function(e,t,n){"use strict";var a=n(1),r=(n(439),n(436),n(52),n(29),n(22),n(21),n(0)),o=n.n(r),l=n(446),i=n(420),c=n.n(i),u=n(428),s=n.n(u),b=n(445),d=37,m=39;function p(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,r=e.className,l=e.handleKeydown,i=e.style,u=e.values,s=e.selectedValue,b=e.tabRefs;return o.a.createElement("div",{className:n?"tabs--centered":null},o.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:c()("tabs",r,{"tabs--block":t}),style:i},u.map((function(e){var t=e.value,n=e.label;return o.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":s===t,className:c()("tab-item",{"tab-item--active":s===t}),key:t,ref:function(e){return b.push(e)},onKeyDown:function(e){return l(b,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function g(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,r=e.size,i=e.values,c=i;if(c[0].group){var u=_.groupBy(c,"group");c=Object.keys(u).map((function(e){return{label:e,options:u[e]}}))}return o.a.createElement(l.a,{className:"react-select-container react-select--"+r,classNamePrefix:"react-select",options:c,isClearable:n,placeholder:t,value:i.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,l=e.groupId,i=e.label,c=e.placeholder,u=e.select,y=e.size,h=(e.style,e.values),f=e.urlKey,v=Object(b.a)(),w=v.tabGroupChoices,O=v.setTabGroupChoices,j=Object(r.useState)(n),N=j[0],k=j[1];if(null!=l){var C=w[l];null!=C&&C!==N&&k(C)}var E=function(e){k(e),null!=l&&O(l,e)},P=[],S=function(e,t,n){switch(n.keyCode){case m:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case d:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(r.useEffect)((function(){if("undefined"!=typeof window&&window.location&&f){var e=s.a.parse(window.location.search);e[f]&&k(e[f])}}),[]),o.a.createElement(o.a.Fragment,null,o.a.createElement("div",{className:"margin-bottom--"+(y||"md")},i&&o.a.createElement("div",{className:"margin-vert--sm"},i),h.length>1&&(u?o.a.createElement(g,Object(a.a)({changeSelectedValue:E,handleKeydown:S,placeholder:c,selectedValue:N,size:y,tabRefs:P},e)):o.a.createElement(p,Object(a.a)({changeSelectedValue:E,handleKeydown:S,selectedValue:N,tabRefs:P},e)))),r.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[150],{302:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return d}));var a=n(1),r=n(9),o=(n(0),n(425)),l=n(424),i=(n(437),n(429)),c={last_modified_on:"2023-07-29",$schema:"/.meta/.schemas/guides.json",title:"Create a Playground Environment on AWS",description:"Step-by-step guide to create a Playground environment on AWS",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},u={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Create a Playground Environment on AWS",description:"Step-by-step guide to create a Playground environment on AWS",permalink:"/guides/tutorial/create-a-playground-environment-on-aws",readingTime:"3 min read",source:"@site/guides/tutorial/create-a-playground-environment-on-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Create a Playground Environment on AWS",truncated:!1,prevItem:{title:"Create a blazingly fast REST API in Rust (Part 1/2)",permalink:"/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1"},nextItem:{title:"Create your Staging environment from your Production environment on AWS",permalink:"/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws"}},s=[{value:"Create your Playground Environment",id:"create-your-playground-environment",children:[]},{value:"Delete your Playground Environment",id:"delete-your-playground-environment",children:[]},{value:"Optional: Create a Playground Cluster",id:"optional-create-a-playground-cluster",children:[]},{value:"Wrapping up",id:"wrapping-up",children:[]}],b={rightToc:s};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)(l.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"The Qovery Playground is another concept than creating a Playground Environment. ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/blog/discover-learn-and-experience-the-qovery-playground-is-now-open"}),"Read more about the Qovery Playground"),".")),Object(o.b)("p",null,"A Playground Environment is an environment where you can do all your testing without impacting an existing environment."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/playground_environments.jpg",alt:"Playground environments"})),Object(o.b)("p",null,"Here are some use cases where a playground environment is helpful for:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Experimenting"),": Test your code without the fear to break anything from your original environment."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Benchmarking"),": You want to stress your application without affecting the original environment."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Debugging"),": You have a bug in production that you want to reproduce but without impacting the production environment."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Product Demo"),": Your Sales or Product Manager needs to make an important demo and want to be sure it will work.")),Object(o.b)(i.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You already have a production environment deployed with Qovery."))),Object(o.b)("p",null,"In this guide, we will create a playground environment on AWS."),Object(o.b)(l.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"Quick Tip: Creating a playground environment results in using the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#clone-environment"}),"Environment Clone")," feature to duplicate it! Nothing more.")),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/90cc74349adb42bc9630fb546886b586",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("h2",{id:"create-your-playground-environment"},"Create your Playground Environment"),Object(o.b)("p",null,"To create your Playground Environment you simply need to:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Go into the base environment that you want to clone"),Object(o.b)("li",{parentName:"ol"},"Click on the ",Object(o.b)("inlineCode",{parentName:"li"},"Actions")," and ",Object(o.b)("inlineCode",{parentName:"li"},"Clone")," button"),Object(o.b)("li",{parentName:"ol"},"Enter a name for your playground environment"),Object(o.b)("li",{parentName:"ol"},"Select the cluster where you want to deploy it"),Object(o.b)("li",{parentName:"ol"},"Set the Environment mode to ",Object(o.b)("inlineCode",{parentName:"li"},"Development")),Object(o.b)("li",{parentName:"ol"},"Click on the Create button"),Object(o.b)("li",{parentName:"ol"},"Deploy your Playground Environment")),Object(o.b)("p",null,"Once deployed, your applications within this environment will have dedicated URLs to get access to. You can use these URLs to test your application."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/48290a88f2294b6f9c371879c2d25cdc",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("p",null,"Then you can check that your playground environment is working by visiting the temporary URL."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/3531b538f4ed47b49a1078303210da83",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("h2",{id:"delete-your-playground-environment"},"Delete your Playground Environment"),Object(o.b)("p",null,"To delete your Playground Environment you simply need to:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Go into the playground environment"),Object(o.b)("li",{parentName:"ol"},"Click on the ",Object(o.b)("inlineCode",{parentName:"li"},"Actions")," and ",Object(o.b)("inlineCode",{parentName:"li"},"Delete")," button"),Object(o.b)("li",{parentName:"ol"},"Confirm and Delete the environment")),Object(o.b)("p",null,"All the resources will be freed."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/951d93f22bbb45aba4a2162104fcdcd9",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("h2",{id:"optional-create-a-playground-cluster"},"Optional: Create a Playground Cluster"),Object(o.b)("p",null,"To prevent your playground environment from impacting your production environment, you can create a dedicated cluster. So every playground environments will be on the same cluster and will not disturb your production."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/playground_environments_with_2_clusters.jpg",alt:"Playground environments with 2 clusters"})),Object(o.b)("p",null,"Here is how to create a playground cluster."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/7cea821edfb7447a928dd707a7d428b5",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("p",null,"And how to create a playground environment on our ",Object(o.b)("inlineCode",{parentName:"p"},"playground cluster"),"."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/82ccf107e3374c08a9f6b629451ef736",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(o.b)("p",null,"In this guide, we have covered everything you need to know to create a secure staging environment from your production. Now, you can take a look at ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/data-seeding-in-postgres/"}),"how to seed your Staging database")," (Guide for Postgres but applicable for most databases)."))}d.isMDXComponent=!0},424:function(e,t,n){"use strict";n(426);var a=n(0),r=n.n(a),o=n(423),l=n.n(o);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,o=e.icon,i=e.type,c=null;switch(i){case"danger":c="alert-triangle";break;case"success":c="check-circle";break;case"warning":c="alert-triangle";break;default:c="info"}return r.a.createElement("div",{className:l()(n,"alert","alert--"+i,{"alert--fill":a,"alert--icon":!1!==o}),role:"alert"},!1!==o&&r.a.createElement("i",{className:l()("feather","icon-"+(o||c))}),t)}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},437:function(e,t,n){"use strict";var a=n(1),r=(n(442),n(439),n(52),n(29),n(22),n(21),n(0)),o=n.n(r),l=n(449),i=n(423),c=n.n(i),u=n(433),s=n.n(u),b=n(448),d=37,m=39;function p(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,r=e.className,l=e.handleKeydown,i=e.style,u=e.values,s=e.selectedValue,b=e.tabRefs;return o.a.createElement("div",{className:n?"tabs--centered":null},o.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:c()("tabs",r,{"tabs--block":t}),style:i},u.map((function(e){var t=e.value,n=e.label;return o.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":s===t,className:c()("tab-item",{"tab-item--active":s===t}),key:t,ref:function(e){return b.push(e)},onKeyDown:function(e){return l(b,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function g(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,r=e.size,i=e.values,c=i;if(c[0].group){var u=_.groupBy(c,"group");c=Object.keys(u).map((function(e){return{label:e,options:u[e]}}))}return o.a.createElement(l.a,{className:"react-select-container react-select--"+r,classNamePrefix:"react-select",options:c,isClearable:n,placeholder:t,value:i.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,l=e.groupId,i=e.label,c=e.placeholder,u=e.select,y=e.size,h=(e.style,e.values),f=e.urlKey,v=Object(b.a)(),w=v.tabGroupChoices,O=v.setTabGroupChoices,j=Object(r.useState)(n),N=j[0],k=j[1];if(null!=l){var C=w[l];null!=C&&C!==N&&k(C)}var E=function(e){k(e),null!=l&&O(l,e)},P=[],S=function(e,t,n){switch(n.keyCode){case m:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case d:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(r.useEffect)((function(){if("undefined"!=typeof window&&window.location&&f){var e=s.a.parse(window.location.search);e[f]&&k(e[f])}}),[]),o.a.createElement(o.a.Fragment,null,o.a.createElement("div",{className:"margin-bottom--"+(y||"md")},i&&o.a.createElement("div",{className:"margin-vert--sm"},i),h.length>1&&(u?o.a.createElement(g,Object(a.a)({changeSelectedValue:E,handleKeydown:S,placeholder:c,selectedValue:N,size:y,tabRefs:P},e)):o.a.createElement(p,Object(a.a)({changeSelectedValue:E,handleKeydown:S,selectedValue:N,tabRefs:P},e)))),r.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}}}]); \ No newline at end of file diff --git a/97f5d064.b0e4137c.js b/97f5d064.0b3165a6.js similarity index 94% rename from 97f5d064.b0e4137c.js rename to 97f5d064.0b3165a6.js index b92482385d..8c31fa5b9c 100644 --- a/97f5d064.b0e4137c.js +++ b/97f5d064.0b3165a6.js @@ -1,2 +1,2 @@ -/*! For license information please see 97f5d064.b0e4137c.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[148],{300:function(e,t,o){"use strict";o.r(t),o.d(t,"frontMatter",(function(){return s})),o.d(t,"metadata",(function(){return l})),o.d(t,"rightToc",(function(){return u})),o.d(t,"default",(function(){return b}));var n=o(1),a=o(9),r=(o(0),o(422)),i=o(421),c=(o(426),o(429)),s={last_modified_on:"2022-07-09",$schema:"/.meta/.schemas/guides.json",title:"Zero to Hero - How to deploy your apps on AWS in 30 minutes",description:"Step-by-step guide on how to deploy your apps on AWS in 30 minutes. No AWS knowledge required.",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0},l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Zero to Hero - How to deploy your apps on AWS in 30 minutes",description:"Step-by-step guide on how to deploy your apps on AWS in 30 minutes. No AWS knowledge required.",permalink:"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes",readingTime:"6 min read",source:"@site/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Zero to Hero - How to deploy your apps on AWS in 30 minutes",truncated:!1,prevItem:{title:"Working with Git Submodules",permalink:"/guides/tutorial/working-with-git-submodules"}},u=[{value:"Before you start",id:"before-you-start",children:[{value:"What is Qovery",id:"what-is-qovery",children:[]},{value:"Why you should use AWS",id:"why-you-should-use-aws",children:[]},{value:"Why you should not use AWS",id:"why-you-should-not-use-aws",children:[]}]},{value:"Create an AWS account",id:"create-an-aws-account",children:[{value:"Get your AWS API keys",id:"get-your-aws-api-keys",children:[]}]},{value:"Configure Qovery",id:"configure-qovery",children:[{value:"Sign-up to Qovery",id:"sign-up-to-qovery",children:[]},{value:"Create your Organization",id:"create-your-organization",children:[]},{value:"Install Qovery on your AWS account",id:"install-qovery-on-your-aws-account",children:[]}]},{value:"Deploy your application",id:"deploy-your-application",children:[]}],p={rightToc:u};function b(e){var t=e.components,o=Object(a.a)(e,["components"]);return Object(r.b)("wrapper",Object(n.a)({},p,o,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aws.amazon.com?ref=qovery"}),"Amazon Web Services")," (AWS) is a platform that offers flexible, reliable, and scalable Cloud computing solutions. The platform is developed with a combination of infrastructure as a service (IaaS), platform as a service (PaaS), and packaged software as a service (SaaS) offerings. In 2021, thousands of companies host their apps on AWS. In 2006, AWS was composed of only 3 services (SQS, S3, EC2) that were simple to use. In 2021, more than 200 services and 2000 features exist, and deploying your app can take days."),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.qovery.com"}),"Qovery")," is the simplest way to deploy your apps on AWS.")),Object(r.b)("p",null,"In this tutorial, I will explain step by step how to deploy your app on AWS in 30 minutes. No AWS/infrastructure/Cloud knowledge required - no kidding!"),Object(r.b)("h2",{id:"before-you-start"},"Before you start"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"This tutorial is perfect for anyone interested into deploying their apps on AWS seamlessly."),Object(r.b)("li",{parentName:"ol"},"If you have any question or suggestion on this tutorial, please contact us via ",Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.qovery.com/contact"}),"this form")," or ",Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://discord.qovery.com"}),"Discord"),".")),Object(r.b)("h3",{id:"what-is-qovery"},"What is Qovery"),Object(r.b)("p",null,'Qovery is a platform that makes your app deployment on AWS very simple. The installation of Qovery on your AWS account takes approximately 30 minutes. Then you\'re ready to deploy your apps "\xe0 la" Heroku-like.'),Object(r.b)("h3",{id:"why-you-should-use-aws"},"Why you should use AWS"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You need a reliable hosting platform."),Object(r.b)("li",{parentName:"ul"},"You want to stay focus on what you are building."),Object(r.b)("li",{parentName:"ul"},"You need to speed up your Go-To-Market and Product Market Fit."),Object(r.b)("li",{parentName:"ul"},"You plan to be the next unicorn \ud83e\udd84")),Object(r.b)("h3",{id:"why-you-should-not-use-aws"},"Why you should not use AWS"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You are building a hobby project."),Object(r.b)("li",{parentName:"ul"},"You are looking for a cheap hosting provider."),Object(r.b)("li",{parentName:"ul"},"You do not want to use Amazon services.")),Object(r.b)("p",null,"Let's start!"),Object(r.b)("h1",{id:"video-install-qovery-on-aws"},"Video: Install Qovery on AWS"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Follow ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"this guide")," to create your AWS credentials")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/3450aa0c4122467892cd7c6e1fc85f6e",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h1",{id:"step-by-step-install-qovery-on-aws"},"Step-by-step: Install Qovery on AWS"),Object(r.b)("h2",{id:"create-an-aws-account"},"Create an AWS account"),Object(r.b)("p",null,Object(r.b)("em",{parentName:"p"},"If you already have an AWS account, you can go to the next point.")),Object(r.b)("p",null,"Before creating an AWS account, I'd recommend contacting AWS to see if you are eligible to free credits. AWS provides up to $100k of credits for 12 to 24 months. Which is convenient to have at the beginning of a project. If you know that you are not eligible, you can create your account by clicking on the top right button ",Object(r.b)("inlineCode",{parentName:"p"},"Create an AWS Account")," of their ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aws.amazon.com?ref=qovery"}),"main page"),"."),Object(r.b)("img",{src:"/img/aws-create-an-account.jpg",alt:"Create an account on AWS"}),Object(r.b)("h3",{id:"get-your-aws-api-keys"},"Get your AWS API keys"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Follow ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"this guide")," to create your AWS credentials")),Object(r.b)("p",null,"To install Qovery on your AWS account, the ",Object(r.b)("inlineCode",{parentName:"p"},"secret access key")," and ",Object(r.b)("inlineCode",{parentName:"p"},"access key id")," are required. Here is a comprehensive ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"step-by-step guide")," on how to generate your ",Object(r.b)("inlineCode",{parentName:"p"},"secret access key")," and ",Object(r.b)("inlineCode",{parentName:"p"},"access key id"),". If you already have those keys, then you can go to the next point."),Object(r.b)("h2",{id:"configure-qovery"},"Configure Qovery"),Object(r.b)("h3",{id:"sign-up-to-qovery"},"Sign-up to Qovery"),Object(r.b)("p",null,"Using Qovery is as simple as connect with your ",Object(r.b)("em",{parentName:"p"},"Github"),", ",Object(r.b)("em",{parentName:"p"},"Gitlab")," or ",Object(r.b)("em",{parentName:"p"},"Bitbucket")," account on ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"start.qovery.com"),"."),Object(r.b)("p",null,"-> ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Connect to Qovery")),Object(r.b)("h3",{id:"create-your-organization"},"Create your Organization"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can skip this step if you already have an Organization.")),Object(r.b)("p",null,"An organization is a shared account where developers can collaborate across many projects at once. Owners and organization administrators can manage:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Cloud accounts."),Object(r.b)("li",{parentName:"ul"},"Members access."),Object(r.b)("li",{parentName:"ul"},"Billing.")),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/"}),"Read more")," about Organizations"),Object(r.b)("p",null,"To deploy on your AWS account, you have to choose between ",Object(r.b)("strong",{parentName:"p"},"Free"),", ",Object(r.b)("strong",{parentName:"p"},"Professional")," and ",Object(r.b)("strong",{parentName:"p"},"Business")," plan for your organization."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Qovery_Pricing_Plans.png",alt:"Qovery - Create an Organization and select the plan"})),Object(r.b)("h3",{id:"install-qovery-on-your-aws-account"},"Install Qovery on your AWS account"),Object(r.b)("p",null,'1/ Go to your organization settings by clicking on the "cog" icon next to your organization name.'),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_clusters_empty.jpg",alt:"Go your organization settings > clusters"})),Object(r.b)("p",null,"2/ Create a cluster, select ",Object(r.b)("em",{parentName:"p"},"Amazon Web Services")," and the region where you want to deploy your apps."),Object(r.b)(i.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Choose a region close to where your users will use your applications to have better performances.")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_create_cluster.jpg",alt:"Create a cluster"})),Object(r.b)("p",null,"3/ Set your AWS credentials. (Check out ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/"}),"this guide")," if you have no AWS credentials)."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_add_credentials.jpg",alt:"Set your cloud credentials"})),Object(r.b)("p",null,"4/ Under the hood, Qovery uses a managed Kubernetes (",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aws.amazon.com/eks"}),"AWS EKS"),") to run your applications. You need to specify the instance type that you would like to use and the min/max number of nodes. Qovery will keep low the number of nodes and will only scale up your nodes if your applications really need to scale.\nIf you don't know which instance type to chose, have a look at the AWS instance list or use the helper to chose the right instance based on your CPU/RAM needs."),Object(r.b)(i.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Qovery optimizes and keep your AWS costs low.")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_cluster_resources.jpg",alt:"Set your cluster resources"})),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},"Qovery might use some temporary free resources on your Kubernetes cluster to perform spotted maintenance operations (e.g. : cluster version upgrades). This is why we recommend a cluster setup with:",Object(r.b)("ul",null,Object(r.b)("li",null,"at least 20% difference between the minimum and the maximum number of nodes;"),Object(r.b)("li",null,"at least 5 nodes as the maximum number of nodes of your cluster;"))),Object(r.b)("p",null,"5/ Click on ",Object(r.b)("strong",{parentName:"p"},"Save")," and ",Object(r.b)("strong",{parentName:"p"},"Deploy"),"."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_clusters_aws.jpg",alt:"AWS cluster is now available"})),Object(r.b)("p",null,"Congrats! Qovery will be installed within 30 minutes \ud83c\udf89. You will be notified when it is all good.\nIn the meantime, you can take a look at our ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"guide section"),"."),Object(r.b)("p",null,"6/ Enable cluster sync with SSO account"),Object(r.b)("p",null,"If you're using SSO for your AWS account deploying the Qovery cluster you have to add some infos in the ",Object(r.b)("em",{parentName:"p"},"aws-auth configmap")," in ",Object(r.b)("inlineCode",{parentName:"p"},"kube-system")," namespace.\nConnect to your cluster and edit the ",Object(r.b)("em",{parentName:"p"},"aws-auth configmap")," in order to add the following code in the mapRoles section:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-yaml"}),'- rolearn: arn:aws:iam:::role/AWSReservedSSO_AdministratorAccess_\n username: "{{SessionName}}"\n groups:\n - system:masters\n')),Object(r.b)("h2",{id:"deploy-your-application"},"Deploy your application"),Object(r.b)("p",null,"Once Qovery is installed on your AWS account, you have the possibility to deploy your application. Take a look to ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"our guide")," on how to ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"deploy your first application")," with Qovery."),Object(r.b)(c.a,{to:"/guides/getting-started/deploy-your-first-application",mdxType:"Jump"},"Deploy your first application"))}b.isMDXComponent=!0},420:function(e,t,o){var n;!function(){"use strict";var o={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[o]=e[o]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(a[o]=e[o])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),o=t;return e&&(o="function"==typeof e?e(t):c({},t,{},e)),o},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var o=e.components,n=e.mdxType,r=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(o),d=n,y=p["".concat(i,".").concat(d)]||p[d]||b[d]||r;return o?a.a.createElement(y,c({ref:t},l,{components:o})):a.a.createElement(y,c({ref:t},l))}));function y(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=o.length,i=new Array(r);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l1?arguments[1]:void 0,o),s=i>2?arguments[2]:void 0,l=void 0===s?o:a(s,o);l>c;)t[c++]=e;return t}},425:function(e,t,o){var n=o(28).f,a=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in a||o(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,o){"use strict";o(425);var n=o(0),a=o.n(n),r=o(421);t.a=function(e){var t=e.children,o=e.name;return a.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",o||"page"," assumes the following:"),t)}},427:function(e,t,o){"use strict";var n=o(1),a=o(0),r=o.n(a),i=o(39),c=o(430),s=o(20),l=o.n(s);t.a=function(e){var t,o=e.to,s=e.href,u=o||s,p=Object(c.a)(u),b=Object(a.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?r.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var o,n;d&&e&&p&&(o=e,n=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){o===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(o),t.disconnect(),n())}))}))).observe(o))},to:u})):r.a.createElement("a",Object(n.a)({},e,{href:u}))}},429:function(e,t,o){"use strict";var n=o(0),a=o.n(n),r=o(427),i=o(420),c=o.n(i);o(133);t.a=function(e){var t=e.children,o=e.className,n=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+l,o),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},n?a.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?a.a.createElement("a",{href:p,target:u,className:b},d):a.a.createElement(r.a,{to:p,className:b},d)}},430:function(e,t,o){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}o.d(t,"a",(function(){return n}))}}]); \ No newline at end of file +/*! For license information please see 97f5d064.0b3165a6.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[151],{303:function(e,t,o){"use strict";o.r(t),o.d(t,"frontMatter",(function(){return s})),o.d(t,"metadata",(function(){return l})),o.d(t,"rightToc",(function(){return u})),o.d(t,"default",(function(){return b}));var n=o(1),a=o(9),r=(o(0),o(425)),i=o(424),c=(o(429),o(431)),s={last_modified_on:"2022-07-09",$schema:"/.meta/.schemas/guides.json",title:"Zero to Hero - How to deploy your apps on AWS in 30 minutes",description:"Step-by-step guide on how to deploy your apps on AWS in 30 minutes. No AWS knowledge required.",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0},l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Zero to Hero - How to deploy your apps on AWS in 30 minutes",description:"Step-by-step guide on how to deploy your apps on AWS in 30 minutes. No AWS knowledge required.",permalink:"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes",readingTime:"6 min read",source:"@site/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Zero to Hero - How to deploy your apps on AWS in 30 minutes",truncated:!1,prevItem:{title:"Working with Git Submodules",permalink:"/guides/tutorial/working-with-git-submodules"}},u=[{value:"Before you start",id:"before-you-start",children:[{value:"What is Qovery",id:"what-is-qovery",children:[]},{value:"Why you should use AWS",id:"why-you-should-use-aws",children:[]},{value:"Why you should not use AWS",id:"why-you-should-not-use-aws",children:[]}]},{value:"Create an AWS account",id:"create-an-aws-account",children:[{value:"Get your AWS API keys",id:"get-your-aws-api-keys",children:[]}]},{value:"Configure Qovery",id:"configure-qovery",children:[{value:"Sign-up to Qovery",id:"sign-up-to-qovery",children:[]},{value:"Create your Organization",id:"create-your-organization",children:[]},{value:"Install Qovery on your AWS account",id:"install-qovery-on-your-aws-account",children:[]}]},{value:"Deploy your application",id:"deploy-your-application",children:[]}],p={rightToc:u};function b(e){var t=e.components,o=Object(a.a)(e,["components"]);return Object(r.b)("wrapper",Object(n.a)({},p,o,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aws.amazon.com?ref=qovery"}),"Amazon Web Services")," (AWS) is a platform that offers flexible, reliable, and scalable Cloud computing solutions. The platform is developed with a combination of infrastructure as a service (IaaS), platform as a service (PaaS), and packaged software as a service (SaaS) offerings. In 2021, thousands of companies host their apps on AWS. In 2006, AWS was composed of only 3 services (SQS, S3, EC2) that were simple to use. In 2021, more than 200 services and 2000 features exist, and deploying your app can take days."),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.qovery.com"}),"Qovery")," is the simplest way to deploy your apps on AWS.")),Object(r.b)("p",null,"In this tutorial, I will explain step by step how to deploy your app on AWS in 30 minutes. No AWS/infrastructure/Cloud knowledge required - no kidding!"),Object(r.b)("h2",{id:"before-you-start"},"Before you start"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"This tutorial is perfect for anyone interested into deploying their apps on AWS seamlessly."),Object(r.b)("li",{parentName:"ol"},"If you have any question or suggestion on this tutorial, please contact us via ",Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.qovery.com/contact"}),"this form")," or ",Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://discord.qovery.com"}),"Discord"),".")),Object(r.b)("h3",{id:"what-is-qovery"},"What is Qovery"),Object(r.b)("p",null,'Qovery is a platform that makes your app deployment on AWS very simple. The installation of Qovery on your AWS account takes approximately 30 minutes. Then you\'re ready to deploy your apps "\xe0 la" Heroku-like.'),Object(r.b)("h3",{id:"why-you-should-use-aws"},"Why you should use AWS"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You need a reliable hosting platform."),Object(r.b)("li",{parentName:"ul"},"You want to stay focus on what you are building."),Object(r.b)("li",{parentName:"ul"},"You need to speed up your Go-To-Market and Product Market Fit."),Object(r.b)("li",{parentName:"ul"},"You plan to be the next unicorn \ud83e\udd84")),Object(r.b)("h3",{id:"why-you-should-not-use-aws"},"Why you should not use AWS"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You are building a hobby project."),Object(r.b)("li",{parentName:"ul"},"You are looking for a cheap hosting provider."),Object(r.b)("li",{parentName:"ul"},"You do not want to use Amazon services.")),Object(r.b)("p",null,"Let's start!"),Object(r.b)("h1",{id:"video-install-qovery-on-aws"},"Video: Install Qovery on AWS"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Follow ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"this guide")," to create your AWS credentials")),Object(r.b)("div",{class:"video-container"},Object(r.b)("p",{align:"center"},Object(r.b)("iframe",{src:"https://www.loom.com/embed/3450aa0c4122467892cd7c6e1fc85f6e",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(r.b)("h1",{id:"step-by-step-install-qovery-on-aws"},"Step-by-step: Install Qovery on AWS"),Object(r.b)("h2",{id:"create-an-aws-account"},"Create an AWS account"),Object(r.b)("p",null,Object(r.b)("em",{parentName:"p"},"If you already have an AWS account, you can go to the next point.")),Object(r.b)("p",null,"Before creating an AWS account, I'd recommend contacting AWS to see if you are eligible to free credits. AWS provides up to $100k of credits for 12 to 24 months. Which is convenient to have at the beginning of a project. If you know that you are not eligible, you can create your account by clicking on the top right button ",Object(r.b)("inlineCode",{parentName:"p"},"Create an AWS Account")," of their ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aws.amazon.com?ref=qovery"}),"main page"),"."),Object(r.b)("img",{src:"/img/aws-create-an-account.jpg",alt:"Create an account on AWS"}),Object(r.b)("h3",{id:"get-your-aws-api-keys"},"Get your AWS API keys"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Follow ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"this guide")," to create your AWS credentials")),Object(r.b)("p",null,"To install Qovery on your AWS account, the ",Object(r.b)("inlineCode",{parentName:"p"},"secret access key")," and ",Object(r.b)("inlineCode",{parentName:"p"},"access key id")," are required. Here is a comprehensive ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"step-by-step guide")," on how to generate your ",Object(r.b)("inlineCode",{parentName:"p"},"secret access key")," and ",Object(r.b)("inlineCode",{parentName:"p"},"access key id"),". If you already have those keys, then you can go to the next point."),Object(r.b)("h2",{id:"configure-qovery"},"Configure Qovery"),Object(r.b)("h3",{id:"sign-up-to-qovery"},"Sign-up to Qovery"),Object(r.b)("p",null,"Using Qovery is as simple as connect with your ",Object(r.b)("em",{parentName:"p"},"Github"),", ",Object(r.b)("em",{parentName:"p"},"Gitlab")," or ",Object(r.b)("em",{parentName:"p"},"Bitbucket")," account on ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"start.qovery.com"),"."),Object(r.b)("p",null,"-> ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Connect to Qovery")),Object(r.b)("h3",{id:"create-your-organization"},"Create your Organization"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can skip this step if you already have an Organization.")),Object(r.b)("p",null,"An organization is a shared account where developers can collaborate across many projects at once. Owners and organization administrators can manage:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Cloud accounts."),Object(r.b)("li",{parentName:"ul"},"Members access."),Object(r.b)("li",{parentName:"ul"},"Billing.")),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/"}),"Read more")," about Organizations"),Object(r.b)("p",null,"To deploy on your AWS account, you have to choose between ",Object(r.b)("strong",{parentName:"p"},"Free"),", ",Object(r.b)("strong",{parentName:"p"},"Professional")," and ",Object(r.b)("strong",{parentName:"p"},"Business")," plan for your organization."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/organization/Qovery_Pricing_Plans.png",alt:"Qovery - Create an Organization and select the plan"})),Object(r.b)("h3",{id:"install-qovery-on-your-aws-account"},"Install Qovery on your AWS account"),Object(r.b)("p",null,'1/ Go to your organization settings by clicking on the "cog" icon next to your organization name.'),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_clusters_empty.jpg",alt:"Go your organization settings > clusters"})),Object(r.b)("p",null,"2/ Create a cluster, select ",Object(r.b)("em",{parentName:"p"},"Amazon Web Services")," and the region where you want to deploy your apps."),Object(r.b)(i.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Choose a region close to where your users will use your applications to have better performances.")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_create_cluster.jpg",alt:"Create a cluster"})),Object(r.b)("p",null,"3/ Set your AWS credentials. (Check out ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/"}),"this guide")," if you have no AWS credentials)."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_add_credentials.jpg",alt:"Set your cloud credentials"})),Object(r.b)("p",null,"4/ Under the hood, Qovery uses a managed Kubernetes (",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aws.amazon.com/eks"}),"AWS EKS"),") to run your applications. You need to specify the instance type that you would like to use and the min/max number of nodes. Qovery will keep low the number of nodes and will only scale up your nodes if your applications really need to scale.\nIf you don't know which instance type to chose, have a look at the AWS instance list or use the helper to chose the right instance based on your CPU/RAM needs."),Object(r.b)(i.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Qovery optimizes and keep your AWS costs low.")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_cluster_resources.jpg",alt:"Set your cluster resources"})),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},"Qovery might use some temporary free resources on your Kubernetes cluster to perform spotted maintenance operations (e.g. : cluster version upgrades). This is why we recommend a cluster setup with:",Object(r.b)("ul",null,Object(r.b)("li",null,"at least 20% difference between the minimum and the maximum number of nodes;"),Object(r.b)("li",null,"at least 5 nodes as the maximum number of nodes of your cluster;"))),Object(r.b)("p",null,"5/ Click on ",Object(r.b)("strong",{parentName:"p"},"Save")," and ",Object(r.b)("strong",{parentName:"p"},"Deploy"),"."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/organization_settings_clusters_aws.jpg",alt:"AWS cluster is now available"})),Object(r.b)("p",null,"Congrats! Qovery will be installed within 30 minutes \ud83c\udf89. You will be notified when it is all good.\nIn the meantime, you can take a look at our ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"guide section"),"."),Object(r.b)("p",null,"6/ Enable cluster sync with SSO account"),Object(r.b)("p",null,"If you're using SSO for your AWS account deploying the Qovery cluster you have to add some infos in the ",Object(r.b)("em",{parentName:"p"},"aws-auth configmap")," in ",Object(r.b)("inlineCode",{parentName:"p"},"kube-system")," namespace.\nConnect to your cluster and edit the ",Object(r.b)("em",{parentName:"p"},"aws-auth configmap")," in order to add the following code in the mapRoles section:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-yaml"}),'- rolearn: arn:aws:iam:::role/AWSReservedSSO_AdministratorAccess_\n username: "{{SessionName}}"\n groups:\n - system:masters\n')),Object(r.b)("h2",{id:"deploy-your-application"},"Deploy your application"),Object(r.b)("p",null,"Once Qovery is installed on your AWS account, you have the possibility to deploy your application. Take a look to ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"our guide")," on how to ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"deploy your first application")," with Qovery."),Object(r.b)(c.a,{to:"/guides/getting-started/deploy-your-first-application",mdxType:"Jump"},"Deploy your first application"))}b.isMDXComponent=!0},423:function(e,t,o){var n;!function(){"use strict";var o={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[o]=e[o]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(a[o]=e[o])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),o=t;return e&&(o="function"==typeof e?e(t):c({},t,{},e)),o},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var o=e.components,n=e.mdxType,r=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(o),d=n,y=p["".concat(i,".").concat(d)]||p[d]||b[d]||r;return o?a.a.createElement(y,c({ref:t},l,{components:o})):a.a.createElement(y,c({ref:t},l))}));function y(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=o.length,i=new Array(r);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l1?arguments[1]:void 0,o),s=i>2?arguments[2]:void 0,l=void 0===s?o:a(s,o);l>c;)t[c++]=e;return t}},428:function(e,t,o){var n=o(28).f,a=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in a||o(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,o){"use strict";o(428);var n=o(0),a=o.n(n),r=o(424);t.a=function(e){var t=e.children,o=e.name;return a.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",o||"page"," assumes the following:"),t)}},430:function(e,t,o){"use strict";var n=o(1),a=o(0),r=o.n(a),i=o(39),c=o(432),s=o(20),l=o.n(s);t.a=function(e){var t,o=e.to,s=e.href,u=o||s,p=Object(c.a)(u),b=Object(a.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?r.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var o,n;d&&e&&p&&(o=e,n=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){o===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(o),t.disconnect(),n())}))}))).observe(o))},to:u})):r.a.createElement("a",Object(n.a)({},e,{href:u}))}},431:function(e,t,o){"use strict";var n=o(0),a=o.n(n),r=o(430),i=o(423),c=o.n(i);o(133);t.a=function(e){var t=e.children,o=e.className,n=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+l,o),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},n?a.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?a.a.createElement("a",{href:p,target:u,className:b},d):a.a.createElement(r.a,{to:p,className:b},d)}},432:function(e,t,o){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}o.d(t,"a",(function(){return n}))}}]); \ No newline at end of file diff --git a/9c8ed74f.bd2c4f08.js.LICENSE.txt b/97f5d064.0b3165a6.js.LICENSE.txt similarity index 100% rename from 9c8ed74f.bd2c4f08.js.LICENSE.txt rename to 97f5d064.0b3165a6.js.LICENSE.txt diff --git a/998e75d2.e1505f50.js b/998e75d2.0b9aa648.js similarity index 68% rename from 998e75d2.e1505f50.js rename to 998e75d2.0b9aa648.js index ae4c934114..1183abdcfc 100644 --- a/998e75d2.e1505f50.js +++ b/998e75d2.0b9aa648.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[149],{301:function(e){e.exports=JSON.parse('{"category":{"name":"provider","title":"Provider","description":null,"permalink":"/guides/provider"}}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[152],{304:function(e){e.exports=JSON.parse('{"category":{"name":"provider","title":"Provider","description":null,"permalink":"/guides/provider"}}')}}]); \ No newline at end of file diff --git a/9ab61bc5.d5def6ed.js b/9ab61bc5.21045276.js similarity index 88% rename from 9ab61bc5.d5def6ed.js rename to 9ab61bc5.21045276.js index 2a6353f34e..1a6381cfec 100644 --- a/9ab61bc5.d5def6ed.js +++ b/9ab61bc5.21045276.js @@ -1,2 +1,2 @@ -/*! For license information please see 9ab61bc5.d5def6ed.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[150],{302:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return u})),t.d(r,"metadata",(function(){return l})),t.d(r,"rightToc",(function(){return s})),t.d(r,"default",(function(){return f}));var o=t(1),n=t(9),a=(t(0),t(422)),c=t(421),i=t(429),u={last_modified_on:"2023-11-25",title:"Google Cloud Platform (GCP)",description:"Learn how to configure and plug your Google Cloud Platform (GCP) account"},l={id:"using-qovery/configuration/cloud-service-provider/google-cloud-platform",title:"Google Cloud Platform (GCP)",description:"Learn how to configure and plug your Google Cloud Platform (GCP) account",source:"@site/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform.md",permalink:"/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform",sidebar:"docs",previous:{title:"Amazon Web Services (AWS)",permalink:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services"},next:{title:"Microsoft Azure",permalink:"/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure"}},s=[{value:"Managed Kubernetes by Qovery",id:"managed-kubernetes-by-qovery",children:[]},{value:"Available Cloud Service Providers",id:"available-cloud-service-providers",children:[]}],p={rightToc:s};function f(e){var r=e.components,t=Object(n.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},p,t,{components:r,mdxType:"MDXLayout"}),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Please refer to ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/provider/kubernetes/"}),"this page")," if you want to install Qovery on your own Kubernetes cluster (BYOK).")),Object(a.b)("h2",{id:"managed-kubernetes-by-qovery"},"Managed Kubernetes by Qovery"),Object(a.b)("p",null,Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://www.qovery.com/blog/early-access-for-google-cloud-platform/"}),"We currently work on supporting Google Cloud Platform (GCP)")," as a managed Kubernetes provider. Stay tuned!"),Object(a.b)("p",null,"Google Cloud Platform is coming soon (",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://roadmap.qovery.com/roadmap/support-google-cloud-platform-gcp"}),"see when"),"). Vote ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://roadmap.qovery.com/roadmap/support-google-cloud-platform-gcp"}),"here")," to make it happen faster."),Object(a.b)("h2",{id:"available-cloud-service-providers"},"Available Cloud Service Providers"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services",mdxType:"Jump"},"Amazon Web Services (AWS)"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform",mdxType:"Jump"},"Google Cloud Platform (GCP)"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure",mdxType:"Jump"},"Azure"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/scaleway",mdxType:"Jump"},"Scaleway"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/other-csps",mdxType:"Jump"},"Others"))}f.isMDXComponent=!0},420:function(e,r,t){var o;!function(){"use strict";var t={}.hasOwnProperty;function n(){for(var e=[],r=0;r=0||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(n[t]=e[t])}return n}var l=n.a.createContext({}),s=function(e){var r=n.a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):i({},r,{},e)),t},p=function(e){var r=s(e.components);return n.a.createElement(l.Provider,{value:r},e.children)},f={inlineCode:"code",wrapper:function(e){var r=e.children;return n.a.createElement(n.a.Fragment,{},r)}},d=Object(o.forwardRef)((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),p=s(t),d=o,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||a;return t?n.a.createElement(m,i({ref:r},l,{components:t})):n.a.createElement(m,i({ref:r},l))}));function m(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,c=new Array(a);c[0]=d;var i={};for(var u in r)hasOwnProperty.call(r,u)&&(i[u]=r[u]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var l=2;l1?arguments[1]:void 0,t),u=c>2?arguments[2]:void 0,l=void 0===u?t:n(u,t);l>i;)r[i++]=e;return r}},427:function(e,r,t){"use strict";var o=t(1),n=t(0),a=t.n(n),c=t(39),i=t(430),u=t(20),l=t.n(u);r.a=function(e){var r,t=e.to,u=e.href,s=t||u,p=Object(i.a)(s),f=Object(n.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(n.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(s),function(){d&&r&&r.disconnect()}}),[s,d,p]),s&&p?a.a.createElement(c.b,Object(o.a)({},e,{onMouseEnter:function(){f.current||(window.docusaurus.preload(s),f.current=!0)},innerRef:function(e){var t,o;d&&e&&p&&(t=e,o=function(){window.docusaurus.prefetch(s)},(r=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(r.unobserve(t),r.disconnect(),o())}))}))).observe(t))},to:s})):a.a.createElement("a",Object(o.a)({},e,{href:s}))}},429:function(e,r,t){"use strict";var o=t(0),n=t.n(o),a=t(427),c=t(420),i=t.n(c);t(133);r.a=function(e){var r=e.children,t=e.className,o=e.badge,c=e.leftIcon,u=e.rightIcon,l=e.size,s=e.target,p=e.to,f=i()("jump-to","jump-to--"+l,t),d=n.a.createElement("div",{className:"jump-to--inner"},n.a.createElement("div",{className:"jump-to--inner-2"},c&&n.a.createElement("div",{className:"jump-to--left"},n.a.createElement("i",{className:"feather icon-"+c})),n.a.createElement("div",{className:"jump-to--main"},o?n.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",r),n.a.createElement("div",{className:"jump-to--right"},n.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return s?n.a.createElement("a",{href:p,target:s,className:f},d):n.a.createElement(a.a,{to:p,className:f},d)}},430:function(e,r,t){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(r,"a",(function(){return o}))}}]); \ No newline at end of file +/*! For license information please see 9ab61bc5.21045276.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[153],{305:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return u})),t.d(r,"metadata",(function(){return l})),t.d(r,"rightToc",(function(){return s})),t.d(r,"default",(function(){return f}));var o=t(1),n=t(9),a=(t(0),t(425)),c=t(424),i=t(431),u={last_modified_on:"2023-11-25",title:"Google Cloud Platform (GCP)",description:"Learn how to configure and plug your Google Cloud Platform (GCP) account"},l={id:"using-qovery/configuration/cloud-service-provider/google-cloud-platform",title:"Google Cloud Platform (GCP)",description:"Learn how to configure and plug your Google Cloud Platform (GCP) account",source:"@site/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform.md",permalink:"/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform",sidebar:"docs",previous:{title:"Amazon Web Services (AWS)",permalink:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services"},next:{title:"Microsoft Azure",permalink:"/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure"}},s=[{value:"Managed Kubernetes by Qovery",id:"managed-kubernetes-by-qovery",children:[]},{value:"Available Cloud Service Providers",id:"available-cloud-service-providers",children:[]}],p={rightToc:s};function f(e){var r=e.components,t=Object(n.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},p,t,{components:r,mdxType:"MDXLayout"}),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Please refer to ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/provider/kubernetes/"}),"this page")," if you want to install Qovery on your own Kubernetes cluster (BYOK).")),Object(a.b)("h2",{id:"managed-kubernetes-by-qovery"},"Managed Kubernetes by Qovery"),Object(a.b)("p",null,Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://www.qovery.com/blog/early-access-for-google-cloud-platform/"}),"We currently work on supporting Google Cloud Platform (GCP)")," as a managed Kubernetes provider. Stay tuned!"),Object(a.b)("p",null,"Google Cloud Platform is coming soon (",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://roadmap.qovery.com/roadmap/support-google-cloud-platform-gcp"}),"see when"),"). Vote ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://roadmap.qovery.com/roadmap/support-google-cloud-platform-gcp"}),"here")," to make it happen faster."),Object(a.b)("h2",{id:"available-cloud-service-providers"},"Available Cloud Service Providers"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services",mdxType:"Jump"},"Amazon Web Services (AWS)"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform",mdxType:"Jump"},"Google Cloud Platform (GCP)"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure",mdxType:"Jump"},"Azure"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/scaleway",mdxType:"Jump"},"Scaleway"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/other-csps",mdxType:"Jump"},"Others"))}f.isMDXComponent=!0},423:function(e,r,t){var o;!function(){"use strict";var t={}.hasOwnProperty;function n(){for(var e=[],r=0;r=0||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(n[t]=e[t])}return n}var l=n.a.createContext({}),s=function(e){var r=n.a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):i({},r,{},e)),t},p=function(e){var r=s(e.components);return n.a.createElement(l.Provider,{value:r},e.children)},f={inlineCode:"code",wrapper:function(e){var r=e.children;return n.a.createElement(n.a.Fragment,{},r)}},d=Object(o.forwardRef)((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),p=s(t),d=o,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||a;return t?n.a.createElement(m,i({ref:r},l,{components:t})):n.a.createElement(m,i({ref:r},l))}));function m(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,c=new Array(a);c[0]=d;var i={};for(var u in r)hasOwnProperty.call(r,u)&&(i[u]=r[u]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var l=2;l1?arguments[1]:void 0,t),u=c>2?arguments[2]:void 0,l=void 0===u?t:n(u,t);l>i;)r[i++]=e;return r}},430:function(e,r,t){"use strict";var o=t(1),n=t(0),a=t.n(n),c=t(39),i=t(432),u=t(20),l=t.n(u);r.a=function(e){var r,t=e.to,u=e.href,s=t||u,p=Object(i.a)(s),f=Object(n.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(n.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(s),function(){d&&r&&r.disconnect()}}),[s,d,p]),s&&p?a.a.createElement(c.b,Object(o.a)({},e,{onMouseEnter:function(){f.current||(window.docusaurus.preload(s),f.current=!0)},innerRef:function(e){var t,o;d&&e&&p&&(t=e,o=function(){window.docusaurus.prefetch(s)},(r=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(r.unobserve(t),r.disconnect(),o())}))}))).observe(t))},to:s})):a.a.createElement("a",Object(o.a)({},e,{href:s}))}},431:function(e,r,t){"use strict";var o=t(0),n=t.n(o),a=t(430),c=t(423),i=t.n(c);t(133);r.a=function(e){var r=e.children,t=e.className,o=e.badge,c=e.leftIcon,u=e.rightIcon,l=e.size,s=e.target,p=e.to,f=i()("jump-to","jump-to--"+l,t),d=n.a.createElement("div",{className:"jump-to--inner"},n.a.createElement("div",{className:"jump-to--inner-2"},c&&n.a.createElement("div",{className:"jump-to--left"},n.a.createElement("i",{className:"feather icon-"+c})),n.a.createElement("div",{className:"jump-to--main"},o?n.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",r),n.a.createElement("div",{className:"jump-to--right"},n.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return s?n.a.createElement("a",{href:p,target:s,className:f},d):n.a.createElement(a.a,{to:p,className:f},d)}},432:function(e,r,t){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(r,"a",(function(){return o}))}}]); \ No newline at end of file diff --git a/9d3c5a68.dffa276e.js.LICENSE.txt b/9ab61bc5.21045276.js.LICENSE.txt similarity index 100% rename from 9d3c5a68.dffa276e.js.LICENSE.txt rename to 9ab61bc5.21045276.js.LICENSE.txt diff --git a/9c8ed74f.bd2c4f08.js b/9c8ed74f.378e65f2.js similarity index 89% rename from 9c8ed74f.bd2c4f08.js rename to 9c8ed74f.378e65f2.js index 0850f90ac4..7274652e46 100644 --- a/9c8ed74f.bd2c4f08.js +++ b/9c8ed74f.378e65f2.js @@ -1,2 +1,2 @@ -/*! For license information please see 9c8ed74f.bd2c4f08.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[151],{303:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return c})),r.d(t,"metadata",(function(){return u})),r.d(t,"rightToc",(function(){return l})),r.d(t,"default",(function(){return f}));var n=r(1),a=r(9),o=(r(0),r(422)),i=(r(431),r(426),r(421)),c={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Terraform",description:"Learn how to use Terraform with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: terraform"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Terraform",description:"Learn how to use Terraform with Qovery",permalink:"/guides/advanced/terraform",readingTime:"1 min read",source:"@site/guides/advanced/terraform.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: terraform",permalink:"/guides/tags/technology-terraform"}],title:"Terraform",truncated:!1,prevItem:{title:"Setup VPC peering on AWS with Qovery",permalink:"/guides/tutorial/aws-vpc-peering-with-qovery"},nextItem:{title:"URL Shortener API with Kotlin (Part 1/2)",permalink:"/guides/tutorial/url-shortener-api-with-kotlin"}},l=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:l};function f(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"this guide")," to learn more about Terraform with Qovery.")),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some additional resources you can use to learn more about Terraform integration with Qovery:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"Deploy AWS RDS instance with Terraform")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"Learn how to deploy an AWS RDS instance with Terraform and Lifecycle Job")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=terraform"}),'Forum "Terraform"')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=terraform"}),'List "Terraform" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}f.isMDXComponent=!0},420:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=a.a.createContext({}),s=function(e){var t=a.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},f=function(e){var t=s(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),f=s(r),m=n,b=f["".concat(i,".").concat(m)]||f[m]||p[m]||o;return r?a.a.createElement(b,c({ref:t},l,{components:r})):a.a.createElement(b,c({ref:t},l))}));function b(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l1?arguments[1]:void 0,r),u=i>2?arguments[2]:void 0,l=void 0===u?r:a(u,r);l>c;)t[c++]=e;return t}},425:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,r){"use strict";r(425);var n=r(0),a=r.n(n),o=r(421);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},428:function(e,t,r){"use strict";var n=r(432),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(r(n,e,i.length))})),i.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(420),r(428)),i=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),s=Object(n.useState)(null),f=s[0],p=s[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!f&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 9c8ed74f.378e65f2.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[154],{306:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return c})),r.d(t,"metadata",(function(){return u})),r.d(t,"rightToc",(function(){return l})),r.d(t,"default",(function(){return f}));var n=r(1),a=r(9),o=(r(0),r(425)),i=(r(434),r(429),r(424)),c={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Terraform",description:"Learn how to use Terraform with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: terraform"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Terraform",description:"Learn how to use Terraform with Qovery",permalink:"/guides/advanced/terraform",readingTime:"1 min read",source:"@site/guides/advanced/terraform.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: terraform",permalink:"/guides/tags/technology-terraform"}],title:"Terraform",truncated:!1,prevItem:{title:"Setup VPC peering on AWS with Qovery",permalink:"/guides/tutorial/aws-vpc-peering-with-qovery"},nextItem:{title:"URL Shortener API with Kotlin (Part 1/2)",permalink:"/guides/tutorial/url-shortener-api-with-kotlin"}},l=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:l};function f(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"this guide")," to learn more about Terraform with Qovery.")),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some additional resources you can use to learn more about Terraform integration with Qovery:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"Deploy AWS RDS instance with Terraform")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"Learn how to deploy an AWS RDS instance with Terraform and Lifecycle Job")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=terraform"}),'Forum "Terraform"')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=terraform"}),'List "Terraform" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}f.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=a.a.createContext({}),s=function(e){var t=a.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},f=function(e){var t=s(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),f=s(r),m=n,b=f["".concat(i,".").concat(m)]||f[m]||p[m]||o;return r?a.a.createElement(b,c({ref:t},l,{components:r})):a.a.createElement(b,c({ref:t},l))}));function b(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l1?arguments[1]:void 0,r),u=i>2?arguments[2]:void 0,l=void 0===u?r:a(u,r);l>c;)t[c++]=e;return t}},428:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,r){"use strict";r(428);var n=r(0),a=r.n(n),o=r(424);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},433:function(e,t,r){"use strict";var n=r(435),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(r(n,e,i.length))})),i.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(423),r(433)),i=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),s=Object(n.useState)(null),f=s[0],p=s[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!f&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/9ddfc3dc.102444c4.js.LICENSE.txt b/9c8ed74f.378e65f2.js.LICENSE.txt similarity index 100% rename from 9ddfc3dc.102444c4.js.LICENSE.txt rename to 9c8ed74f.378e65f2.js.LICENSE.txt diff --git a/9d3c5a68.dffa276e.js b/9d3c5a68.0e456d14.js similarity index 96% rename from 9d3c5a68.dffa276e.js rename to 9d3c5a68.0e456d14.js index 0e92c62a78..a42423f184 100644 --- a/9d3c5a68.dffa276e.js +++ b/9d3c5a68.0e456d14.js @@ -1,2 +1,2 @@ -/*! For license information please see 9d3c5a68.dffa276e.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[152],{304:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),o=(n(0),n(422)),c=n(431),i={last_modified_on:"2021-07-02",title:"Object Storage",description:"Learn how to configure object storage with your applications"},s={id:"using-qovery/configuration/object-storage",title:"Object Storage",description:"Learn how to configure object storage with your applications",source:"@site/docs/using-qovery/configuration/object-storage.md",permalink:"/docs/using-qovery/configuration/object-storage",sidebar:"docs",previous:{title:"Service Advanced Settings",permalink:"/docs/using-qovery/configuration/advanced-settings"},next:{title:"Deployment Rule",permalink:"/docs/using-qovery/configuration/deployment-rule"}},l=[{value:"Use cases",id:"use-cases",children:[{value:"\u2705 Good use cases",id:"-good-use-cases",children:[]},{value:"\u274c Bad use cases",id:"-bad-use-cases",children:[]}]},{value:"Pros & Cons",id:"pros--cons",children:[{value:"Pros",id:"pros",children:[]},{value:"Cons",id:"cons",children:[]}]},{value:"Using Object Storage",id:"using-object-storage",children:[{value:"AWS",id:"aws",children:[]},{value:"Digital Ocean",id:"digital-ocean",children:[]},{value:"Scaleway",id:"scaleway",children:[]}]}],u={rightToc:l};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"The default filesystem for applications running on Qovery is ephemeral. Application data isn\u2019t persisted across deploys and restarts, which works just fine for most apps because they use managed databases to persist data.\nIf, however, your application needs persistent storage across restarts or needs to store large amounts of data that doesn't really fit well to be stored in databases, Object Storage might fit your needs."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Examples of applications"),":"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Music streaming services like Spotify"),Object(o.b)("li",{parentName:"ul"},"Photo-heavy apps like Instagram, Facebook"),Object(o.b)("li",{parentName:"ul"},"Storing backups/archives over long periods")),Object(o.b)("h2",{id:"use-cases"},"Use cases"),Object(o.b)("h3",{id:"-good-use-cases"},"\u2705 Good use cases"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Storing large amounts of read-only data"),Object(o.b)("li",{parentName:"ul"},"High availability"),Object(o.b)("li",{parentName:"ul"},"High scalability"),Object(o.b)("li",{parentName:"ul"},"Unstructured data like music, photos, videos"),Object(o.b)("li",{parentName:"ul"},"Geographical distribution of data")),Object(o.b)("h3",{id:"-bad-use-cases"},"\u274c Bad use cases"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"For I/O intensive applications (e.g. databases)"),Object(o.b)("li",{parentName:"ul"},"Frequent data updates"),Object(o.b)("li",{parentName:"ul"},"Temporary files"),Object(o.b)("li",{parentName:"ul"},"Transactional data")),Object(o.b)("h2",{id:"pros--cons"},"Pros & Cons"),Object(o.b)("h3",{id:"pros"},"Pros"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Reduce infrastructure costs of storing data"),Object(o.b)("li",{parentName:"ul"},"Reduce management time because of the easiness of scalability")),Object(o.b)("h3",{id:"cons"},"Cons"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Not suited for frequently changing data"),Object(o.b)("li",{parentName:"ul"},"Eventual consistency of data might be not enough for certain types of applications that require strong consistency")),Object(o.b)("h2",{id:"using-object-storage"},"Using Object Storage"),Object(o.b)("p",null,"Using Object Storage with Qovery is very simple. All you need to do is to set up a ",Object(o.b)("strong",{parentName:"p"},"bucket")," in the cloud provider of your choice\nand configure your application to use it using secrets or environment variables."),Object(o.b)("h3",{id:"aws"},"AWS"),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Navigate to ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://s3.console.aws.amazon.com/s3/home"}),"AWS S3 Console"))),Object(o.b)("li",null,Object(o.b)("p",null,"Click ",Object(o.b)("strong",{parentName:"p"},"Create bucket")," button"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/objectstorage/aws-1.png",alt:"Storage"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Set up your bucket settings, like name, permissions, cloud region")),Object(o.b)("li",null,Object(o.b)("p",null,"Connect your application to your bucket (example using Node.js)"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-javascript"}),"// Load dependencies\nconst aws = require('aws-sdk');\nconst express = require('express');\nconst multer = require('multer');\nconst multerS3 = require('multer-s3');\n\nconst app = express();\n\n// Set S3 endpoint to AWS S3 in correct region\nconst endpoint = new aws.Endpoint('s3.us-east-2.amazonaws.com');\nconst s3 = new aws.S3({\n endpoint: endpoint\n});\n\n// Change bucket property to your Bucket name\nconst upload = multer({\n storage: multerS3({\n s3: s3,\n bucket: 'your-bucket-here',\n acl: 'public-read',\n key: function (request, file, cb) {\n console.log(file);\n cb(null, file.originalname);\n }\n })\n}).array('upload', 1);\n")),Object(o.b)("p",null,"If your bucket access is secured, all you need to do is to set up those environment variables in your application:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"AWS_ACCESS_KEY_ID"),Object(o.b)("li",{parentName:"ul"},"AWS_SECRET_ACCESS_KEY")),Object(o.b)("p",null,"You can set up secrets in your application by ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/getting-started/managing-environment-variables/"}),"following our guide"),".")))),Object(o.b)("h3",{id:"digital-ocean"},"Digital Ocean"),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Navigate to ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://cloud.digitalocean.com/projects"}),"DO Console"))),Object(o.b)("li",null,Object(o.b)("p",null,"Click ",Object(o.b)("strong",{parentName:"p"},"Create"),", and ",Object(o.b)("strong",{parentName:"p"},"Spaces")," button"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/objectstorage/do-1.png",alt:"Storage"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Set up your bucket settings, like name, permissions, cloud region")),Object(o.b)("li",null,Object(o.b)("p",null,"Connect your application to your bucket (DO Spaces are AWS S3 compatible, this is why we use S3 client in the example):"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-javascript"}),"// Load dependencies\nconst aws = require('aws-sdk');\nconst express = require('express');\nconst multer = require('multer');\nconst multerS3 = require('multer-s3');\n\nconst app = express();\n\n// Set S3 endpoint to DigitalOcean Spaces in correct region\nconst endpoint = new aws.Endpoint('nyc3.digitaloceanspaces.com');\nconst s3 = new aws.S3({\n endpoint: endpoint\n});\n\n// Change bucket property to your Space name\nconst upload = multer({\n storage: multerS3({\n s3: s3,\n bucket: 'your-space-here',\n acl: 'public-read',\n key: function (request, file, cb) {\n console.log(file);\n cb(null, file.originalname);\n }\n })\n}).array('upload', 1);\n")),Object(o.b)("p",null,"If your bucket is private, all you need to do is to set up those environment variables for your application:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"AWS_ACCESS_KEY_ID"),Object(o.b)("li",{parentName:"ul"},"AWS_SECRET_ACCESS_KEY")),Object(o.b)("p",null,"You can find your secrets in your Space configuration. You can set up secrets in your application by ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/getting-started/managing-environment-variables/"}),"following our guide"),".")))),Object(o.b)("h3",{id:"scaleway"},"Scaleway"),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Navigate to ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://console.scaleway.com/object-storage/buckets"}),"Scaleway Console"))),Object(o.b)("li",null,Object(o.b)("p",null,"Click ",Object(o.b)("strong",{parentName:"p"},"Create"),", and ",Object(o.b)("strong",{parentName:"p"},"Spaces")," button"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/objectstorage/scaleway-1.png",alt:"Storage"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Set up your bucket settings, like name, permissions, cloud region")),Object(o.b)("li",null,Object(o.b)("p",null,"Connect your application to your bucket (Scaleway Buckets are partly AWS S3 compatible, this is why we use S3 client in the example):"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-javascript"}),"// Load dependencies\nconst aws = require('aws-sdk');\nconst express = require('express');\nconst multer = require('multer');\nconst multerS3 = require('multer-s3');\n\nconst app = express();\n\n// Set S3 endpoint to Scaleway Bucket in correct region\nconst endpoint = new aws.Endpoint('https://s3.fr-par.scw.cloud.');\nconst s3 = new aws.S3({\n endpoint: endpoint\n});\n\n// Change bucket property to your Bucket name\nconst upload = multer({\n storage: multerS3({\n s3: s3,\n bucket: 'your-bucket-here',\n acl: 'public-read',\n key: function (request, file, cb) {\n console.log(file);\n cb(null, file.originalname);\n }\n })\n}).array('upload', 1);\n")),Object(o.b)("p",null,"If your bucket is private, all you need to do is to set up those environment variables for your application:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"AWS_ACCESS_KEY_ID"),Object(o.b)("li",{parentName:"ul"},"AWS_SECRET_ACCESS_KEY")),Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.scaleway.com/en/docs/object-storage-with-s3cmd/#-Retrieving-your-Credentials"}),"Scaleway guide")," to get your credentials. You can set up secrets in your application by ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/getting-started/managing-environment-variables/"}),"following our guide"),".")))))}b.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),b=u(n),d=r,m=b["".concat(c,".").concat(d)]||b[d]||p[d]||o;return n?a.a.createElement(m,i({ref:t},l,{components:n})):a.a.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,c=new Array(o);c[0]=d;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),b=u(n),d=r,m=b["".concat(c,".").concat(d)]||b[d]||p[d]||o;return n?a.a.createElement(m,i({ref:t},l,{components:n})):a.a.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,c=new Array(o);c[0]=d;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},d=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=u(n),b=r,f=d["".concat(i,".").concat(b)]||d[b]||p[b]||o;return n?a.a.createElement(f,c({ref:t},s,{components:n})):a.a.createElement(f,c({ref:t},s))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>c;)t[c++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see 9ddfc3dc.0dd0c386.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[156],{308:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return d}));var r=n(1),a=n(9),o=(n(0),n(425)),i=n(424),c={last_modified_on:"2023-04-04",title:"MongoDB",description:"How to set up and use a MongoDB database"},l={id:"using-qovery/configuration/database/mongodb",title:"MongoDB",description:"How to set up and use a MongoDB database",source:"@site/docs/using-qovery/configuration/database/mongodb.md",permalink:"/docs/using-qovery/configuration/database/mongodb",sidebar:"docs",previous:{title:"MySQL",permalink:"/docs/using-qovery/configuration/database/mysql"},next:{title:"Redis",permalink:"/docs/using-qovery/configuration/database/redis"}},s=[{value:"Supported Versions and Cloud Providers",id:"supported-versions-and-cloud-providers",children:[]},{value:"Credentials",id:"credentials",children:[]}],u={rightToc:s};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"MongoDB is a cross-platform document-oriented database program. Classified as a NoSQL, MongoDB uses JSON-like documents with schema."),Object(o.b)("h2",{id:"supported-versions-and-cloud-providers"},"Supported Versions and Cloud Providers"),Object(o.b)("p",null,"You can find the supported versions directly within the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),"."),Object(o.b)("p",null,"Availability of the Container version or Cloud Provider Managed versions depends on the chosen Cloud Provider "),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Cloud provider"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Container supported"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Managed supported"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"AWS"),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Yes"),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Yes")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Scaleway"),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Yes"),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"No")))),Object(o.b)("h2",{id:"credentials"},"Credentials"),Object(o.b)(i.a,{type:"danger",mdxType:"Alert"},Object(o.b)("p",null,"Your Docker image must contain the TLS certificate of the MongoDB cluster - it can be ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem"}),"downloaded here"),"."),Object(o.b)("p",null,"The application must be configured to use it. If you use the environment variables to build the URI to connect tou your database, you usually should have just append ",Object(o.b)("inlineCode",{parentName:"p"},"&ssl_ca_certs=/path/to/the/rds-combined-ca-bundle.pem")," to its value.")),Object(o.b)("p",null,"Have a look at the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/"}),"Database page")," to know more about the database creation and setup."))}d.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},d=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=u(n),b=r,f=d["".concat(i,".").concat(b)]||d[b]||p[b]||o;return n?a.a.createElement(f,c({ref:t},s,{components:n})):a.a.createElement(f,c({ref:t},s))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>c;)t[c++]=e;return t}}}]); \ No newline at end of file diff --git a/9feef5a0.37f831cb.js.LICENSE.txt b/9ddfc3dc.0dd0c386.js.LICENSE.txt similarity index 100% rename from 9feef5a0.37f831cb.js.LICENSE.txt rename to 9ddfc3dc.0dd0c386.js.LICENSE.txt diff --git a/9ecfa6fe.723ec4c4.js b/9ecfa6fe.0b95ed41.js similarity index 87% rename from 9ecfa6fe.723ec4c4.js rename to 9ecfa6fe.0b95ed41.js index 5f15da38fa..fd8addb34f 100644 --- a/9ecfa6fe.723ec4c4.js +++ b/9ecfa6fe.0b95ed41.js @@ -1,2 +1,2 @@ -/*! For license information please see 9ecfa6fe.723ec4c4.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[154],{306:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),a=(n(0),n(422)),i=(n(431),n(426),n(421)),c={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Monitoring",description:"Learn how to monitor your infrastructure and your apps with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Monitoring",description:"Learn how to monitor your infrastructure and your apps with Qovery",permalink:"/guides/advanced/monitoring",readingTime:"1 min read",source:"@site/guides/advanced/monitoring.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Monitoring",truncated:!1,prevItem:{title:"Migration",permalink:"/guides/advanced/migration"},nextItem:{title:"Mono repository",permalink:"/guides/advanced/monorepository"}},s=[{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},"WIP"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Prometheus & Grafana"),Object(a.b)("li",{parentName:"ul"},"Datadog")),Object(a.b)("h2",{id:"qa"},"Q&A"),Object(a.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:o(u,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),p=l[0],f=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return f("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see 9ecfa6fe.0b95ed41.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[157],{309:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),a=(n(0),n(425)),i=(n(434),n(429),n(424)),c={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Monitoring",description:"Learn how to monitor your infrastructure and your apps with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Monitoring",description:"Learn how to monitor your infrastructure and your apps with Qovery",permalink:"/guides/advanced/monitoring",readingTime:"1 min read",source:"@site/guides/advanced/monitoring.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Monitoring",truncated:!1,prevItem:{title:"Migration",permalink:"/guides/advanced/migration"},nextItem:{title:"Mono repository",permalink:"/guides/advanced/monorepository"}},s=[{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},"WIP"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Prometheus & Grafana"),Object(a.b)("li",{parentName:"ul"},"Datadog")),Object(a.b)("h2",{id:"qa"},"Q&A"),Object(a.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:o(u,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),p=l[0],f=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return f("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/a156f6a6.219e64e1.js.LICENSE.txt b/9ecfa6fe.0b95ed41.js.LICENSE.txt similarity index 100% rename from a156f6a6.219e64e1.js.LICENSE.txt rename to 9ecfa6fe.0b95ed41.js.LICENSE.txt diff --git a/9feef5a0.37f831cb.js b/9feef5a0.37f831cb.js deleted file mode 100644 index d9c76a206c..0000000000 --- a/9feef5a0.37f831cb.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see 9feef5a0.37f831cb.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[155],{307:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return b})),a.d(t,"metadata",(function(){return d})),a.d(t,"rightToc",(function(){return u})),a.d(t,"default",(function(){return m}));var n=a(1),r=a(9),o=(a(0),a(422)),i=a(421),c=a(429),l=a(431),s=a(426),b={last_modified_on:"2023-11-03",title:"Databases",description:"Learn how to configure Databases on Qovery",sidebar_label:"hidden",hide_pagination:!0},d={id:"using-qovery/configuration/database",title:"Databases",description:"Learn how to configure Databases on Qovery",source:"@site/docs/using-qovery/configuration/database.md",permalink:"/docs/using-qovery/configuration/database",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Application",permalink:"/docs/using-qovery/configuration/application"},next:{title:"PostgreSQL",permalink:"/docs/using-qovery/configuration/database/postgresql"}},u=[{value:"Container mode",id:"container-mode",children:[]},{value:"Managed mode",id:"managed-mode",children:[{value:"Applying changes to a managed database",id:"applying-changes-to-a-managed-database",children:[]}]},{value:"Create a database",id:"create-a-database",children:[]},{value:"Configuration",id:"configuration",children:[{value:"General",id:"general",children:[]},{value:"Resources",id:"resources",children:[]}]},{value:"Credentials and connectivity",id:"credentials-and-connectivity",children:[]},{value:"Clone",id:"clone",children:[]},{value:"Delete your database instance",id:"delete-your-database-instance",children:[]},{value:"Available Databases",id:"available-databases",children:[]}],p={rightToc:u};function m(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},p,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)(s.a,{name:"documentation",mdxType:"Assumptions"},Object(o.b)("p",null,"You have created an ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment"),".")),Object(o.b)("p",null,"Qovery natively lets you deploy and access the most popular SQL and NoSQL databases available on the major cloud providers. Reliability and resiliency are at the heart of their services, so you don't have to worry about your data on Qovery. "),Object(o.b)("p",null,"Qovery natively supports the following databases:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"PostgreSQL"),Object(o.b)("li",{parentName:"ul"},"MySQL"),Object(o.b)("li",{parentName:"ul"},"MongoDB"),Object(o.b)("li",{parentName:"ul"},"Redis")),Object(o.b)("p",null,'Qovery can natively operate a database in two different ways (called "Mode"):'),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Container mode: preferred for testing and development"),Object(o.b)("li",{parentName:"ul"},"Managed mode: preferred for production, limited configuration parameters (see the ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"#configuration"}),"Configuration")," section).")),Object(o.b)("p",null,"If the natively supported databases or operation modes are not enough for you, depending on your use case you have the following alternative solutions:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Use an existing DB on a dedicated VPC: your applications can access this database via VPC peering. Have a look at ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"this guide")," for more information."),Object(o.b)("li",{parentName:"ul"},"Create your custom database via Qovery: You will be able to deploy any kind of database through Qovery by using a ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"lifecycle jobs"),". For example, you can use a terraform script to deploy your custom RDS instance on AWS via Terraform (have a look at ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-rds-with-terraform"}),"this example"),").")),Object(o.b)("p",null,"The following sections will show you how you can create and manage the databases natively supported by Qovery. For any other use case, please refer to the guides provided above. "),Object(o.b)("h2",{id:"container-mode"},"Container mode"),Object(o.b)("p",null,"The database is created as a container with attached persistent storage directly on your Kubernetes cluster (1 instance). They are perfect for development and testing, as they are significantly cheaper than services provided by cloud providers. "),Object(o.b)("h2",{id:"managed-mode"},"Managed mode"),Object(o.b)("p",null,"Qovery creates and manages the lifecycle of a cloud provider managed database instance (for example an RDS instance on AWS). These are perfect for production since they guarantee the right level of resilience, performance and data security best practices."),Object(o.b)("h3",{id:"applying-changes-to-a-managed-database"},"Applying changes to a managed database"),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},"Since Qovery manages the lifecycle of your database, DO NOT change the database settings directly from within the cloud provider console (to avoid configuration drifts)."),Object(o.b)("p",null,"Once you request to change the version, instance type or disk size of your Managed database, the cloud provider applies the update based on its own internal rules and might cause downtime of your database."),Object(o.b)("p",null,"For example, by default AWS doesn't apply major updates immediately on the database and instead, it waits for a ",Object(o.b)("inlineCode",{parentName:"p"},"maintenance window"),". This means that your change will not be applied immediately but you can always force the change directly from your AWS console AFTER having applied the change on Qovery (to avoid configuration drifts). "),Object(o.b)("p",null,"Have a look at your cloud provider documentation to know more about how version upgrades are managed:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"AWS RDS DB engine upgrade: ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.MySQL.html"}),"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.MySQL.html")),Object(o.b)("li",{parentName:"ul"},"AWS maintenance window: ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Maintenance.html"}),"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Maintenance.html"))),Object(o.b)("h2",{id:"create-a-database"},"Create a database"),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Check out ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"this video guide")," to create and deploy your first database")),Object(o.b)(l.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Navigate to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(o.b)("li",null,Object(o.b)("p",null,"Select your project and environment")),Object(o.b)("li",null,Object(o.b)("p",null,"Click ",Object(o.b)("inlineCode",{parentName:"p"},"Add Database")," button"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/database/db-1.png",alt:"Database"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Select database type, name, description (optional), version, mode and accessibility"),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},"Please refer to the Configuration section below to know more about each of these parameters."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/database/db-2.png",alt:"General Information"}))),Object(o.b)("li",null,Object(o.b)("p",null,'Within the "Resources" step you will find different configurations based on the selected ',Object(o.b)("inlineCode",{parentName:"p"},"mode"),":"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"If you are using the database in ",Object(o.b)("inlineCode",{parentName:"li"},"Container")," mode, you can set the CPU, RAM and storage that will be assigned to the instance running the docker image of the database."),Object(o.b)("li",{parentName:"ul"},"If you are using the database in ",Object(o.b)("inlineCode",{parentName:"li"},"Managed")," mode, you can select the instance type and the storage that will be assigned to the instance running the database. Note, the instance selected instance type has a direct impact on your cloud provider cost.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/database/db-3.png",alt:"Resources"}))),Object(o.b)("li",null,"At the end a recap will allow you to just create the database or create and deploy it",Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/database/db-4.png",alt:"Recap"}))))),Object(o.b)("h2",{id:"configuration"},"Configuration"),Object(o.b)("p",null,"Once created, you can access the configuration of a database at any time via the Settings tab available on the database page"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/database/settings.png",alt:"Database Settings"})),Object(o.b)("p",null,"You can find below the description of each of the tabs available in this section"),Object(o.b)("h3",{id:"general"},"General"),Object(o.b)("h4",{id:"modes"},"Modes"),Object(o.b)("p",null,"As described at the beginning of this document, databases can operate in two modes:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Managed"),Object(o.b)("li",{parentName:"ul"},"Container")),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Managed")," databases are perfect for production - they are provided and managed by major cloud providers like AWS to make sure your production data is well managed."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Container")," databases are managed by Qovery as Docker containers with attached persistent storage directly on your Kubernetes cluster (1 instance). They are perfect for development and testing, as they are significantly cheaper than services provided by cloud providers."),Object(o.b)("p",null,"Please refer to the dedicated database sub-pages to get more information on the supported mode for each cloud provider."),Object(o.b)("h4",{id:"versions"},"Versions"),Object(o.b)("p",null,"We regularly update the version available for each database. Please refer to the dedicated database sub-pages to get more information on the supported version for each database types and cloud provider."),Object(o.b)("p",null,"You can upgrade the version of your database directly from the Qovery interface."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Any change on this field will not be applied immediately to your database, check the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"#applying-changes-to-a-managed-database"}),"managed mode")," section.")),Object(o.b)("h4",{id:"accessibility"},"Accessibility"),Object(o.b)("p",null,"This parameter lets you decide whether to expose publicly or not your database."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Public")," access will make your database accessible via the public network"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Private")," access will make your database accessible only by applications in your environment")),Object(o.b)("h3",{id:"resources"},"Resources"),Object(o.b)("h4",{id:"cpu--memory"},"CPU / Memory"),Object(o.b)("p",null,"This configuration is available only for databases in ",Object(o.b)("strong",{parentName:"p"},"Container")," mode"),Object(o.b)("p",null,"You can select the CPU assigned to the Kuerbetes pod running the database instance"),Object(o.b)("h4",{id:"instance-type"},"Instance Type"),Object(o.b)("p",null,"This configuration is available only for databases in ",Object(o.b)("strong",{parentName:"p"},"Managed")," mode"),Object(o.b)("p",null,"You can modify the CPU assigned to the instance running your database (And thus, its resources)."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Any change on this field will not be applied immediately to your database, check the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"#applying-changes-to-a-managed-database"}),"managed mode")," section.")),Object(o.b)("h4",{id:"storage"},"Storage"),Object(o.b)("p",null,"You can select the size of the persistent storage attached to the container database."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Any change on this field will not be applied immediately to your database, check the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"#applying-changes-to-a-managed-database"}),"managed mode")," section.")),Object(o.b)("h2",{id:"credentials-and-connectivity"},"Credentials and connectivity"),Object(o.b)("p",null,"When a database is created in your environment, Qovery will automatically create and inject a set of BUILT_IN environment variables containing all the parameters necessary to your application to connect to the database."),Object(o.b)("p",null,"This is the list of environment variables and secrets that will be automatically created:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Name"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Example"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_DEFAULT_DATABASE_NAME"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Env Var containing the default database name"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"postgres")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_HOST"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),'Env Var containing the external hostname of the database (if you need access from the outside and the DB is configured with visibility "PUBLIC")'),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"zf5206c84-postgresql.oom.sh")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_HOST_INTERNAL"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Env Var containing the internal hostname of the database (if you need access it from within the cluster network)"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"zf5206c84-postgresql")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_LOGIN"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Env Var containing the username of the DB"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"superuser")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_PORT"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Env Var containing the port to be used for connecting to the DB"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"5432")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_HOST"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),'Secret containing the external URI to be used for connecting to the DB (if you need access from the outside and the DB is configured with visibility "PUBLIC")'),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"sql://root:xxxx@z4a58c1e2-postgresql.oom.sh:27017/admin")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_HOST_INTERNAL"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Secret containing the internal URI to be used for connecting to the DB (if you need access it from within the cluster network)"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"sql://root:xxxx@z4a58c1e2-postgresql:27017/admin")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_PASSWORD"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Secret containing the password of the DB"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"dbsecret")))),Object(o.b)("p",null,"Please note that the built-in variables follow the naming pattern: ",Object(o.b)("inlineCode",{parentName:"p"},"QOVERY_DATABASETYPE")," + + where:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"")," is the name of your database"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"")," is the type of variable we inject, e.g. ",Object(o.b)("inlineCode",{parentName:"li"},"PASSWORD"),", ",Object(o.b)("inlineCode",{parentName:"li"},"VERSION"),", ",Object(o.b)("inlineCode",{parentName:"li"},"CONNECTION_URI")," and so on.")),Object(o.b)("p",null,"To know how to access your database from your application, ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-a-database"}),"have a look at the database section"),"."),Object(o.b)("h2",{id:"clone"},"Clone"),Object(o.b)("p",null,"You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/clone_service.png",alt:"Clone Service"})),Object(o.b)("p",null,"The target environment can be the same as the current environment or even another one in a completely different project."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"}," Important information ")),Object(o.b)("p",null,"Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"same environment:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"))),Object(o.b)("li",{parentName:"ul"},"another environment:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"),Object(o.b)("li",{parentName:"ul"},"environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)"),Object(o.b)("li",{parentName:"ul"},"deployment pipeline: stage setup is not copied (since the target stage might not exist)"),Object(o.b)("li",{parentName:"ul"},"number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)")))),Object(o.b)("p",null,"Please check the configuration of the new service before deploying it."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Note that only the instance configuration will be copied, not the data contained within the database.")),Object(o.b)("h2",{id:"delete-your-database-instance"},"Delete your database instance"),Object(o.b)(i.a,{type:"danger",mdxType:"Alert"},Object(o.b)("p",null,"Delete action drops the service and its data!")),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"As Managed Services databases (like RDS) are mainly used for production, Qovery does not delete automated snapshots and backups on deletion.\nIt is up to the user or Cloud provider Administrator to delete it manually.")),Object(o.b)(l.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Navigate to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(o.b)("li",null,Object(o.b)("p",null,"Select your environment and database")),Object(o.b)("li",null,Object(o.b)("p",null,"In database overview, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Action")," remove button"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/database/delete.png",alt:"Database Remove"})))),Object(o.b)("h2",{id:"available-databases"},"Available Databases"),Object(o.b)(c.a,{to:"/docs/using-qovery/configuration/database/mongodb/",mdxType:"Jump"},"Mongodb"),Object(o.b)(c.a,{to:"/docs/using-qovery/configuration/database/mysql/",mdxType:"Jump"},"Mysql"),Object(o.b)(c.a,{to:"/docs/using-qovery/configuration/database/postgresql/",mdxType:"Jump"},"Postgresql"),Object(o.b)(c.a,{to:"/docs/using-qovery/configuration/database/redis/",mdxType:"Jump"},"Redis")))}m.isMDXComponent=!0},420:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=r.a.createContext({}),b=function(e){var t=r.a.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):c({},t,{},e)),a},d=function(e){var t=b(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},p=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=b(a),p=n,m=d["".concat(i,".").concat(p)]||d[p]||u[p]||o;return a?r.a.createElement(m,c({ref:t},s,{components:a})):r.a.createElement(m,c({ref:t},s))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,i=new Array(o);i[0]=p;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s1?arguments[1]:void 0,a),l=i>2?arguments[2]:void 0,s=void 0===l?a:r(l,a);s>c;)t[c++]=e;return t}},425:function(e,t,a){var n=a(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var n=a(0),r=a.n(n),o=a(421);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},427:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),i=a(39),c=a(430),l=a(20),s=a.n(l);t.a=function(e){var t,a=e.to,l=e.href,b=a||l,d=Object(c.a)(b),u=Object(r.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&d&&window.docusaurus.prefetch(b),function(){p&&t&&t.disconnect()}}),[b,p,d]),b&&d?o.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){u.current||(window.docusaurus.preload(b),u.current=!0)},innerRef:function(e){var a,n;p&&e&&d&&(a=e,n=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:b})):o.a.createElement("a",Object(n.a)({},e,{href:b}))}},428:function(e,t,a){"use strict";var n=a(432),r=a(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var a=function(e){var t;switch(e.arrayFormat){case"index":return function(e,a,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=a):n[e]=a};case"bracket":return function(e,a,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],a):n[e]=[a]:n[e]=a};default:return function(e,t,a){void 0!==a[e]?a[e]=[].concat(a[e],t):a[e]=t}}}(t=r({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),a(decodeURIComponent(r),o,n)})),Object.keys(n).sort().reduce((function(e,t){var a=n[t];return Boolean(a)&&"object"==typeof a&&!Array.isArray(a)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(a):e[t]=a,e}),Object.create(null))):n},t.stringify=function(e,t){var a=function(e){switch(e.arrayFormat){case"index":return function(t,a,n){return null===a?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(a,e)].join("")};case"bracket":return function(t,a){return null===a?o(t,e):[o(t,e),"[]=",o(a,e)].join("")};default:return function(t,a){return null===a?o(t,e):[o(t,e),"=",o(a,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var r=e[n];if(void 0===r)return"";if(null===r)return o(n,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(a(n,e,i.length))})),i.join("&")}return o(n,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(427),i=a(420),c=a.n(i);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,b=e.target,d=e.to,u=c()("jump-to","jump-to--"+s,a),p=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return b?r.a.createElement("a",{href:d,target:b,className:u},p):r.a.createElement(o.a,{to:d,className:u},p)}},430:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},431:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=(a(420),a(428)),i=a.n(o);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),b=Object(n.useState)(null),d=b[0],u=b[1];return r.a.createElement("div",{className:"steps steps--h"+a},t,!o&&!d&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return u("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==d&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,a){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/9feef5a0.6cc59dfc.js b/9feef5a0.6cc59dfc.js new file mode 100644 index 0000000000..3f84cfecc9 --- /dev/null +++ b/9feef5a0.6cc59dfc.js @@ -0,0 +1,2 @@ +/*! For license information please see 9feef5a0.6cc59dfc.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[158],{310:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return b})),a.d(t,"metadata",(function(){return d})),a.d(t,"rightToc",(function(){return u})),a.d(t,"default",(function(){return m}));var n=a(1),r=a(9),o=(a(0),a(425)),i=a(424),c=a(431),l=a(434),s=a(429),b={last_modified_on:"2023-11-30",title:"Databases",description:"Learn how to configure Databases on Qovery",sidebar_label:"hidden",hide_pagination:!0},d={id:"using-qovery/configuration/database",title:"Databases",description:"Learn how to configure Databases on Qovery",source:"@site/docs/using-qovery/configuration/database.md",permalink:"/docs/using-qovery/configuration/database",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Helm",permalink:"/docs/using-qovery/configuration/helm"},next:{title:"PostgreSQL",permalink:"/docs/using-qovery/configuration/database/postgresql"}},u=[{value:"Container mode",id:"container-mode",children:[]},{value:"Managed mode",id:"managed-mode",children:[{value:"Applying changes to a managed database",id:"applying-changes-to-a-managed-database",children:[]}]},{value:"Create a database",id:"create-a-database",children:[]},{value:"Configuration",id:"configuration",children:[{value:"General",id:"general",children:[]},{value:"Resources",id:"resources",children:[]}]},{value:"Credentials and connectivity",id:"credentials-and-connectivity",children:[]},{value:"Clone",id:"clone",children:[]},{value:"Delete your database instance",id:"delete-your-database-instance",children:[]},{value:"Available Databases",id:"available-databases",children:[]}],p={rightToc:u};function m(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},p,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)(s.a,{name:"documentation",mdxType:"Assumptions"},Object(o.b)("p",null,"You have created an ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment"),".")),Object(o.b)("p",null,"Qovery natively lets you deploy and access the most popular SQL and NoSQL databases available on the major cloud providers. Reliability and resiliency are at the heart of their services, so you don't have to worry about your data on Qovery. "),Object(o.b)("p",null,"Qovery natively supports the following databases:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"PostgreSQL"),Object(o.b)("li",{parentName:"ul"},"MySQL"),Object(o.b)("li",{parentName:"ul"},"MongoDB"),Object(o.b)("li",{parentName:"ul"},"Redis")),Object(o.b)("p",null,'Qovery can natively operate a database in two different ways (called "Mode"):'),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Container mode: preferred for testing and development"),Object(o.b)("li",{parentName:"ul"},"Managed mode: preferred for production, limited configuration parameters (see the ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"#configuration"}),"Configuration")," section).")),Object(o.b)("p",null,"If the natively supported databases or operation modes are not enough for you, depending on your use case you have the following alternative solutions:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Use an existing DB on a dedicated VPC: your applications can access this database via VPC peering. Have a look at ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"this guide")," for more information."),Object(o.b)("li",{parentName:"ul"},"Create your custom database via Qovery: You will be able to deploy any kind of database through Qovery by using a ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"lifecycle jobs"),". For example, you can use a terraform script to deploy your custom RDS instance on AWS via Terraform (have a look at ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/aws-rds-with-terraform"}),"this example"),").")),Object(o.b)("p",null,"The following sections will show you how you can create and manage the databases natively supported by Qovery. For any other use case, please refer to the guides provided above. "),Object(o.b)("h2",{id:"container-mode"},"Container mode"),Object(o.b)("p",null,"The database is created as a container with attached persistent storage directly on your Kubernetes cluster (1 instance). They are perfect for development and testing, as they are significantly cheaper than services provided by cloud providers. "),Object(o.b)("h2",{id:"managed-mode"},"Managed mode"),Object(o.b)("p",null,"Qovery creates and manages the lifecycle of a cloud provider managed database instance (for example an RDS instance on AWS). These are perfect for production since they guarantee the right level of resilience, performance and data security best practices."),Object(o.b)("h3",{id:"applying-changes-to-a-managed-database"},"Applying changes to a managed database"),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},"Since Qovery manages the lifecycle of your database, DO NOT change the database settings directly from within the cloud provider console (to avoid configuration drifts)."),Object(o.b)("p",null,"Once you request to change the version, instance type or disk size of your Managed database, the cloud provider applies the update based on its own internal rules and might cause downtime of your database."),Object(o.b)("p",null,"For example, by default AWS doesn't apply major updates immediately on the database and instead, it waits for a ",Object(o.b)("inlineCode",{parentName:"p"},"maintenance window"),". This means that your change will not be applied immediately but you can always force the change directly from your AWS console AFTER having applied the change on Qovery (to avoid configuration drifts). "),Object(o.b)("p",null,"Have a look at your cloud provider documentation to know more about how version upgrades are managed:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"AWS RDS DB engine upgrade: ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.MySQL.html"}),"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.MySQL.html")),Object(o.b)("li",{parentName:"ul"},"AWS maintenance window: ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Maintenance.html"}),"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Maintenance.html"))),Object(o.b)("h2",{id:"create-a-database"},"Create a database"),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Check out ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"this video guide")," to create and deploy your first database")),Object(o.b)(l.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Navigate to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(o.b)("li",null,Object(o.b)("p",null,"Select your project and environment")),Object(o.b)("li",null,Object(o.b)("p",null,"Click ",Object(o.b)("inlineCode",{parentName:"p"},"Add Database")," button"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/database/db-1.png",alt:"Database"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Select database type, name, description (optional), version, mode and accessibility"),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},"Please refer to the Configuration section below to know more about each of these parameters."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/database/db-2.png",alt:"General Information"}))),Object(o.b)("li",null,Object(o.b)("p",null,'Within the "Resources" step you will find different configurations based on the selected ',Object(o.b)("inlineCode",{parentName:"p"},"mode"),":"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"If you are using the database in ",Object(o.b)("inlineCode",{parentName:"li"},"Container")," mode, you can set the CPU, RAM and storage that will be assigned to the instance running the docker image of the database."),Object(o.b)("li",{parentName:"ul"},"If you are using the database in ",Object(o.b)("inlineCode",{parentName:"li"},"Managed")," mode, you can select the instance type and the storage that will be assigned to the instance running the database. Note, the instance selected instance type has a direct impact on your cloud provider cost.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/database/db-3.png",alt:"Resources"}))),Object(o.b)("li",null,"At the end a recap will allow you to just create the database or create and deploy it",Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/database/db-4.png",alt:"Recap"}))))),Object(o.b)("h2",{id:"configuration"},"Configuration"),Object(o.b)("p",null,"Once created, you can access the configuration of a database at any time via the Settings tab available on the database page"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/database/settings.png",alt:"Database Settings"})),Object(o.b)("p",null,"You can find below the description of each of the tabs available in this section"),Object(o.b)("h3",{id:"general"},"General"),Object(o.b)("h4",{id:"modes"},"Modes"),Object(o.b)("p",null,"As described at the beginning of this document, databases can operate in two modes:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Managed"),Object(o.b)("li",{parentName:"ul"},"Container")),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Managed")," databases are perfect for production - they are provided and managed by major cloud providers like AWS to make sure your production data is well managed."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Container")," databases are managed by Qovery as Docker containers with attached persistent storage directly on your Kubernetes cluster (1 instance). They are perfect for development and testing, as they are significantly cheaper than services provided by cloud providers."),Object(o.b)("p",null,"Please refer to the dedicated database sub-pages to get more information on the supported mode for each cloud provider."),Object(o.b)("h4",{id:"versions"},"Versions"),Object(o.b)("p",null,"We regularly update the version available for each database. Please refer to the dedicated database sub-pages to get more information on the supported version for each database types and cloud provider."),Object(o.b)("p",null,"You can upgrade the version of your database directly from the Qovery interface."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Any change on this field will not be applied immediately to your database, check the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"#applying-changes-to-a-managed-database"}),"managed mode")," section.")),Object(o.b)("h4",{id:"accessibility"},"Accessibility"),Object(o.b)("p",null,"This parameter lets you decide whether to expose publicly or not your database."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Public")," access will make your database accessible via the public network"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Private")," access will make your database accessible only by applications in your environment")),Object(o.b)("h3",{id:"resources"},"Resources"),Object(o.b)("h4",{id:"cpu--memory"},"CPU / Memory"),Object(o.b)("p",null,"This configuration is available only for databases in ",Object(o.b)("strong",{parentName:"p"},"Container")," mode"),Object(o.b)("p",null,"You can select the CPU assigned to the Kuerbetes pod running the database instance"),Object(o.b)("h4",{id:"instance-type"},"Instance Type"),Object(o.b)("p",null,"This configuration is available only for databases in ",Object(o.b)("strong",{parentName:"p"},"Managed")," mode"),Object(o.b)("p",null,"You can modify the CPU assigned to the instance running your database (And thus, its resources)."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Any change on this field will not be applied immediately to your database, check the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"#applying-changes-to-a-managed-database"}),"managed mode")," section.")),Object(o.b)("h4",{id:"storage"},"Storage"),Object(o.b)("p",null,"You can select the size of the persistent storage attached to the container database."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Any change on this field will not be applied immediately to your database, check the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"#applying-changes-to-a-managed-database"}),"managed mode")," section.")),Object(o.b)("h2",{id:"credentials-and-connectivity"},"Credentials and connectivity"),Object(o.b)("p",null,"When a database is created in your environment, Qovery will automatically create and inject a set of BUILT_IN environment variables containing all the parameters necessary to your application to connect to the database."),Object(o.b)("p",null,"This is the list of environment variables and secrets that will be automatically created:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Name"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Example"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_DEFAULT_DATABASE_NAME"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Env Var containing the default database name"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"postgres")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_HOST"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),'Env Var containing the external hostname of the database (if you need access from the outside and the DB is configured with visibility "PUBLIC")'),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"zf5206c84-postgresql.oom.sh")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_HOST_INTERNAL"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Env Var containing the internal hostname of the database (if you need access it from within the cluster network)"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"zf5206c84-postgresql")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_LOGIN"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Env Var containing the username of the DB"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"superuser")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_PORT"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Env Var containing the port to be used for connecting to the DB"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"5432")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_HOST"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),'Secret containing the external URI to be used for connecting to the DB (if you need access from the outside and the DB is configured with visibility "PUBLIC")'),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"sql://root:xxxx@z4a58c1e2-postgresql.oom.sh:27017/admin")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_HOST_INTERNAL"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Secret containing the internal URI to be used for connecting to the DB (if you need access it from within the cluster network)"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"sql://root:xxxx@z4a58c1e2-postgresql:27017/admin")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"QOVERY",Object(o.b)("em",{parentName:"td"},Object(o.b)("inlineCode",{parentName:"em"},"")),Object(o.b)("inlineCode",{parentName:"td"},""),"_PASSWORD"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Secret containing the password of the DB"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"dbsecret")))),Object(o.b)("p",null,"Please note that the built-in variables follow the naming pattern: ",Object(o.b)("inlineCode",{parentName:"p"},"QOVERY_DATABASETYPE")," + + where:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"")," is the name of your database"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"")," is the type of variable we inject, e.g. ",Object(o.b)("inlineCode",{parentName:"li"},"PASSWORD"),", ",Object(o.b)("inlineCode",{parentName:"li"},"VERSION"),", ",Object(o.b)("inlineCode",{parentName:"li"},"CONNECTION_URI")," and so on.")),Object(o.b)("p",null,"To know how to access your database from your application, ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-a-database"}),"have a look at the database section"),"."),Object(o.b)("h2",{id:"clone"},"Clone"),Object(o.b)("p",null,"You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/clone_service.png",alt:"Clone Service"})),Object(o.b)("p",null,"The target environment can be the same as the current environment or even another one in a completely different project."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"}," Important information ")),Object(o.b)("p",null,"Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"same environment:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"))),Object(o.b)("li",{parentName:"ul"},"another environment:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"),Object(o.b)("li",{parentName:"ul"},"environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)"),Object(o.b)("li",{parentName:"ul"},"deployment pipeline: stage setup is not copied (since the target stage might not exist)"),Object(o.b)("li",{parentName:"ul"},"number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)")))),Object(o.b)("p",null,"Please check the configuration of the new service before deploying it."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Note that only the instance configuration will be copied, not the data contained within the database.")),Object(o.b)("h2",{id:"delete-your-database-instance"},"Delete your database instance"),Object(o.b)(i.a,{type:"danger",mdxType:"Alert"},Object(o.b)("p",null,"Delete action drops the service and its data!")),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"As Managed Services databases (like RDS) are mainly used for production, Qovery does not delete automated snapshots and backups on deletion.\nIt is up to the user or Cloud provider Administrator to delete it manually.")),Object(o.b)(l.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Navigate to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(o.b)("li",null,Object(o.b)("p",null,"Select your environment and database")),Object(o.b)("li",null,Object(o.b)("p",null,"In database overview, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Action")," remove button"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/database/delete.png",alt:"Database Remove"})))),Object(o.b)("h2",{id:"available-databases"},"Available Databases"),Object(o.b)(c.a,{to:"/docs/using-qovery/configuration/database/mongodb/",mdxType:"Jump"},"Mongodb"),Object(o.b)(c.a,{to:"/docs/using-qovery/configuration/database/mysql/",mdxType:"Jump"},"Mysql"),Object(o.b)(c.a,{to:"/docs/using-qovery/configuration/database/postgresql/",mdxType:"Jump"},"Postgresql"),Object(o.b)(c.a,{to:"/docs/using-qovery/configuration/database/redis/",mdxType:"Jump"},"Redis")))}m.isMDXComponent=!0},423:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=r.a.createContext({}),b=function(e){var t=r.a.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):c({},t,{},e)),a},d=function(e){var t=b(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},p=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=b(a),p=n,m=d["".concat(i,".").concat(p)]||d[p]||u[p]||o;return a?r.a.createElement(m,c({ref:t},s,{components:a})):r.a.createElement(m,c({ref:t},s))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,i=new Array(o);i[0]=p;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s1?arguments[1]:void 0,a),l=i>2?arguments[2]:void 0,s=void 0===l?a:r(l,a);s>c;)t[c++]=e;return t}},428:function(e,t,a){var n=a(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var n=a(0),r=a.n(n),o=a(424);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},430:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),i=a(39),c=a(432),l=a(20),s=a.n(l);t.a=function(e){var t,a=e.to,l=e.href,b=a||l,d=Object(c.a)(b),u=Object(r.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&d&&window.docusaurus.prefetch(b),function(){p&&t&&t.disconnect()}}),[b,p,d]),b&&d?o.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){u.current||(window.docusaurus.preload(b),u.current=!0)},innerRef:function(e){var a,n;p&&e&&d&&(a=e,n=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:b})):o.a.createElement("a",Object(n.a)({},e,{href:b}))}},431:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(430),i=a(423),c=a.n(i);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,b=e.target,d=e.to,u=c()("jump-to","jump-to--"+s,a),p=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return b?r.a.createElement("a",{href:d,target:b,className:u},p):r.a.createElement(o.a,{to:d,className:u},p)}},432:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},433:function(e,t,a){"use strict";var n=a(435),r=a(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var a=function(e){var t;switch(e.arrayFormat){case"index":return function(e,a,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=a):n[e]=a};case"bracket":return function(e,a,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],a):n[e]=[a]:n[e]=a};default:return function(e,t,a){void 0!==a[e]?a[e]=[].concat(a[e],t):a[e]=t}}}(t=r({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),a(decodeURIComponent(r),o,n)})),Object.keys(n).sort().reduce((function(e,t){var a=n[t];return Boolean(a)&&"object"==typeof a&&!Array.isArray(a)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(a):e[t]=a,e}),Object.create(null))):n},t.stringify=function(e,t){var a=function(e){switch(e.arrayFormat){case"index":return function(t,a,n){return null===a?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(a,e)].join("")};case"bracket":return function(t,a){return null===a?o(t,e):[o(t,e),"[]=",o(a,e)].join("")};default:return function(t,a){return null===a?o(t,e):[o(t,e),"=",o(a,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var r=e[n];if(void 0===r)return"";if(null===r)return o(n,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(a(n,e,i.length))})),i.join("&")}return o(n,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=(a(423),a(433)),i=a.n(o);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),b=Object(n.useState)(null),d=b[0],u=b[1];return r.a.createElement("div",{className:"steps steps--h"+a},t,!o&&!d&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return u("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==d&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,a){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/a1fea8fb.ca185edd.js.LICENSE.txt b/9feef5a0.6cc59dfc.js.LICENSE.txt similarity index 100% rename from a1fea8fb.ca185edd.js.LICENSE.txt rename to 9feef5a0.6cc59dfc.js.LICENSE.txt diff --git a/a156f6a6.219e64e1.js b/a156f6a6.aab2f4d6.js similarity index 95% rename from a156f6a6.219e64e1.js rename to a156f6a6.aab2f4d6.js index d6bb0107ac..9499f351d0 100644 --- a/a156f6a6.219e64e1.js +++ b/a156f6a6.aab2f4d6.js @@ -1,2 +1,2 @@ -/*! For license information please see a156f6a6.219e64e1.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[156],{308:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return o})),t.d(n,"metadata",(function(){return l})),t.d(n,"rightToc",(function(){return s})),t.d(n,"default",(function(){return p}));var a=t(1),r=t(9),i=(t(0),t(422)),o=(t(421),t(426),t(429),{last_modified_on:"2022-04-22",$schema:"/.meta/.schemas/guides.json",title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",description:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",description:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",permalink:"/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws",readingTime:"10 min read",source:"@site/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",truncated:!1,prevItem:{title:"Debugging",permalink:"/guides/getting-started/debugging"},nextItem:{title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",permalink:"/guides/tutorial/build-e2e-testing-ephemeral-environments"}},s=[{value:"Qovery Deployment Platform",id:"qovery-deployment-platform",children:[]},{value:"Previ1ew Environments",id:"previ1ew-environments",children:[]},{value:"Preview environments benefits",id:"preview-environments-benefits",children:[]},{value:"Demo",id:"demo",children:[{value:"AWS Infrastructure",id:"aws-infrastructure",children:[]},{value:"Full Stack Application",id:"full-stack-application",children:[]},{value:"Frontend",id:"frontend",children:[]},{value:"Backend",id:"backend",children:[]},{value:"Deployment",id:"deployment",children:[]},{value:"Enable Preview Environments",id:"enable-preview-environments",children:[]},{value:"Testing Preview Environments",id:"testing-preview-environments",children:[]},{value:"Preview Environment Explained",id:"preview-environment-explained",children:[]},{value:"Testing Preview Environments PT II",id:"testing-preview-environments-pt-ii",children:[]},{value:"Conclusion",id:"conclusion",children:[]}]}],c={rightToc:s};function p(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},c,t,{components:n,mdxType:"MDXLayout"}),Object(i.b)("h3",{id:"qovery-deployment-platform"},"Qovery Deployment Platform"),Object(i.b)("p",null,"Have you ever dreamed of deploying your applications on the cloud without any hassle? Imagine a platform where all you need to do is to sign in with your AWS credentials, and automagically the platform does all the hard work of configuration of the cloud for you, and, on top of that, provides some extra features that do not exist out of the box anywhere else."),Object(i.b)("p",null,"Qovery is this platform - not only does it allow you to deploy your infrastructure and applications on your own cloud account, but also provides extra cool features, one of which we will see in this article."),Object(i.b)("p",null,Object(i.b)("em",{parentName:"p"},"Don't take our words for granted - 14000 developers from more than 100 countries use Qovery to deploy their apps on AWS.")),Object(i.b)("h3",{id:"previ1ew-environments"},"Previ1ew Environments"),Object(i.b)("p",null,"Imagine working on a new feature. You're dealing with a full-stack application - you have a frontend, backend, and a database. You introduce a change to your backend app - how do you test all of it? It would be great if there was a service that could deploy everything for you so you can test your changes quickly and in separation with all the components..."),Object(i.b)("p",null,"Qovery Preview Environments are designed to help you with exactly this."),Object(i.b)("p",null,"It not only deploys the app you changed but all other related applications and databases as well in the cloud so that you can test your new features and collaborate with reviewers of your code."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/1.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Preview environments feature is available on other platforms as well. Vercel and Netlify allows you to test your changes before merging code into production. It\u2019s perfect for single frontend applications, but the concept of Preview Environments on Qovery goes far beyond this."),Object(i.b)("p",null,"Qovery is able not only to create a preview environment for your frontend, but also for the backend and databases - the whole stack is supported. Running a set of backend microservices? No worries, Qovery got you covered. All services will be replicated in the new environment."),Object(i.b)("h3",{id:"preview-environments-benefits"},"Preview environments benefits"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Time-saving")," - You don't have to set up a fresh environment to test changes in isolation - Qovery does it all for you"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Productivity")," - Faster changes, quicker review, better feedback loop - the productivity and quality of your application increases dramatically"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Better tests")," - It's best to test apps in isolation, but it's almost impossible with a complicated stack if you have to prepare the testing environment manually - Qovery does it all \"automagically\" for you"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Independence")," - Each environment is completely separate, meaning more people can work flawlessly on the project, testing the changes they introduce in parallel, not blocking each other"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Deliver quickly")," - Faster feedback loop, independent developers, fewer bugs, meaning the product is delivered more quickly"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Reduce friction")," - Waiting for others to test your changes is frustrating - with preview envs everyone has his own testing environment")),Object(i.b)("h2",{id:"demo"},"Demo"),Object(i.b)("h3",{id:"aws-infrastructure"},"AWS Infrastructure"),Object(i.b)("p",null,"Before we start with the deployments, we need to have our AWS infrastructure ready and deployed. It can be done as simply as by providing credentials to your cloud account, you can see how to configure the credentials in this article - ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/"}),"https://hub.qovery.com/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/2.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"The initial setup takes about 15 min, and your cluster is ready to host your applications."),Object(i.b)("h3",{id:"full-stack-application"},"Full Stack Application"),Object(i.b)("p",null,"In this example, we will use a Next.js frontend, Node.js backend, and MongoDB as a database. The app will display an image gallery with images fetched from the backend. Preview Environments feature will help us introduce a new change in the backend - moving away from a hardcoded POC list of images to a list fetched from our database."),Object(i.b)("h3",{id:"frontend"},"Frontend"),Object(i.b)("p",null,"Our simple image gallery will look like this"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/3.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"To generate the application, we used ",Object(i.b)("inlineCode",{parentName:"p"},"npx create-next-app@latest"),", but the source code can be found here - ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/gallery-demo/tree/master/frontend"}),"https://github.com/pjeziorowski/gallery-demo/tree/master/frontend")),Object(i.b)("p",null,"The main changes introduced to the generated application scaffolding are:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Adding a ",Object(i.b)("inlineCode",{parentName:"li"},"Dockerfile"))),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-docker"}),"FROM node:alpine\n\nRUN mkdir -p /usr/src\nWORKDIR /usr/src\n\nCOPY . /usr/src\nRUN npm install\nRUN npm run build\n\nEXPOSE 3000\nCMD npm run start\n")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Adding a query to our backend (which we will be built soon in the next steps) that fetches a list of images to display in our gallery"),Object(i.b)("pre",{parentName:"li"},Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'function useImages() {\n return useQuery("images", async () => {\n const { data } = await axios.get(\n `${apiRoot}/api/v1/images`\n );\n return data;\n });\n}\n'))),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Plus, we adjusted the HTML and styling for the demo purpose of showing a list of images"))),Object(i.b)("h3",{id:"backend"},"Backend"),Object(i.b)("p",null,"Our backend is the main star of the demo. In its first version, the backend is displaying a hardcoded list of images. In the next step, we will gradually expand its capabilities. It will connect to a database and fetch the list from MongoDB instead. To make sure the changes are correct, we will use ",Object(i.b)("inlineCode",{parentName:"p"},"Preview Environment")," feature before merging the pull request to our production environment"),Object(i.b)("p",null,"The backend was generated using Express ",Object(i.b)("inlineCode",{parentName:"p"},"npx express-generator --no-view"),", and the source code can be found here - ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/gallery-demo/tree/master/frontend"}),"https://github.com/pjeziorowski/gallery-demo/tree/master/backend")),Object(i.b)("p",null,"Changes that we introduced to the generated app scaffolding are the following:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Adding a Dockerfile"),Object(i.b)("pre",{parentName:"li"},Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-docker"}),'FROM node:16\n\nWORKDIR /usr/src/app\n\nCOPY package*.json ./\nRUN npm install\nCOPY . .\n\nEXPOSE 8080\nCMD [ "node", "src/index.js" ]\n'))),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Creating a ",Object(i.b)("inlineCode",{parentName:"p"},"/api/v1/images")," endpoint that returns a hardcoded array of images"),Object(i.b)("pre",{parentName:"li"},Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"router.get('/images', (req, res) => {\n res.json([\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n }\n });\n});\n")),Object(i.b)("p",{parentName:"li"}," In the next step we will improve the function to use a Mongo database instead."))),Object(i.b)("h3",{id:"deployment"},"Deployment"),Object(i.b)("p",null,"After creating a new project, let's now set up our ",Object(i.b)("inlineCode",{parentName:"p"},"production")," environment."),Object(i.b)("p",null,"First, let's deploy our frontend. Click ",Object(i.b)("inlineCode",{parentName:"p"},"Add my first application"),", select a correct repository, ",Object(i.b)("inlineCode",{parentName:"p"},"Docker")," as build mode and expose port ",Object(i.b)("inlineCode",{parentName:"p"},"3000"),". The application root path is ",Object(i.b)("inlineCode",{parentName:"p"},"/frontend"),"."),Object(i.b)("p",null,"Next step: add a ",Object(i.b)("inlineCode",{parentName:"p"},"MongoDB")," database - it will be used by our backend later on. You can do so by clicking on ",Object(i.b)("inlineCode",{parentName:"p"},"Add")," button in Qovery Console in Environment."),Object(i.b)("p",null,"Now let's deploy our backend. Click ",Object(i.b)("inlineCode",{parentName:"p"},"Add")," \u2192 ",Object(i.b)("inlineCode",{parentName:"p"},"Application"),", pick up ",Object(i.b)("inlineCode",{parentName:"p"},"/backend")," as application root path, ",Object(i.b)("inlineCode",{parentName:"p"},"8080")," port, and ",Object(i.b)("inlineCode",{parentName:"p"},"Docker")," build mode."),Object(i.b)("p",null,"For the future connection to DB, let's add an alias named ",Object(i.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," that points to our Mongo database internal URL in our backend ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variable")," settings:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/4.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Additionally, let's create an alias called ",Object(i.b)("inlineCode",{parentName:"p"},"API_ROOT")," in our frontend application that points to our backend external URL:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/5.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"This is it! Now we can deploy our production environment. After a few minutes, navigate to the frontend app, click on ",Object(i.b)("inlineCode",{parentName:"p"},"Open")," - you should be redirected to the image gallery"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/6.png",alt:"AWS Preview Environments"})),Object(i.b)("h3",{id:"enable-preview-environments"},"Enable Preview Environments"),Object(i.b)("p",null,"The next step to see the preview environment feature in action is to enable it for our backend application."),Object(i.b)("p",null,"To do so, navigate to ",Object(i.b)("inlineCode",{parentName:"p"},"Environment")," \u2192 ",Object(i.b)("inlineCode",{parentName:"p"},"Settings")," \u2192 ",Object(i.b)("inlineCode",{parentName:"p"},"Preview Env")," and tick it for the backend app"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/7.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Great! The feature is enabled. To see it in action, let's edit our code in the backend app so that the list of images is fetched from the database instead."),Object(i.b)("h3",{id:"testing-preview-environments"},"Testing Preview Environments"),Object(i.b)("p",null,"Let's make a small update of our backend - let's connect to MongoDB and fetch images from there. Here are changes to the function we could introduce to make it happen:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const databaseUrl = process.env.DATABASE_URL\n || 'mongodb://localhost:27017/test';\n\nconst imageSchema = new mongoose.Schema({\n title: String,\n size: String,\n source: String\n});\n\nmongoose.connect(databaseUrl);\n\nrouter.get('/', (req, res) => {\n imageSchema.find().then((data) => {\n res.json(\n data\n )\n });\n});\n")),Object(i.b)("p",null,"Let's now create a new branch in our repository and create a pull request to our production (master branch) environment. Preview Environments feature will spin up a new environment for us so that we can safely test changes we just introduced!"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/8.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Once the PR is created, an automatic comment has been dropped on our PR to let us know that the new preview environment has been created."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/14.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Now, when we display environments in our project, we will see that a new environment for the pull request is being deployed:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/9.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"with all the resources we need! A database, backend, frontend - we can now test our changes in complete separation from the production without any manual setting up work:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/10.png",alt:"AWS Preview Environments"})),Object(i.b)("h3",{id:"preview-environment-explained"},"Preview Environment Explained"),Object(i.b)("p",null,"The Preview Environment feature can be enabled or disabled per app. It creates a complete copy of your environment so that you can test new changes from pull requests in separation. It deploys your databases, backend, and frontend applications to a completely new environment once a pull request is opened. If you update your pull request, all new changes are also reflected in the new environment so that you can test them or fix problems during the review. What is great is that Qovery takes care of managing all environment variables for you as well, creates new aliases just as you had in your prod environment, so that everything is really tested separately and it all happens automagically. After the pull request is merged, Qovery automatically cleans up the preview environment to save your money."),Object(i.b)("h3",{id:"testing-preview-environments-pt-ii"},"Testing Preview Environments PT II"),Object(i.b)("p",null,"After a few minutes, your preview environment should be up and running. You can now navigate to the frontend app and click ",Object(i.b)("inlineCode",{parentName:"p"},"Open")," - in the image gallery, you will see an empty list because we don't yet have any images in the database."),Object(i.b)("p",null,"You can add a few images manually by connecting to your mongo instance via CLI. The credentials can be found in the database overview:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/11.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"After connecting, let's add images by executing the following:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"db.createCollection(\"images\")\n\ndb.images.insert([\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n },\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n },\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n }\n ])\n")),Object(i.b)("p",null,"Now, after opening the frontend app in our preview environment, we will see all the images we put in the database! It looks like the feature is working well, so let's merge the PR:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/12.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"What now happens is automatically after the PR merge, the preview environment is automatically cleaned up:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/13.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Great job! Thanks to Qovery Preview Environments, we managed to develop a new feature in a complete separation from our production, we tested it in a real environment deployed in the cloud, and we didn't have to spend any time preparing our environment for tests at all."),Object(i.b)("h3",{id:"conclusion"},"Conclusion"),Object(i.b)("p",null,"In the article, we quickly went through the process of creating a full-stack application with frontend, backend, and database. We enabled the Preview Environment feature to develop new features more quickly. We learned what the benefits of Preview Environments are, how to use them, and how to integrate them to day to day development workflow."))}p.isMDXComponent=!0},420:function(e,n,t){var a;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var c=r.a.createContext({}),p=function(e){var n=r.a.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):l({},n,{},e)),t},u=function(e){var n=p(e.components);return r.a.createElement(c.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},b=Object(a.forwardRef)((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,o=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=p(t),b=a,m=u["".concat(o,".").concat(b)]||u[b]||d[b]||i;return t?r.a.createElement(m,l({ref:n},c,{components:t})):r.a.createElement(m,l({ref:n},c))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=b;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var c=2;c1?arguments[1]:void 0,t),s=o>2?arguments[2]:void 0,c=void 0===s?t:r(s,t);c>l;)n[l++]=e;return n}},425:function(e,n,t){var a=t(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||t(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},426:function(e,n,t){"use strict";t(425);var a=t(0),r=t.n(a),i=t(421);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},427:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),l=t(430),s=t(20),c=t.n(s);n.a=function(e){var n,t=e.to,s=e.href,p=t||s,u=Object(l.a)(p),d=Object(r.useRef)(!1),b=c.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!b&&u&&window.docusaurus.prefetch(p),function(){b&&n&&n.disconnect()}}),[p,b,u]),p&&u?i.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(p),d.current=!0)},innerRef:function(e){var t,a;b&&e&&u&&(t=e,a=function(){window.docusaurus.prefetch(p)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),a())}))}))).observe(t))},to:p})):i.a.createElement("a",Object(a.a)({},e,{href:p}))}},429:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(427),o=t(420),l=t.n(o);t(133);n.a=function(e){var n=e.children,t=e.className,a=e.badge,o=e.leftIcon,s=e.rightIcon,c=e.size,p=e.target,u=e.to,d=l()("jump-to","jump-to--"+c,t),b=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},o&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+o})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",n),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:u,target:p,className:d},b):r.a.createElement(i.a,{to:u,className:d},b)}},430:function(e,n,t){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see a156f6a6.aab2f4d6.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[159],{311:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return o})),t.d(n,"metadata",(function(){return l})),t.d(n,"rightToc",(function(){return s})),t.d(n,"default",(function(){return p}));var a=t(1),r=t(9),i=(t(0),t(425)),o=(t(424),t(429),t(431),{last_modified_on:"2022-04-22",$schema:"/.meta/.schemas/guides.json",title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",description:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",description:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",permalink:"/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws",readingTime:"10 min read",source:"@site/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",truncated:!1,prevItem:{title:"Debugging",permalink:"/guides/getting-started/debugging"},nextItem:{title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery",permalink:"/guides/tutorial/build-e2e-testing-ephemeral-environments"}},s=[{value:"Qovery Deployment Platform",id:"qovery-deployment-platform",children:[]},{value:"Previ1ew Environments",id:"previ1ew-environments",children:[]},{value:"Preview environments benefits",id:"preview-environments-benefits",children:[]},{value:"Demo",id:"demo",children:[{value:"AWS Infrastructure",id:"aws-infrastructure",children:[]},{value:"Full Stack Application",id:"full-stack-application",children:[]},{value:"Frontend",id:"frontend",children:[]},{value:"Backend",id:"backend",children:[]},{value:"Deployment",id:"deployment",children:[]},{value:"Enable Preview Environments",id:"enable-preview-environments",children:[]},{value:"Testing Preview Environments",id:"testing-preview-environments",children:[]},{value:"Preview Environment Explained",id:"preview-environment-explained",children:[]},{value:"Testing Preview Environments PT II",id:"testing-preview-environments-pt-ii",children:[]},{value:"Conclusion",id:"conclusion",children:[]}]}],c={rightToc:s};function p(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},c,t,{components:n,mdxType:"MDXLayout"}),Object(i.b)("h3",{id:"qovery-deployment-platform"},"Qovery Deployment Platform"),Object(i.b)("p",null,"Have you ever dreamed of deploying your applications on the cloud without any hassle? Imagine a platform where all you need to do is to sign in with your AWS credentials, and automagically the platform does all the hard work of configuration of the cloud for you, and, on top of that, provides some extra features that do not exist out of the box anywhere else."),Object(i.b)("p",null,"Qovery is this platform - not only does it allow you to deploy your infrastructure and applications on your own cloud account, but also provides extra cool features, one of which we will see in this article."),Object(i.b)("p",null,Object(i.b)("em",{parentName:"p"},"Don't take our words for granted - 14000 developers from more than 100 countries use Qovery to deploy their apps on AWS.")),Object(i.b)("h3",{id:"previ1ew-environments"},"Previ1ew Environments"),Object(i.b)("p",null,"Imagine working on a new feature. You're dealing with a full-stack application - you have a frontend, backend, and a database. You introduce a change to your backend app - how do you test all of it? It would be great if there was a service that could deploy everything for you so you can test your changes quickly and in separation with all the components..."),Object(i.b)("p",null,"Qovery Preview Environments are designed to help you with exactly this."),Object(i.b)("p",null,"It not only deploys the app you changed but all other related applications and databases as well in the cloud so that you can test your new features and collaborate with reviewers of your code."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/1.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Preview environments feature is available on other platforms as well. Vercel and Netlify allows you to test your changes before merging code into production. It\u2019s perfect for single frontend applications, but the concept of Preview Environments on Qovery goes far beyond this."),Object(i.b)("p",null,"Qovery is able not only to create a preview environment for your frontend, but also for the backend and databases - the whole stack is supported. Running a set of backend microservices? No worries, Qovery got you covered. All services will be replicated in the new environment."),Object(i.b)("h3",{id:"preview-environments-benefits"},"Preview environments benefits"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Time-saving")," - You don't have to set up a fresh environment to test changes in isolation - Qovery does it all for you"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Productivity")," - Faster changes, quicker review, better feedback loop - the productivity and quality of your application increases dramatically"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Better tests")," - It's best to test apps in isolation, but it's almost impossible with a complicated stack if you have to prepare the testing environment manually - Qovery does it all \"automagically\" for you"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Independence")," - Each environment is completely separate, meaning more people can work flawlessly on the project, testing the changes they introduce in parallel, not blocking each other"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Deliver quickly")," - Faster feedback loop, independent developers, fewer bugs, meaning the product is delivered more quickly"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Reduce friction")," - Waiting for others to test your changes is frustrating - with preview envs everyone has his own testing environment")),Object(i.b)("h2",{id:"demo"},"Demo"),Object(i.b)("h3",{id:"aws-infrastructure"},"AWS Infrastructure"),Object(i.b)("p",null,"Before we start with the deployments, we need to have our AWS infrastructure ready and deployed. It can be done as simply as by providing credentials to your cloud account, you can see how to configure the credentials in this article - ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/"}),"https://hub.qovery.com/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/2.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"The initial setup takes about 15 min, and your cluster is ready to host your applications."),Object(i.b)("h3",{id:"full-stack-application"},"Full Stack Application"),Object(i.b)("p",null,"In this example, we will use a Next.js frontend, Node.js backend, and MongoDB as a database. The app will display an image gallery with images fetched from the backend. Preview Environments feature will help us introduce a new change in the backend - moving away from a hardcoded POC list of images to a list fetched from our database."),Object(i.b)("h3",{id:"frontend"},"Frontend"),Object(i.b)("p",null,"Our simple image gallery will look like this"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/3.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"To generate the application, we used ",Object(i.b)("inlineCode",{parentName:"p"},"npx create-next-app@latest"),", but the source code can be found here - ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/gallery-demo/tree/master/frontend"}),"https://github.com/pjeziorowski/gallery-demo/tree/master/frontend")),Object(i.b)("p",null,"The main changes introduced to the generated application scaffolding are:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Adding a ",Object(i.b)("inlineCode",{parentName:"li"},"Dockerfile"))),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-docker"}),"FROM node:alpine\n\nRUN mkdir -p /usr/src\nWORKDIR /usr/src\n\nCOPY . /usr/src\nRUN npm install\nRUN npm run build\n\nEXPOSE 3000\nCMD npm run start\n")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Adding a query to our backend (which we will be built soon in the next steps) that fetches a list of images to display in our gallery"),Object(i.b)("pre",{parentName:"li"},Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'function useImages() {\n return useQuery("images", async () => {\n const { data } = await axios.get(\n `${apiRoot}/api/v1/images`\n );\n return data;\n });\n}\n'))),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Plus, we adjusted the HTML and styling for the demo purpose of showing a list of images"))),Object(i.b)("h3",{id:"backend"},"Backend"),Object(i.b)("p",null,"Our backend is the main star of the demo. In its first version, the backend is displaying a hardcoded list of images. In the next step, we will gradually expand its capabilities. It will connect to a database and fetch the list from MongoDB instead. To make sure the changes are correct, we will use ",Object(i.b)("inlineCode",{parentName:"p"},"Preview Environment")," feature before merging the pull request to our production environment"),Object(i.b)("p",null,"The backend was generated using Express ",Object(i.b)("inlineCode",{parentName:"p"},"npx express-generator --no-view"),", and the source code can be found here - ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/gallery-demo/tree/master/frontend"}),"https://github.com/pjeziorowski/gallery-demo/tree/master/backend")),Object(i.b)("p",null,"Changes that we introduced to the generated app scaffolding are the following:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Adding a Dockerfile"),Object(i.b)("pre",{parentName:"li"},Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-docker"}),'FROM node:16\n\nWORKDIR /usr/src/app\n\nCOPY package*.json ./\nRUN npm install\nCOPY . .\n\nEXPOSE 8080\nCMD [ "node", "src/index.js" ]\n'))),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Creating a ",Object(i.b)("inlineCode",{parentName:"p"},"/api/v1/images")," endpoint that returns a hardcoded array of images"),Object(i.b)("pre",{parentName:"li"},Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"router.get('/images', (req, res) => {\n res.json([\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n }\n });\n});\n")),Object(i.b)("p",{parentName:"li"}," In the next step we will improve the function to use a Mongo database instead."))),Object(i.b)("h3",{id:"deployment"},"Deployment"),Object(i.b)("p",null,"After creating a new project, let's now set up our ",Object(i.b)("inlineCode",{parentName:"p"},"production")," environment."),Object(i.b)("p",null,"First, let's deploy our frontend. Click ",Object(i.b)("inlineCode",{parentName:"p"},"Add my first application"),", select a correct repository, ",Object(i.b)("inlineCode",{parentName:"p"},"Docker")," as build mode and expose port ",Object(i.b)("inlineCode",{parentName:"p"},"3000"),". The application root path is ",Object(i.b)("inlineCode",{parentName:"p"},"/frontend"),"."),Object(i.b)("p",null,"Next step: add a ",Object(i.b)("inlineCode",{parentName:"p"},"MongoDB")," database - it will be used by our backend later on. You can do so by clicking on ",Object(i.b)("inlineCode",{parentName:"p"},"Add")," button in Qovery Console in Environment."),Object(i.b)("p",null,"Now let's deploy our backend. Click ",Object(i.b)("inlineCode",{parentName:"p"},"Add")," \u2192 ",Object(i.b)("inlineCode",{parentName:"p"},"Application"),", pick up ",Object(i.b)("inlineCode",{parentName:"p"},"/backend")," as application root path, ",Object(i.b)("inlineCode",{parentName:"p"},"8080")," port, and ",Object(i.b)("inlineCode",{parentName:"p"},"Docker")," build mode."),Object(i.b)("p",null,"For the future connection to DB, let's add an alias named ",Object(i.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," that points to our Mongo database internal URL in our backend ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variable")," settings:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/4.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Additionally, let's create an alias called ",Object(i.b)("inlineCode",{parentName:"p"},"API_ROOT")," in our frontend application that points to our backend external URL:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/5.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"This is it! Now we can deploy our production environment. After a few minutes, navigate to the frontend app, click on ",Object(i.b)("inlineCode",{parentName:"p"},"Open")," - you should be redirected to the image gallery"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/6.png",alt:"AWS Preview Environments"})),Object(i.b)("h3",{id:"enable-preview-environments"},"Enable Preview Environments"),Object(i.b)("p",null,"The next step to see the preview environment feature in action is to enable it for our backend application."),Object(i.b)("p",null,"To do so, navigate to ",Object(i.b)("inlineCode",{parentName:"p"},"Environment")," \u2192 ",Object(i.b)("inlineCode",{parentName:"p"},"Settings")," \u2192 ",Object(i.b)("inlineCode",{parentName:"p"},"Preview Env")," and tick it for the backend app"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/7.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Great! The feature is enabled. To see it in action, let's edit our code in the backend app so that the list of images is fetched from the database instead."),Object(i.b)("h3",{id:"testing-preview-environments"},"Testing Preview Environments"),Object(i.b)("p",null,"Let's make a small update of our backend - let's connect to MongoDB and fetch images from there. Here are changes to the function we could introduce to make it happen:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const databaseUrl = process.env.DATABASE_URL\n || 'mongodb://localhost:27017/test';\n\nconst imageSchema = new mongoose.Schema({\n title: String,\n size: String,\n source: String\n});\n\nmongoose.connect(databaseUrl);\n\nrouter.get('/', (req, res) => {\n imageSchema.find().then((data) => {\n res.json(\n data\n )\n });\n});\n")),Object(i.b)("p",null,"Let's now create a new branch in our repository and create a pull request to our production (master branch) environment. Preview Environments feature will spin up a new environment for us so that we can safely test changes we just introduced!"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/8.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Once the PR is created, an automatic comment has been dropped on our PR to let us know that the new preview environment has been created."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/14.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Now, when we display environments in our project, we will see that a new environment for the pull request is being deployed:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/9.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"with all the resources we need! A database, backend, frontend - we can now test our changes in complete separation from the production without any manual setting up work:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/10.png",alt:"AWS Preview Environments"})),Object(i.b)("h3",{id:"preview-environment-explained"},"Preview Environment Explained"),Object(i.b)("p",null,"The Preview Environment feature can be enabled or disabled per app. It creates a complete copy of your environment so that you can test new changes from pull requests in separation. It deploys your databases, backend, and frontend applications to a completely new environment once a pull request is opened. If you update your pull request, all new changes are also reflected in the new environment so that you can test them or fix problems during the review. What is great is that Qovery takes care of managing all environment variables for you as well, creates new aliases just as you had in your prod environment, so that everything is really tested separately and it all happens automagically. After the pull request is merged, Qovery automatically cleans up the preview environment to save your money."),Object(i.b)("h3",{id:"testing-preview-environments-pt-ii"},"Testing Preview Environments PT II"),Object(i.b)("p",null,"After a few minutes, your preview environment should be up and running. You can now navigate to the frontend app and click ",Object(i.b)("inlineCode",{parentName:"p"},"Open")," - in the image gallery, you will see an empty list because we don't yet have any images in the database."),Object(i.b)("p",null,"You can add a few images manually by connecting to your mongo instance via CLI. The credentials can be found in the database overview:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/11.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"After connecting, let's add images by executing the following:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"db.createCollection(\"images\")\n\ndb.images.insert([\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n },\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n },\n {\n title: 'IMG_4985.HEIC',\n size: '3.9 MB',\n source:\n 'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',\n }\n ])\n")),Object(i.b)("p",null,"Now, after opening the frontend app in our preview environment, we will see all the images we put in the database! It looks like the feature is working well, so let's merge the PR:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/12.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"What now happens is automatically after the PR merge, the preview environment is automatically cleaned up:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-preview-envs/13.png",alt:"AWS Preview Environments"})),Object(i.b)("p",null,"Great job! Thanks to Qovery Preview Environments, we managed to develop a new feature in a complete separation from our production, we tested it in a real environment deployed in the cloud, and we didn't have to spend any time preparing our environment for tests at all."),Object(i.b)("h3",{id:"conclusion"},"Conclusion"),Object(i.b)("p",null,"In the article, we quickly went through the process of creating a full-stack application with frontend, backend, and database. We enabled the Preview Environment feature to develop new features more quickly. We learned what the benefits of Preview Environments are, how to use them, and how to integrate them to day to day development workflow."))}p.isMDXComponent=!0},423:function(e,n,t){var a;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var c=r.a.createContext({}),p=function(e){var n=r.a.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):l({},n,{},e)),t},u=function(e){var n=p(e.components);return r.a.createElement(c.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},b=Object(a.forwardRef)((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,o=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=p(t),b=a,m=u["".concat(o,".").concat(b)]||u[b]||d[b]||i;return t?r.a.createElement(m,l({ref:n},c,{components:t})):r.a.createElement(m,l({ref:n},c))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=b;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var c=2;c1?arguments[1]:void 0,t),s=o>2?arguments[2]:void 0,c=void 0===s?t:r(s,t);c>l;)n[l++]=e;return n}},428:function(e,n,t){var a=t(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||t(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,n,t){"use strict";t(428);var a=t(0),r=t.n(a),i=t(424);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},430:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),l=t(432),s=t(20),c=t.n(s);n.a=function(e){var n,t=e.to,s=e.href,p=t||s,u=Object(l.a)(p),d=Object(r.useRef)(!1),b=c.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!b&&u&&window.docusaurus.prefetch(p),function(){b&&n&&n.disconnect()}}),[p,b,u]),p&&u?i.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(p),d.current=!0)},innerRef:function(e){var t,a;b&&e&&u&&(t=e,a=function(){window.docusaurus.prefetch(p)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),a())}))}))).observe(t))},to:p})):i.a.createElement("a",Object(a.a)({},e,{href:p}))}},431:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(430),o=t(423),l=t.n(o);t(133);n.a=function(e){var n=e.children,t=e.className,a=e.badge,o=e.leftIcon,s=e.rightIcon,c=e.size,p=e.target,u=e.to,d=l()("jump-to","jump-to--"+c,t),b=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},o&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+o})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",n),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:u,target:p,className:d},b):r.a.createElement(i.a,{to:u,className:d},b)}},432:function(e,n,t){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/a3cf753a.903d9691.js.LICENSE.txt b/a156f6a6.aab2f4d6.js.LICENSE.txt similarity index 100% rename from a3cf753a.903d9691.js.LICENSE.txt rename to a156f6a6.aab2f4d6.js.LICENSE.txt diff --git a/a1fea8fb.ca185edd.js b/a1fea8fb.2563bae5.js similarity index 91% rename from a1fea8fb.ca185edd.js rename to a1fea8fb.2563bae5.js index f2b657f585..e1096b7aeb 100644 --- a/a1fea8fb.ca185edd.js +++ b/a1fea8fb.2563bae5.js @@ -1,2 +1,2 @@ -/*! For license information please see a1fea8fb.ca185edd.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[157],{309:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return s}));var r=n(1),a=n(9),o=(n(0),n(422)),i=(n(421),n(426),n(429),{last_modified_on:"2021-12-17",$schema:"/.meta/.schemas/guides.json",title:"How to use CloudFront with a React frontend application on Qovery",description:"Setting up AWS CloudFront for frontend apps on Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to use CloudFront with a React frontend application on Qovery",description:"Setting up AWS CloudFront for frontend apps on Qovery",permalink:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery",readingTime:"4 min read",source:"@site/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to use CloudFront with a React frontend application on Qovery",truncated:!1,prevItem:{title:"How to seed a Postgres database on a dev environment",permalink:"/guides/tutorial/data-seeding-in-postgres"},nextItem:{title:"How to use Github Organizations with Qovery",permalink:"/guides/tutorial/github-organization-repository-access"}},l=[{value:"Stack",id:"stack",children:[]},{value:"Frontend Application",id:"frontend-application",children:[]},{value:"Deployment",id:"deployment",children:[]},{value:"CloudFront",id:"cloudfront",children:[]}],u={rightToc:l};function s(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"If you'd like to use Cloudflare instead of CloudFront as your CDN, check out ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery/"}),"this article"),".")),Object(o.b)("p",null,"Frontend apps primarily consist of static content which goes unchanged. Web pages that contain static assets are essentially prebuilt, which makes it efficiently quicker to grab and render content. Their static nature makes them a perfect use case for CDNs and caching systems on edge servers is as it boosts the web page performance and user experience with the system."),Object(o.b)("h2",{id:"stack"},"Stack"),Object(o.b)("p",null,"For our frontend stack, we'll use a React app that is served as static files using Nginx."),Object(o.b)("h2",{id:"frontend-application"},"Frontend Application"),Object(o.b)("p",null,"To bootstrap the application skeleton, we use ",Object(o.b)("inlineCode",{parentName:"p"},"create-react-app"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"npx create-react-app my-app\n")),Object(o.b)("p",null,"Then, we add a ",Object(o.b)("inlineCode",{parentName:"p"},"Dockerfile")," to configure how to build the application image:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-docker"}),'FROM node:14-alpine AS builder\nENV NODE_ENV production\n\n# Add a work directory\nWORKDIR /app\n# Cache and Install dependencies\nCOPY package.json .\nCOPY yarn.lock .\nRUN yarn install --production\n# Copy app files\nCOPY . .\n# Build the app\nRUN yarn build\n\n# Bundle static assets with nginx\nFROM nginx:1.21.0-alpine as production\nENV NODE_ENV production\n# Copy built assets from builder\nCOPY --from=builder /app/build /usr/share/nginx/html\n# Add your nginx.conf\nCOPY nginx.conf /etc/nginx/conf.d/default.conf\n# Expose port\nEXPOSE 80\n# Start nginx\nCMD ["nginx", "-g", "daemon off;"]\n')),Object(o.b)("p",null,"The last step - let's configure our Nginx server by adding a ",Object(o.b)("inlineCode",{parentName:"p"},"nginx.conf")," file with the following content:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"server {\n listen 80;\n\n location / {\n root /usr/share/nginx/html/;\n include /etc/nginx/mime.types;\n try_files $uri $uri/ /index.html;\n }\n}\n")),Object(o.b)("h2",{id:"deployment"},"Deployment"),Object(o.b)("p",null,"Now, to deploy the app, create a new application on Qovery with the following configuration:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Port - ",Object(o.b)("inlineCode",{parentName:"li"},"80")),Object(o.b)("li",{parentName:"ul"},"Build Mode - ",Object(o.b)("inlineCode",{parentName:"li"},"Docker")),Object(o.b)("li",{parentName:"ul"},"Keep other options in default settings")),Object(o.b)("p",null,"After the app is created and configured as above, you can safely run the app deployment. After a few minutes when the app is running, click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Open")," button:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/1.png",alt:"CloudFront"})),Object(o.b)("h2",{id:"cloudfront"},"CloudFront"),Object(o.b)("p",null,"To set up CloudFront as a CDN, first, navigate to CloudFront service in AWS console and click on the new distribution button:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/2.png",alt:"CloudFront"})),Object(o.b)("p",null,"In settings, choose an origin (URL to your frontend app hosted on Qovery):"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/3.png",alt:"CloudFront"})),Object(o.b)("p",null,"You can also tweak other settings or leave them in their defaults:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/4.png",alt:"CloudFront"})),Object(o.b)("p",null,"Additionally, you can assign an alternate domain to your application in ",Object(o.b)("inlineCode",{parentName:"p"},"Alternate domain name"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/5.png",alt:"CloudFront"})),Object(o.b)("p",null,"Adding an alternate domain requires it having a certificate - click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Request certificate")," button, type your alternate domain name and use DNS for validation method:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/6.png",alt:"CloudFront"})),Object(o.b)("p",null,"Request the certificate. In the end, you will see a screen with settings you need to set up in your domain name provider:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/7.png",alt:"CloudFront"})),Object(o.b)("p",null,"Copy them and save them in your DNS provider settings:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/8.png",alt:"CloudFront"})),Object(o.b)("p",null,"After it's done, you should be granted a certificate - go back to CloudFront Distribution settings, and pick the certificate for your alternate domain name from the list:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/9.png",alt:"CloudFront"})),Object(o.b)("p",null,"In the end, you should end up with a CloudFront set up with your app on Qovery and using an alternate domain name. Now it's time for you to tweak the CloudFront settings to meet your needs."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/10.png",alt:"CloudFront"})))}s.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),b=r,f=p["".concat(i,".").concat(b)]||p[b]||d[b]||o;return n?a.a.createElement(f,c({ref:t},u,{components:n})):a.a.createElement(f,c({ref:t},u))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(430),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,p=Object(c.a)(s),d=Object(a.useRef)(!1),b=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!b&&p&&window.docusaurus.prefetch(s),function(){b&&t&&t.disconnect()}}),[s,b,p]),s&&p?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(s),d.current=!0)},innerRef:function(e){var n,r;b&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:s})):o.a.createElement("a",Object(r.a)({},e,{href:s}))}},429:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,p=e.to,d=c()("jump-to","jump-to--"+u,n),b=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?a.a.createElement("a",{href:p,target:s,className:d},b):a.a.createElement(o.a,{to:p,className:d},b)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file +/*! For license information please see a1fea8fb.2563bae5.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[160],{312:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return s}));var r=n(1),a=n(9),o=(n(0),n(425)),i=(n(424),n(429),n(431),{last_modified_on:"2021-12-17",$schema:"/.meta/.schemas/guides.json",title:"How to use CloudFront with a React frontend application on Qovery",description:"Setting up AWS CloudFront for frontend apps on Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to use CloudFront with a React frontend application on Qovery",description:"Setting up AWS CloudFront for frontend apps on Qovery",permalink:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery",readingTime:"4 min read",source:"@site/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to use CloudFront with a React frontend application on Qovery",truncated:!1,prevItem:{title:"How to seed a Postgres database on a dev environment",permalink:"/guides/tutorial/data-seeding-in-postgres"},nextItem:{title:"How to use Github Organizations with Qovery",permalink:"/guides/tutorial/github-organization-repository-access"}},l=[{value:"Stack",id:"stack",children:[]},{value:"Frontend Application",id:"frontend-application",children:[]},{value:"Deployment",id:"deployment",children:[]},{value:"CloudFront",id:"cloudfront",children:[]}],u={rightToc:l};function s(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"If you'd like to use Cloudflare instead of CloudFront as your CDN, check out ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery/"}),"this article"),".")),Object(o.b)("p",null,"Frontend apps primarily consist of static content which goes unchanged. Web pages that contain static assets are essentially prebuilt, which makes it efficiently quicker to grab and render content. Their static nature makes them a perfect use case for CDNs and caching systems on edge servers is as it boosts the web page performance and user experience with the system."),Object(o.b)("h2",{id:"stack"},"Stack"),Object(o.b)("p",null,"For our frontend stack, we'll use a React app that is served as static files using Nginx."),Object(o.b)("h2",{id:"frontend-application"},"Frontend Application"),Object(o.b)("p",null,"To bootstrap the application skeleton, we use ",Object(o.b)("inlineCode",{parentName:"p"},"create-react-app"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"npx create-react-app my-app\n")),Object(o.b)("p",null,"Then, we add a ",Object(o.b)("inlineCode",{parentName:"p"},"Dockerfile")," to configure how to build the application image:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-docker"}),'FROM node:14-alpine AS builder\nENV NODE_ENV production\n\n# Add a work directory\nWORKDIR /app\n# Cache and Install dependencies\nCOPY package.json .\nCOPY yarn.lock .\nRUN yarn install --production\n# Copy app files\nCOPY . .\n# Build the app\nRUN yarn build\n\n# Bundle static assets with nginx\nFROM nginx:1.21.0-alpine as production\nENV NODE_ENV production\n# Copy built assets from builder\nCOPY --from=builder /app/build /usr/share/nginx/html\n# Add your nginx.conf\nCOPY nginx.conf /etc/nginx/conf.d/default.conf\n# Expose port\nEXPOSE 80\n# Start nginx\nCMD ["nginx", "-g", "daemon off;"]\n')),Object(o.b)("p",null,"The last step - let's configure our Nginx server by adding a ",Object(o.b)("inlineCode",{parentName:"p"},"nginx.conf")," file with the following content:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"server {\n listen 80;\n\n location / {\n root /usr/share/nginx/html/;\n include /etc/nginx/mime.types;\n try_files $uri $uri/ /index.html;\n }\n}\n")),Object(o.b)("h2",{id:"deployment"},"Deployment"),Object(o.b)("p",null,"Now, to deploy the app, create a new application on Qovery with the following configuration:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Port - ",Object(o.b)("inlineCode",{parentName:"li"},"80")),Object(o.b)("li",{parentName:"ul"},"Build Mode - ",Object(o.b)("inlineCode",{parentName:"li"},"Docker")),Object(o.b)("li",{parentName:"ul"},"Keep other options in default settings")),Object(o.b)("p",null,"After the app is created and configured as above, you can safely run the app deployment. After a few minutes when the app is running, click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Open")," button:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/1.png",alt:"CloudFront"})),Object(o.b)("h2",{id:"cloudfront"},"CloudFront"),Object(o.b)("p",null,"To set up CloudFront as a CDN, first, navigate to CloudFront service in AWS console and click on the new distribution button:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/2.png",alt:"CloudFront"})),Object(o.b)("p",null,"In settings, choose an origin (URL to your frontend app hosted on Qovery):"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/3.png",alt:"CloudFront"})),Object(o.b)("p",null,"You can also tweak other settings or leave them in their defaults:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/4.png",alt:"CloudFront"})),Object(o.b)("p",null,"Additionally, you can assign an alternate domain to your application in ",Object(o.b)("inlineCode",{parentName:"p"},"Alternate domain name"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/5.png",alt:"CloudFront"})),Object(o.b)("p",null,"Adding an alternate domain requires it having a certificate - click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Request certificate")," button, type your alternate domain name and use DNS for validation method:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/6.png",alt:"CloudFront"})),Object(o.b)("p",null,"Request the certificate. In the end, you will see a screen with settings you need to set up in your domain name provider:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/7.png",alt:"CloudFront"})),Object(o.b)("p",null,"Copy them and save them in your DNS provider settings:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/8.png",alt:"CloudFront"})),Object(o.b)("p",null,"After it's done, you should be granted a certificate - go back to CloudFront Distribution settings, and pick the certificate for your alternate domain name from the list:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/9.png",alt:"CloudFront"})),Object(o.b)("p",null,"In the end, you should end up with a CloudFront set up with your app on Qovery and using an alternate domain name. Now it's time for you to tweak the CloudFront settings to meet your needs."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudfront/10.png",alt:"CloudFront"})))}s.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),b=r,f=p["".concat(i,".").concat(b)]||p[b]||d[b]||o;return n?a.a.createElement(f,c({ref:t},u,{components:n})):a.a.createElement(f,c({ref:t},u))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(432),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,p=Object(c.a)(s),d=Object(a.useRef)(!1),b=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!b&&p&&window.docusaurus.prefetch(s),function(){b&&t&&t.disconnect()}}),[s,b,p]),s&&p?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(s),d.current=!0)},innerRef:function(e){var n,r;b&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:s})):o.a.createElement("a",Object(r.a)({},e,{href:s}))}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,p=e.to,d=c()("jump-to","jump-to--"+u,n),b=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?a.a.createElement("a",{href:p,target:s,className:d},b):a.a.createElement(o.a,{to:p,className:d},b)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/a4401f0f.1cd779ba.js.LICENSE.txt b/a1fea8fb.2563bae5.js.LICENSE.txt similarity index 100% rename from a4401f0f.1cd779ba.js.LICENSE.txt rename to a1fea8fb.2563bae5.js.LICENSE.txt diff --git a/a264e41a.2549591b.js b/a264e41a.dd5aa035.js similarity index 73% rename from a264e41a.2549591b.js rename to a264e41a.dd5aa035.js index a47d1e0a4a..8c1049d977 100644 --- a/a264e41a.2549591b.js +++ b/a264e41a.dd5aa035.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[158],{310:function(a){a.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"framework-rails","name":"framework: rails","count":1,"permalink":"/guides/tags/framework-rails"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[161],{313:function(a){a.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"framework-rails","name":"framework: rails","count":1,"permalink":"/guides/tags/framework-rails"}')}}]); \ No newline at end of file diff --git a/a3cf753a.903d9691.js b/a3cf753a.4cb494e4.js similarity index 96% rename from a3cf753a.903d9691.js rename to a3cf753a.4cb494e4.js index c8777a8245..65fa4584fd 100644 --- a/a3cf753a.903d9691.js +++ b/a3cf753a.4cb494e4.js @@ -1,2 +1,2 @@ -/*! For license information please see a3cf753a.903d9691.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[159],{311:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return s})),t.d(n,"metadata",(function(){return p})),t.d(n,"rightToc",(function(){return b})),t.d(n,"default",(function(){return u}));var i=t(1),r=t(9),a=(t(0),t(422)),o=t(431),l=t(421),c=t(426),s={last_modified_on:"2022-02-02",$schema:"/.meta/.schemas/guides.json",title:"Deploy Rails with PostgreSQL and Sidekiq",description:"How to deploy a Rails application with the PostgreSQL database and Sidekiq workers",author_github:"https://github.com/l0ck3",tags:["type: tutorial","framework: rails","language: ruby","database: postgresql"],hide_pagination:!0},p={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Deploy Rails with PostgreSQL and Sidekiq",description:"How to deploy a Rails application with the PostgreSQL database and Sidekiq workers",permalink:"/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq",readingTime:"11 min read",source:"@site/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"framework: rails",permalink:"/guides/tags/framework-rails"},{label:"language: ruby",permalink:"/guides/tags/language-ruby"},{label:"database: postgresql",permalink:"/guides/tags/database-postgresql"}],title:"Deploy Rails with PostgreSQL and Sidekiq",truncated:!1,prevItem:{title:"Deploy Frontend App",permalink:"/guides/advanced/deploy-frontend"},nextItem:{title:"Deploy Temporal on Kubernetes",permalink:"/guides/tutorial/deploy-temporal-on-kubernetes"}},b=[{value:"Goal",id:"goal",children:[]},{value:"Prepare your Rails application",id:"prepare-your-rails-application",children:[]},{value:"Deploy your application to Qovery",id:"deploy-your-application-to-qovery",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],d={rightToc:b};function u(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(i.a)({},d,t,{components:n,mdxType:"MDXLayout"}),Object(a.b)(c.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have a Qovery cluster ready"))),Object(a.b)("h2",{id:"goal"},"Goal"),Object(a.b)("p",null,"In this tutorial we will deploy a typical Rails 6 application, using PostgreSQL as a database and Sidekiq as an ActiveJob backend for background tasks."),Object(a.b)("h2",{id:"prepare-your-rails-application"},"Prepare your Rails application"),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"If you don't have a Rails 6 application at hand, you can clone this demo app: https://github.com/Qovery/qovery-rails-full-application-example"),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Qovery doesn't support Procfiles with multiple processes yet. We'll have to use Dockerfiles for both the web application and Sidekiq workers.",Object(a.b)("br",null),"Qovery doesn't support overriding Docker command yet, so we'll use two different Dockerfiles."),Object(a.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"web-application-dockerfile"},"Web application Dockerfile"),Object(a.b)("p",null,"Add a ",Object(a.b)("inlineCode",{parentName:"p"},"Dockerfile")," file at the root of your application with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{className:"language-Dockerfile"}),'FROM ruby:3.0.2-alpine3.13 AS builder\n\n# Minimal requirements to run a Rails app\nRUN apk add --no-cache --update build-base \\\n linux-headers \\\n git \\\n postgresql-dev=~13 \\\n # Rails SQL schema format requires `pg_dump(1)` and `psql(1)`\n postgresql=~13 \\\n # Install same version of pg_dump\n postgresql-client=~13 \\\n nodejs \\\n yarn \\\n # Needed for nodejs / node-gyp\n python2 \\\n tzdata\n\n \nENV BUNDLER_VERSION 2.2.24\nENV BUNDLE_JOBS 8\nENV BUNDLE_RETRY 5\nENV BUNDLE_WITHOUT development:test\nENV BUNDLE_CACHE_ALL true\nENV RAILS_ENV production\nENV RACK_ENV production\nENV NODE_ENV production\nENV APP_PATH /work\n\nWORKDIR $APP_PATH\n\n# Gems installation\nCOPY Gemfile Gemfile.lock ./\nRUN gem install bundler -v $BUNDLER_VERSION\n\nRUN bundle config --global frozen 1 && \\\n bundle install && \\\n rm -rf /usr/local/bundle/cache/*.gem && \\\n find /usr/local/bundle/gems/ -name "*.c" -delete && \\\n find /usr/local/bundle/gems/ -name "*.o" -delete\n\n \n\n# NPM packages installation\nCOPY package.json yarn.lock ./\nRUN yarn install --frozen-lockfile --non-interactive --production\n\nADD . $APP_PATH\n\nRUN SECRET_KEY_BASE=`bin/rake secret` rails assets:precompile --trace && \\\n yarn cache clean && \\\n rm -rf node_modules tmp/cache vendor/assets test\n\n \nFROM ruby:3.0.2-alpine3.13\n\nRUN mkdir -p /work\nWORKDIR /work\n\nENV RAILS_ENV production\nENV NODE_ENV production\nENV RAILS_SERVE_STATIC_FILES true\n\n# Some native extensions required by gems such as pg or mysql2.\nCOPY --from=builder /usr/lib /usr/lib\n\n# Timezone data is required at runtime\nCOPY --from=builder /usr/share/zoneinfo/ /usr/share/zoneinfo/\n\n# Ruby gems\nCOPY --from=builder /usr/local/bundle /usr/local/bundle\nCOPY --from=builder /work /work\n\nCOPY docker-entrypoint.sh ./\nENTRYPOINT ["./docker-entrypoint.sh"]\n\nEXPOSE 3000\n\nCMD ["rails", "server", "-p", "3000", "-b", "0.0.0.0"]\n')),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"You can tweak the versions if you are using a different version of Ruby, Bundler, PostgreSQL ...")),Object(a.b)("li",null,Object(a.b)("h4",{id:"sidekiq-dockerfile"},"Sidekiq Dockerfile"),Object(a.b)("p",null,"We'll use a similar Dockerfile for our Sidekiq worker.\nCreate a ",Object(a.b)("inlineCode",{parentName:"p"},"Dockerfile.sidekiq")," at the root of your repository with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{className:"language-Dockerfile"}),'FROM ruby:3.0.2-alpine3.13 AS builder\n\nLABEL maintener=\'yirbah@qovery.com\'\n\n# Minimal requirements to run a Rails app\nRUN apk add --no-cache --update build-base \\\n linux-headers \\\n git \\\n postgresql-dev=~13 \\\n # Rails SQL schema format requires `pg_dump(1)` and `psql(1)`\n postgresql=~13 \\\n # Install same version of pg_dump\n postgresql-client=~13 \\\n nodejs \\\n yarn \\\n # Needed for nodejs / node-gyp\n python2 \\\n tzdata\n\nENV BUNDLER_VERSION 2.2.24\nENV BUNDLE_JOBS 8\nENV BUNDLE_RETRY 5\nENV BUNDLE_WITHOUT development:test\nENV BUNDLE_CACHE_ALL true\nENV RAILS_ENV production\nENV RACK_ENV production\nENV NODE_ENV production\nENV APP_PATH /work\n\nWORKDIR $APP_PATH\n\n# Gems installation\nCOPY Gemfile Gemfile.lock ./\n\nRUN gem install bundler -v $BUNDLER_VERSION\n\nRUN bundle config --global frozen 1 && \\\n bundle install && \\\n rm -rf /usr/local/bundle/cache/*.gem && \\\n find /usr/local/bundle/gems/ -name "*.c" -delete && \\\n find /usr/local/bundle/gems/ -name "*.o" -delete\n\n# NPM packages installation\nCOPY package.json yarn.lock ./\n\nRUN yarn install --frozen-lockfile --non-interactive --production\n\nADD . $APP_PATH\n\nRUN SECRET_KEY_BASE=`bin/rake secret` rails assets:precompile --trace && \\\n yarn cache clean && \\\n rm -rf node_modules tmp/cache vendor/assets test\n\nFROM ruby:3.0.2-alpine3.13\n\nRUN mkdir -p /work\nWORKDIR /work\n\nENV RAILS_ENV production\nENV NODE_ENV production\nENV RAILS_SERVE_STATIC_FILES true\n\n# Some native extensions required by gems such as pg or mysql2.\nCOPY --from=builder /usr/lib /usr/lib\n\n# Timezone data is required at runtime\nCOPY --from=builder /usr/share/zoneinfo/ /usr/share/zoneinfo/\n\n# Ruby gems\nCOPY --from=builder /usr/local/bundle /usr/local/bundle\n\nCOPY --from=builder /work /work\n\nCOPY docker-entrypoint.sh ./\n\n\nCMD ["bundle", "exec", "sidekiq"]\n'))),Object(a.b)("li",null,Object(a.b)("h4",{id:"dockerignore"},"Dockerignore"),Object(a.b)("p",null,"In order to avoid unneeded files being copied to your Docker image, you can add a ",Object(a.b)("inlineCode",{parentName:"p"},".dockerignore")," file to the root of your project, with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{}),"# See https://help.github.com/articles/ignoring-files for more about ignoring files.\n#\n# If you find yourself ignoring temporary files generated by your text editor\n# or operating system, you probably want to add a global ignore instead:\n# git config --global core.excludesfile '~/.gitignore_global'\n\n# Ignore bundler config.\n/.bundle\n\n# Ignore all logfiles and tempfiles.\n/log/*\n/tmp/*\n!/log/.keep\n!/tmp/.keep\n\n# Ignore pidfiles, but keep the directory.\n/tmp/pids/*\n!/tmp/pids/\n!/tmp/pids/.keep\n\n# Ignore uploaded files in development.\n/storage/*\n!/storage/.keep\n/public/assets\n.byebug_history\n\n# Ignore master key for decrypting credentials and more.\n/config/master.key\n/public/packs\n/public/packs-test\n/node_modules\n/yarn-error.log\nyarn-debug.log*\n.yarn-integrity\n")),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"You can customize this file for the needs of your project. Add any file that is not useful for the runtime of your application.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"docker-entrypoint"},"Docker entrypoint"),Object(a.b)("p",null,"Finally we will add an entrypoint script that will be called at the start of the application.\nWe'll use it to run the database setup and migration commands."),Object(a.b)("p",null,"You can read more about why this entrypoint is needed ",Object(a.b)("a",Object(i.a)({parentName:"p"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"here"),". "),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"Soon Qovery will add lifecycle hooks and this won't be needed anymore"),Object(a.b)("p",null,"Add a ",Object(a.b)("inlineCode",{parentName:"p"},"docker-entrypoint.sh")," file at the root of your project with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{className:"language-bash"}),'#! /bin/sh\n\nbundle exec rake db:migrate\n\nif [[ $? != 0 ]]; then\n\necho\necho "== Failed to migrate. Running setup first."\necho\n\nbundle exec rake db:setup\nfi\n\n# Execute the given or default command:\n\nexec "$@"\n')),Object(a.b)("p",null,"Make this script executable: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{}),"chmod +x docker-entrypoint.sh\n"))))),Object(a.b)("h2",{id:"deploy-your-application-to-qovery"},"Deploy your application to Qovery"),Object(a.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"create-a-project"},"Create a project"),Object(a.b)("p",null,"Now that your Rails application is ready to be dockerized, we can create a project on the Qovery console:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/01.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"create-an-environment"},"Create an environment"),Object(a.b)("p",null,"Now we'll create an environment. Let's start with our ",Object(a.b)("inlineCode",{parentName:"p"},"staging")," environment:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/02.png",alt:"Qovery console"})),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/03.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-your-rails-app"},"Add your Rails app"),Object(a.b)("p",null,"We'll now add our Rails app to the environment: "),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/04.png",alt:"Qovery console"})),Object(a.b)("p",null,"On the form you'll need to enter the following information:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"The app name: it can be whatever you want. Here ",Object(a.b)("inlineCode",{parentName:"li"},"web"),"."),Object(a.b)("li",{parentName:"ul"},"Pick your Git privider, then the repository for your application"),Object(a.b)("li",{parentName:"ul"},"The branch you want to deploy for this application. We chose ",Object(a.b)("inlineCode",{parentName:"li"},"main")),Object(a.b)("li",{parentName:"ul"},"The Root application path. In case your application is not at the root of your repository (e.g. you have a monorepo), otherwise it will be ",Object(a.b)("inlineCode",{parentName:"li"},"/"),"."),Object(a.b)("li",{parentName:"ul"},"For the Build mode, pick ",Object(a.b)("inlineCode",{parentName:"li"},"Dockerfile"),"."),Object(a.b)("li",{parentName:"ul"},"Enter the path to your Dockerfile.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/05.png",alt:"Qovery console"})),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/06.png",alt:"Qovery console"})),Object(a.b)("p",null,"You can then click ",Object(a.b)("inlineCode",{parentName:"p"},"Create"),". You'll be redirected to your application dashboard."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/07.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"Your application is not being deployed yet. We'll add the database and do some more configuration before.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-a-postgresql-database"},"Add a PostgreSQL database"),Object(a.b)("p",null,"Our application will use a PostgreSQL database. Let's add one to our environment:"),Object(a.b)("p",null,"Click on ",Object(a.b)("inlineCode",{parentName:"p"},"ADD"),", then ",Object(a.b)("inlineCode",{parentName:"p"},"Database")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/08.png",alt:"Qovery console"})),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Give a name to your database."),Object(a.b)("li",{parentName:"ul"},"For the Type, select ",Object(a.b)("inlineCode",{parentName:"li"},"POSTGRESQL"),"."),Object(a.b)("li",{parentName:"ul"},"For the Mode, we'll pick ",Object(a.b)("inlineCode",{parentName:"li"},"CONTAINER"),"."),Object(a.b)("li",{parentName:"ul"},"Chose the Version you need.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/09.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Since we are creating a Staging environment, we used the CONTAINER mode. This is not recommended for Production. In Production environment you should go for the MANAGED option."),Object(a.b)("p",null,"You can then click ",Object(a.b)("inlineCode",{parentName:"p"},"Create"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-a-redis-database"},"Add a Redis database"),Object(a.b)("p",null,"Since we're using Sidekiq, we'll also need a Redis database as a backend."),Object(a.b)("p",null,"If you didn't close the ",Object(a.b)("inlineCode",{parentName:"p"},"Database")," modal, you can click the ",Object(a.b)("inlineCode",{parentName:"p"},"ADD")," button, then in the dropbox for ",Object(a.b)("inlineCode",{parentName:"p"},"Database 2")," click ",Object(a.b)("inlineCode",{parentName:"p"},"Create database"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/10.png",alt:"Qovery console"})),Object(a.b)("p",null,"Fill the form the same way you did for PostgreSQL:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/11.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Since we are creating a Staging environment, we used the CONTAINER mode. This is not recommended for Production. In Production environment you should go for the MANAGED option."),Object(a.b)("p",null,"Click ",Object(a.b)("inlineCode",{parentName:"p"},"Create")," and close the Databases modal."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/12.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"configure-your-application-env-variables"},"Configure your application ENV variables"),Object(a.b)("p",null,"Go back to your environment view:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/13.png",alt:"Qovery console"})),Object(a.b)("p",null,"Then click on your application:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/14.png",alt:"Qovery console"})),Object(a.b)("p",null,"On your application dashboard, go to ",Object(a.b)("inlineCode",{parentName:"p"},"Environment variables"),":"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/15.png",alt:"Qovery console"})),Object(a.b)("p",null,"Here you can add any environment variable your application needs."),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Since we are creating a Staging environment, we used the CONTAIWe do not advise you to add secret values here. For sensitive information, like credentials, use the Secret variables, which are encrypted."),Object(a.b)("p",null,"We'll now configure a few secrets for our application. Click on the ",Object(a.b)("inlineCode",{parentName:"p"},"Secret variables")," tab:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/16.png",alt:"Qovery console"})),Object(a.b)("p",null,"First since our Demo application uses the Rails Encrypted Secrets, we'll add the ",Object(a.b)("inlineCode",{parentName:"p"},"RAILS_MASTER_KEY")," secret\nClick on ",Object(a.b)("inlineCode",{parentName:"p"},"CREATE SECRET"),", then fill the form:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Variable: enter the variable name, ",Object(a.b)("inlineCode",{parentName:"li"},"RAILS_MASTER_KEY"),"."),Object(a.b)("li",{parentName:"ul"},"Value: enter the actual value for your ",Object(a.b)("inlineCode",{parentName:"li"},"RAILS_MASTER_KEY"),"."),Object(a.b)("li",{parentName:"ul"},"Scope: chose ",Object(a.b)("inlineCode",{parentName:"li"},"ENVIRONMENT")," since the secret will be used by our Sidekiq worker too.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/17.png",alt:"Qovery console"})),Object(a.b)("p",null,"Now we'll need to add the ",Object(a.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," and ",Object(a.b)("inlineCode",{parentName:"p"},"REDIS_URL"),", that Rails will use to connect to PostgreSQL and Redis. Those are secrets as well, since the URLs contain passwords."),Object(a.b)("p",null,"But instead of creating new secrets like we did for the ",Object(a.b)("inlineCode",{parentName:"p"},"RAILS_MASTER_KEY"),", we'll use aliases. Aliases are just a way of giving a different name to an existing ENV variable or secret.\nSince Qovery provides us with the secrets corresponding to the two databases we created earlier, we can alias them."),Object(a.b)("p",null,"First, create an alias to the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_POSTGRESQL_ZXXXXXXXX_DATABASE_URL_INTERNAL"),":"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/18.png",alt:"Qovery console"})),Object(a.b)("p",null,"In the form, chose ",Object(a.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," for the alias name and set it at the ",Object(a.b)("inlineCode",{parentName:"p"},"ENVIRONMENT")," level:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/19.png",alt:"Qovery console"})),Object(a.b)("p",null,"Click ",Object(a.b)("inlineCode",{parentName:"p"},"Create")," then do the same thing with a ",Object(a.b)("inlineCode",{parentName:"p"},"REDIS_URL")," alias to the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_REDIS_ZXXXXXXXX_DATABASE_URL_INTERNAL"),"."),Object(a.b)("p",null,"You should see your two aliases created:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/20.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"These are the secrets required for our demo application. Yours might need more. Add all the variables you need before going to the next step.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"deploy-the-environment"},"Deploy the environment"),Object(a.b)("p",null,"Go back to the ",Object(a.b)("inlineCode",{parentName:"p"},"staging")," environment view and deploy it:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/21.png",alt:"Qovery console"})),Object(a.b)("p",null,"You should see it switch to the ",Object(a.b)("inlineCode",{parentName:"p"},"DEPLOYING")," status. Wait until the status turns to ",Object(a.b)("inlineCode",{parentName:"p"},"RUNNING"),". "),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"The first deployment could take a while."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/22.png",alt:"Qovery console"})),Object(a.b)("p",null,"Once your environment is ",Object(a.b)("inlineCode",{parentName:"p"},"RUNNING"),", open the ",Object(a.b)("inlineCode",{parentName:"p"},"web")," application to see if it works. It will open a new tab showing your application."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/23.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-the-sidekiq-worker"},"Add the Sidekiq worker"),Object(a.b)("p",null,"The last step is to add your Sidekiq Worker. We'll follow the same steps as in the ",Object(a.b)("inlineCode",{parentName:"p"},"Add your Rails app")," section with a few differences:"),Object(a.b)("p",null,"Add a new application:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/24.png",alt:"Qovery console"})),Object(a.b)("p",null,"The settigs are the same as for the Rails application, except:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"We use the ",Object(a.b)("inlineCode",{parentName:"li"},"Dockerfile.sidekiq")," Dockerfile this time"),Object(a.b)("li",{parentName:"ul"},"We don't declare a port since our worker is not a web service but communicates with our application through Redis.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/25.png",alt:"Qovery console"})),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/26.png",alt:"Qovery console"})),Object(a.b)("p",null,"Click ",Object(a.b)("inlineCode",{parentName:"p"},"Create"),"."),Object(a.b)("p",null,"If we check the ENV variables and secrets, we notice that it directly inherited the ones we set at the ",Object(a.b)("inlineCode",{parentName:"p"},"Environment")," level. So we don't need to do the configuration again."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/27.png",alt:"Qovery console"})),Object(a.b)("p",null,"You can now deploy your ",Object(a.b)("inlineCode",{parentName:"p"},"worker")," application:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/28.png",alt:"Qovery console"})),Object(a.b)("p",null,"Wait for it to switch to the ",Object(a.b)("inlineCode",{parentName:"p"},"RUNNING")," status.")))),Object(a.b)("h2",{id:"conclusion"},"Conclusion"),Object(a.b)("p",null,"You now have a Rails application with PostgreSQL and Sidekiq running on Qovery. "),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Depending on the gems you are using, their versions or your application configuration, you might need to tweak the Dockerfiles provided.",Object(a.b)("br",null),"This example is meant to be a starting point for your own configuration, not a one-size-fits-all configuration."))}u.isMDXComponent=!0},420:function(e,n,t){var i;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=r.a.createContext({}),p=function(e){var n=r.a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):l({},n,{},e)),t},b=function(e){var n=p(e.components);return r.a.createElement(s.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},u=Object(i.forwardRef)((function(e,n){var t=e.components,i=e.mdxType,a=e.originalType,o=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),b=p(t),u=i,m=b["".concat(o,".").concat(u)]||b[u]||d[u]||a;return t?r.a.createElement(m,l({ref:n},s,{components:t})):r.a.createElement(m,l({ref:n},s))}));function m(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var a=t.length,o=new Array(a);o[0]=u;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l.mdxType="string"==typeof e?e:i,o[1]=l;for(var s=2;s1?arguments[1]:void 0,t),c=o>2?arguments[2]:void 0,s=void 0===c?t:r(c,t);s>l;)n[l++]=e;return n}},425:function(e,n,t){var i=t(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||t(10)&&i(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,n,t){"use strict";t(425);var i=t(0),r=t.n(i),a=t(421);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},428:function(e,n,t){"use strict";var i=t(432),r=t(51);function a(e,n){return n.encode?n.strict?i(e):encodeURIComponent(e):e}n.extract=function(e){return e.split("?")[1]||""},n.parse=function(e,n){var t=function(e){var n;switch(e.arrayFormat){case"index":return function(e,t,i){n=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),n?(void 0===i[e]&&(i[e]={}),i[e][n[1]]=t):i[e]=t};case"bracket":return function(e,t,i){n=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),n?void 0!==i[e]?i[e]=[].concat(i[e],t):i[e]=[t]:i[e]=t};default:return function(e,n,t){void 0!==t[e]?t[e]=[].concat(t[e],n):t[e]=n}}}(n=r({arrayFormat:"none"},n)),i=Object.create(null);return"string"!=typeof e?i:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var n=e.replace(/\+/g," ").split("="),r=n.shift(),a=n.length>0?n.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),t(decodeURIComponent(r),a,i)})),Object.keys(i).sort().reduce((function(e,n){var t=i[n];return Boolean(t)&&"object"==typeof t&&!Array.isArray(t)?e[n]=function e(n){return Array.isArray(n)?n.sort():"object"==typeof n?e(Object.keys(n)).sort((function(e,n){return Number(e)-Number(n)})).map((function(e){return n[e]})):n}(t):e[n]=t,e}),Object.create(null))):i},n.stringify=function(e,n){var t=function(e){switch(e.arrayFormat){case"index":return function(n,t,i){return null===t?[a(n,e),"[",i,"]"].join(""):[a(n,e),"[",a(i,e),"]=",a(t,e)].join("")};case"bracket":return function(n,t){return null===t?a(n,e):[a(n,e),"[]=",a(t,e)].join("")};default:return function(n,t){return null===t?a(n,e):[a(n,e),"=",a(t,e)].join("")}}}(n=r({encode:!0,strict:!0,arrayFormat:"none"},n));return e?Object.keys(e).sort().map((function(i){var r=e[i];if(void 0===r)return"";if(null===r)return a(i,n);if(Array.isArray(r)){var o=[];return r.slice().forEach((function(e){void 0!==e&&o.push(t(i,e,o.length))})),o.join("&")}return a(i,n)+"="+a(r,n)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,n,t){"use strict";var i=t(0),r=t.n(i),a=(t(420),t(428)),o=t.n(a);t(134);n.a=function(e){var n=e.children,t=e.headingDepth,a=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,c={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+o.a.stringify(c),p=Object(i.useState)(null),b=p[0],d=p[1];return r.a.createElement("div",{className:"steps steps--h"+t},n,!a&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,n,t){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see a3cf753a.4cb494e4.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[162],{314:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return s})),t.d(n,"metadata",(function(){return p})),t.d(n,"rightToc",(function(){return b})),t.d(n,"default",(function(){return u}));var i=t(1),r=t(9),a=(t(0),t(425)),o=t(434),l=t(424),c=t(429),s={last_modified_on:"2022-02-02",$schema:"/.meta/.schemas/guides.json",title:"Deploy Rails with PostgreSQL and Sidekiq",description:"How to deploy a Rails application with the PostgreSQL database and Sidekiq workers",author_github:"https://github.com/l0ck3",tags:["type: tutorial","framework: rails","language: ruby","database: postgresql"],hide_pagination:!0},p={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Deploy Rails with PostgreSQL and Sidekiq",description:"How to deploy a Rails application with the PostgreSQL database and Sidekiq workers",permalink:"/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq",readingTime:"11 min read",source:"@site/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"framework: rails",permalink:"/guides/tags/framework-rails"},{label:"language: ruby",permalink:"/guides/tags/language-ruby"},{label:"database: postgresql",permalink:"/guides/tags/database-postgresql"}],title:"Deploy Rails with PostgreSQL and Sidekiq",truncated:!1,prevItem:{title:"Deploy Frontend App",permalink:"/guides/advanced/deploy-frontend"},nextItem:{title:"Deploy Temporal on Kubernetes",permalink:"/guides/tutorial/deploy-temporal-on-kubernetes"}},b=[{value:"Goal",id:"goal",children:[]},{value:"Prepare your Rails application",id:"prepare-your-rails-application",children:[]},{value:"Deploy your application to Qovery",id:"deploy-your-application-to-qovery",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],d={rightToc:b};function u(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(i.a)({},d,t,{components:n,mdxType:"MDXLayout"}),Object(a.b)(c.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have a Qovery cluster ready"))),Object(a.b)("h2",{id:"goal"},"Goal"),Object(a.b)("p",null,"In this tutorial we will deploy a typical Rails 6 application, using PostgreSQL as a database and Sidekiq as an ActiveJob backend for background tasks."),Object(a.b)("h2",{id:"prepare-your-rails-application"},"Prepare your Rails application"),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"If you don't have a Rails 6 application at hand, you can clone this demo app: https://github.com/Qovery/qovery-rails-full-application-example"),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Qovery doesn't support Procfiles with multiple processes yet. We'll have to use Dockerfiles for both the web application and Sidekiq workers.",Object(a.b)("br",null),"Qovery doesn't support overriding Docker command yet, so we'll use two different Dockerfiles."),Object(a.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"web-application-dockerfile"},"Web application Dockerfile"),Object(a.b)("p",null,"Add a ",Object(a.b)("inlineCode",{parentName:"p"},"Dockerfile")," file at the root of your application with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{className:"language-Dockerfile"}),'FROM ruby:3.0.2-alpine3.13 AS builder\n\n# Minimal requirements to run a Rails app\nRUN apk add --no-cache --update build-base \\\n linux-headers \\\n git \\\n postgresql-dev=~13 \\\n # Rails SQL schema format requires `pg_dump(1)` and `psql(1)`\n postgresql=~13 \\\n # Install same version of pg_dump\n postgresql-client=~13 \\\n nodejs \\\n yarn \\\n # Needed for nodejs / node-gyp\n python2 \\\n tzdata\n\n \nENV BUNDLER_VERSION 2.2.24\nENV BUNDLE_JOBS 8\nENV BUNDLE_RETRY 5\nENV BUNDLE_WITHOUT development:test\nENV BUNDLE_CACHE_ALL true\nENV RAILS_ENV production\nENV RACK_ENV production\nENV NODE_ENV production\nENV APP_PATH /work\n\nWORKDIR $APP_PATH\n\n# Gems installation\nCOPY Gemfile Gemfile.lock ./\nRUN gem install bundler -v $BUNDLER_VERSION\n\nRUN bundle config --global frozen 1 && \\\n bundle install && \\\n rm -rf /usr/local/bundle/cache/*.gem && \\\n find /usr/local/bundle/gems/ -name "*.c" -delete && \\\n find /usr/local/bundle/gems/ -name "*.o" -delete\n\n \n\n# NPM packages installation\nCOPY package.json yarn.lock ./\nRUN yarn install --frozen-lockfile --non-interactive --production\n\nADD . $APP_PATH\n\nRUN SECRET_KEY_BASE=`bin/rake secret` rails assets:precompile --trace && \\\n yarn cache clean && \\\n rm -rf node_modules tmp/cache vendor/assets test\n\n \nFROM ruby:3.0.2-alpine3.13\n\nRUN mkdir -p /work\nWORKDIR /work\n\nENV RAILS_ENV production\nENV NODE_ENV production\nENV RAILS_SERVE_STATIC_FILES true\n\n# Some native extensions required by gems such as pg or mysql2.\nCOPY --from=builder /usr/lib /usr/lib\n\n# Timezone data is required at runtime\nCOPY --from=builder /usr/share/zoneinfo/ /usr/share/zoneinfo/\n\n# Ruby gems\nCOPY --from=builder /usr/local/bundle /usr/local/bundle\nCOPY --from=builder /work /work\n\nCOPY docker-entrypoint.sh ./\nENTRYPOINT ["./docker-entrypoint.sh"]\n\nEXPOSE 3000\n\nCMD ["rails", "server", "-p", "3000", "-b", "0.0.0.0"]\n')),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"You can tweak the versions if you are using a different version of Ruby, Bundler, PostgreSQL ...")),Object(a.b)("li",null,Object(a.b)("h4",{id:"sidekiq-dockerfile"},"Sidekiq Dockerfile"),Object(a.b)("p",null,"We'll use a similar Dockerfile for our Sidekiq worker.\nCreate a ",Object(a.b)("inlineCode",{parentName:"p"},"Dockerfile.sidekiq")," at the root of your repository with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{className:"language-Dockerfile"}),'FROM ruby:3.0.2-alpine3.13 AS builder\n\nLABEL maintener=\'yirbah@qovery.com\'\n\n# Minimal requirements to run a Rails app\nRUN apk add --no-cache --update build-base \\\n linux-headers \\\n git \\\n postgresql-dev=~13 \\\n # Rails SQL schema format requires `pg_dump(1)` and `psql(1)`\n postgresql=~13 \\\n # Install same version of pg_dump\n postgresql-client=~13 \\\n nodejs \\\n yarn \\\n # Needed for nodejs / node-gyp\n python2 \\\n tzdata\n\nENV BUNDLER_VERSION 2.2.24\nENV BUNDLE_JOBS 8\nENV BUNDLE_RETRY 5\nENV BUNDLE_WITHOUT development:test\nENV BUNDLE_CACHE_ALL true\nENV RAILS_ENV production\nENV RACK_ENV production\nENV NODE_ENV production\nENV APP_PATH /work\n\nWORKDIR $APP_PATH\n\n# Gems installation\nCOPY Gemfile Gemfile.lock ./\n\nRUN gem install bundler -v $BUNDLER_VERSION\n\nRUN bundle config --global frozen 1 && \\\n bundle install && \\\n rm -rf /usr/local/bundle/cache/*.gem && \\\n find /usr/local/bundle/gems/ -name "*.c" -delete && \\\n find /usr/local/bundle/gems/ -name "*.o" -delete\n\n# NPM packages installation\nCOPY package.json yarn.lock ./\n\nRUN yarn install --frozen-lockfile --non-interactive --production\n\nADD . $APP_PATH\n\nRUN SECRET_KEY_BASE=`bin/rake secret` rails assets:precompile --trace && \\\n yarn cache clean && \\\n rm -rf node_modules tmp/cache vendor/assets test\n\nFROM ruby:3.0.2-alpine3.13\n\nRUN mkdir -p /work\nWORKDIR /work\n\nENV RAILS_ENV production\nENV NODE_ENV production\nENV RAILS_SERVE_STATIC_FILES true\n\n# Some native extensions required by gems such as pg or mysql2.\nCOPY --from=builder /usr/lib /usr/lib\n\n# Timezone data is required at runtime\nCOPY --from=builder /usr/share/zoneinfo/ /usr/share/zoneinfo/\n\n# Ruby gems\nCOPY --from=builder /usr/local/bundle /usr/local/bundle\n\nCOPY --from=builder /work /work\n\nCOPY docker-entrypoint.sh ./\n\n\nCMD ["bundle", "exec", "sidekiq"]\n'))),Object(a.b)("li",null,Object(a.b)("h4",{id:"dockerignore"},"Dockerignore"),Object(a.b)("p",null,"In order to avoid unneeded files being copied to your Docker image, you can add a ",Object(a.b)("inlineCode",{parentName:"p"},".dockerignore")," file to the root of your project, with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{}),"# See https://help.github.com/articles/ignoring-files for more about ignoring files.\n#\n# If you find yourself ignoring temporary files generated by your text editor\n# or operating system, you probably want to add a global ignore instead:\n# git config --global core.excludesfile '~/.gitignore_global'\n\n# Ignore bundler config.\n/.bundle\n\n# Ignore all logfiles and tempfiles.\n/log/*\n/tmp/*\n!/log/.keep\n!/tmp/.keep\n\n# Ignore pidfiles, but keep the directory.\n/tmp/pids/*\n!/tmp/pids/\n!/tmp/pids/.keep\n\n# Ignore uploaded files in development.\n/storage/*\n!/storage/.keep\n/public/assets\n.byebug_history\n\n# Ignore master key for decrypting credentials and more.\n/config/master.key\n/public/packs\n/public/packs-test\n/node_modules\n/yarn-error.log\nyarn-debug.log*\n.yarn-integrity\n")),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"You can customize this file for the needs of your project. Add any file that is not useful for the runtime of your application.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"docker-entrypoint"},"Docker entrypoint"),Object(a.b)("p",null,"Finally we will add an entrypoint script that will be called at the start of the application.\nWe'll use it to run the database setup and migration commands."),Object(a.b)("p",null,"You can read more about why this entrypoint is needed ",Object(a.b)("a",Object(i.a)({parentName:"p"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"here"),". "),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"Soon Qovery will add lifecycle hooks and this won't be needed anymore"),Object(a.b)("p",null,"Add a ",Object(a.b)("inlineCode",{parentName:"p"},"docker-entrypoint.sh")," file at the root of your project with the following content: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{className:"language-bash"}),'#! /bin/sh\n\nbundle exec rake db:migrate\n\nif [[ $? != 0 ]]; then\n\necho\necho "== Failed to migrate. Running setup first."\necho\n\nbundle exec rake db:setup\nfi\n\n# Execute the given or default command:\n\nexec "$@"\n')),Object(a.b)("p",null,"Make this script executable: "),Object(a.b)("pre",null,Object(a.b)("code",Object(i.a)({parentName:"pre"},{}),"chmod +x docker-entrypoint.sh\n"))))),Object(a.b)("h2",{id:"deploy-your-application-to-qovery"},"Deploy your application to Qovery"),Object(a.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"create-a-project"},"Create a project"),Object(a.b)("p",null,"Now that your Rails application is ready to be dockerized, we can create a project on the Qovery console:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/01.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"create-an-environment"},"Create an environment"),Object(a.b)("p",null,"Now we'll create an environment. Let's start with our ",Object(a.b)("inlineCode",{parentName:"p"},"staging")," environment:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/02.png",alt:"Qovery console"})),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/03.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-your-rails-app"},"Add your Rails app"),Object(a.b)("p",null,"We'll now add our Rails app to the environment: "),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/04.png",alt:"Qovery console"})),Object(a.b)("p",null,"On the form you'll need to enter the following information:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"The app name: it can be whatever you want. Here ",Object(a.b)("inlineCode",{parentName:"li"},"web"),"."),Object(a.b)("li",{parentName:"ul"},"Pick your Git privider, then the repository for your application"),Object(a.b)("li",{parentName:"ul"},"The branch you want to deploy for this application. We chose ",Object(a.b)("inlineCode",{parentName:"li"},"main")),Object(a.b)("li",{parentName:"ul"},"The Root application path. In case your application is not at the root of your repository (e.g. you have a monorepo), otherwise it will be ",Object(a.b)("inlineCode",{parentName:"li"},"/"),"."),Object(a.b)("li",{parentName:"ul"},"For the Build mode, pick ",Object(a.b)("inlineCode",{parentName:"li"},"Dockerfile"),"."),Object(a.b)("li",{parentName:"ul"},"Enter the path to your Dockerfile.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/05.png",alt:"Qovery console"})),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/06.png",alt:"Qovery console"})),Object(a.b)("p",null,"You can then click ",Object(a.b)("inlineCode",{parentName:"p"},"Create"),". You'll be redirected to your application dashboard."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/07.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"Your application is not being deployed yet. We'll add the database and do some more configuration before.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-a-postgresql-database"},"Add a PostgreSQL database"),Object(a.b)("p",null,"Our application will use a PostgreSQL database. Let's add one to our environment:"),Object(a.b)("p",null,"Click on ",Object(a.b)("inlineCode",{parentName:"p"},"ADD"),", then ",Object(a.b)("inlineCode",{parentName:"p"},"Database")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/08.png",alt:"Qovery console"})),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Give a name to your database."),Object(a.b)("li",{parentName:"ul"},"For the Type, select ",Object(a.b)("inlineCode",{parentName:"li"},"POSTGRESQL"),"."),Object(a.b)("li",{parentName:"ul"},"For the Mode, we'll pick ",Object(a.b)("inlineCode",{parentName:"li"},"CONTAINER"),"."),Object(a.b)("li",{parentName:"ul"},"Chose the Version you need.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/09.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Since we are creating a Staging environment, we used the CONTAINER mode. This is not recommended for Production. In Production environment you should go for the MANAGED option."),Object(a.b)("p",null,"You can then click ",Object(a.b)("inlineCode",{parentName:"p"},"Create"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-a-redis-database"},"Add a Redis database"),Object(a.b)("p",null,"Since we're using Sidekiq, we'll also need a Redis database as a backend."),Object(a.b)("p",null,"If you didn't close the ",Object(a.b)("inlineCode",{parentName:"p"},"Database")," modal, you can click the ",Object(a.b)("inlineCode",{parentName:"p"},"ADD")," button, then in the dropbox for ",Object(a.b)("inlineCode",{parentName:"p"},"Database 2")," click ",Object(a.b)("inlineCode",{parentName:"p"},"Create database"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/10.png",alt:"Qovery console"})),Object(a.b)("p",null,"Fill the form the same way you did for PostgreSQL:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/11.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Since we are creating a Staging environment, we used the CONTAINER mode. This is not recommended for Production. In Production environment you should go for the MANAGED option."),Object(a.b)("p",null,"Click ",Object(a.b)("inlineCode",{parentName:"p"},"Create")," and close the Databases modal."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/12.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"configure-your-application-env-variables"},"Configure your application ENV variables"),Object(a.b)("p",null,"Go back to your environment view:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/13.png",alt:"Qovery console"})),Object(a.b)("p",null,"Then click on your application:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/14.png",alt:"Qovery console"})),Object(a.b)("p",null,"On your application dashboard, go to ",Object(a.b)("inlineCode",{parentName:"p"},"Environment variables"),":"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/15.png",alt:"Qovery console"})),Object(a.b)("p",null,"Here you can add any environment variable your application needs."),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Since we are creating a Staging environment, we used the CONTAIWe do not advise you to add secret values here. For sensitive information, like credentials, use the Secret variables, which are encrypted."),Object(a.b)("p",null,"We'll now configure a few secrets for our application. Click on the ",Object(a.b)("inlineCode",{parentName:"p"},"Secret variables")," tab:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/16.png",alt:"Qovery console"})),Object(a.b)("p",null,"First since our Demo application uses the Rails Encrypted Secrets, we'll add the ",Object(a.b)("inlineCode",{parentName:"p"},"RAILS_MASTER_KEY")," secret\nClick on ",Object(a.b)("inlineCode",{parentName:"p"},"CREATE SECRET"),", then fill the form:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Variable: enter the variable name, ",Object(a.b)("inlineCode",{parentName:"li"},"RAILS_MASTER_KEY"),"."),Object(a.b)("li",{parentName:"ul"},"Value: enter the actual value for your ",Object(a.b)("inlineCode",{parentName:"li"},"RAILS_MASTER_KEY"),"."),Object(a.b)("li",{parentName:"ul"},"Scope: chose ",Object(a.b)("inlineCode",{parentName:"li"},"ENVIRONMENT")," since the secret will be used by our Sidekiq worker too.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/17.png",alt:"Qovery console"})),Object(a.b)("p",null,"Now we'll need to add the ",Object(a.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," and ",Object(a.b)("inlineCode",{parentName:"p"},"REDIS_URL"),", that Rails will use to connect to PostgreSQL and Redis. Those are secrets as well, since the URLs contain passwords."),Object(a.b)("p",null,"But instead of creating new secrets like we did for the ",Object(a.b)("inlineCode",{parentName:"p"},"RAILS_MASTER_KEY"),", we'll use aliases. Aliases are just a way of giving a different name to an existing ENV variable or secret.\nSince Qovery provides us with the secrets corresponding to the two databases we created earlier, we can alias them."),Object(a.b)("p",null,"First, create an alias to the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_POSTGRESQL_ZXXXXXXXX_DATABASE_URL_INTERNAL"),":"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/18.png",alt:"Qovery console"})),Object(a.b)("p",null,"In the form, chose ",Object(a.b)("inlineCode",{parentName:"p"},"DATABASE_URL")," for the alias name and set it at the ",Object(a.b)("inlineCode",{parentName:"p"},"ENVIRONMENT")," level:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/19.png",alt:"Qovery console"})),Object(a.b)("p",null,"Click ",Object(a.b)("inlineCode",{parentName:"p"},"Create")," then do the same thing with a ",Object(a.b)("inlineCode",{parentName:"p"},"REDIS_URL")," alias to the ",Object(a.b)("inlineCode",{parentName:"p"},"QOVERY_REDIS_ZXXXXXXXX_DATABASE_URL_INTERNAL"),"."),Object(a.b)("p",null,"You should see your two aliases created:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/20.png",alt:"Qovery console"})),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"These are the secrets required for our demo application. Yours might need more. Add all the variables you need before going to the next step.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"deploy-the-environment"},"Deploy the environment"),Object(a.b)("p",null,"Go back to the ",Object(a.b)("inlineCode",{parentName:"p"},"staging")," environment view and deploy it:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/21.png",alt:"Qovery console"})),Object(a.b)("p",null,"You should see it switch to the ",Object(a.b)("inlineCode",{parentName:"p"},"DEPLOYING")," status. Wait until the status turns to ",Object(a.b)("inlineCode",{parentName:"p"},"RUNNING"),". "),Object(a.b)(l.a,{type:"notice",mdxType:"Alert"},"The first deployment could take a while."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/22.png",alt:"Qovery console"})),Object(a.b)("p",null,"Once your environment is ",Object(a.b)("inlineCode",{parentName:"p"},"RUNNING"),", open the ",Object(a.b)("inlineCode",{parentName:"p"},"web")," application to see if it works. It will open a new tab showing your application."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/23.png",alt:"Qovery console"}))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-the-sidekiq-worker"},"Add the Sidekiq worker"),Object(a.b)("p",null,"The last step is to add your Sidekiq Worker. We'll follow the same steps as in the ",Object(a.b)("inlineCode",{parentName:"p"},"Add your Rails app")," section with a few differences:"),Object(a.b)("p",null,"Add a new application:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/24.png",alt:"Qovery console"})),Object(a.b)("p",null,"The settigs are the same as for the Rails application, except:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"We use the ",Object(a.b)("inlineCode",{parentName:"li"},"Dockerfile.sidekiq")," Dockerfile this time"),Object(a.b)("li",{parentName:"ul"},"We don't declare a port since our worker is not a web service but communicates with our application through Redis.")),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/25.png",alt:"Qovery console"})),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/26.png",alt:"Qovery console"})),Object(a.b)("p",null,"Click ",Object(a.b)("inlineCode",{parentName:"p"},"Create"),"."),Object(a.b)("p",null,"If we check the ENV variables and secrets, we notice that it directly inherited the ones we set at the ",Object(a.b)("inlineCode",{parentName:"p"},"Environment")," level. So we don't need to do the configuration again."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/27.png",alt:"Qovery console"})),Object(a.b)("p",null,"You can now deploy your ",Object(a.b)("inlineCode",{parentName:"p"},"worker")," application:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deploy-rails-with-postgresql-and-sidekiq/28.png",alt:"Qovery console"})),Object(a.b)("p",null,"Wait for it to switch to the ",Object(a.b)("inlineCode",{parentName:"p"},"RUNNING")," status.")))),Object(a.b)("h2",{id:"conclusion"},"Conclusion"),Object(a.b)("p",null,"You now have a Rails application with PostgreSQL and Sidekiq running on Qovery. "),Object(a.b)(l.a,{type:"warning",mdxType:"Alert"},"Depending on the gems you are using, their versions or your application configuration, you might need to tweak the Dockerfiles provided.",Object(a.b)("br",null),"This example is meant to be a starting point for your own configuration, not a one-size-fits-all configuration."))}u.isMDXComponent=!0},423:function(e,n,t){var i;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=r.a.createContext({}),p=function(e){var n=r.a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):l({},n,{},e)),t},b=function(e){var n=p(e.components);return r.a.createElement(s.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},u=Object(i.forwardRef)((function(e,n){var t=e.components,i=e.mdxType,a=e.originalType,o=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),b=p(t),u=i,m=b["".concat(o,".").concat(u)]||b[u]||d[u]||a;return t?r.a.createElement(m,l({ref:n},s,{components:t})):r.a.createElement(m,l({ref:n},s))}));function m(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var a=t.length,o=new Array(a);o[0]=u;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l.mdxType="string"==typeof e?e:i,o[1]=l;for(var s=2;s1?arguments[1]:void 0,t),c=o>2?arguments[2]:void 0,s=void 0===c?t:r(c,t);s>l;)n[l++]=e;return n}},428:function(e,n,t){var i=t(28).f,r=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in r||t(10)&&i(r,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,n,t){"use strict";t(428);var i=t(0),r=t.n(i),a=t(424);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},433:function(e,n,t){"use strict";var i=t(435),r=t(51);function a(e,n){return n.encode?n.strict?i(e):encodeURIComponent(e):e}n.extract=function(e){return e.split("?")[1]||""},n.parse=function(e,n){var t=function(e){var n;switch(e.arrayFormat){case"index":return function(e,t,i){n=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),n?(void 0===i[e]&&(i[e]={}),i[e][n[1]]=t):i[e]=t};case"bracket":return function(e,t,i){n=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),n?void 0!==i[e]?i[e]=[].concat(i[e],t):i[e]=[t]:i[e]=t};default:return function(e,n,t){void 0!==t[e]?t[e]=[].concat(t[e],n):t[e]=n}}}(n=r({arrayFormat:"none"},n)),i=Object.create(null);return"string"!=typeof e?i:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var n=e.replace(/\+/g," ").split("="),r=n.shift(),a=n.length>0?n.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),t(decodeURIComponent(r),a,i)})),Object.keys(i).sort().reduce((function(e,n){var t=i[n];return Boolean(t)&&"object"==typeof t&&!Array.isArray(t)?e[n]=function e(n){return Array.isArray(n)?n.sort():"object"==typeof n?e(Object.keys(n)).sort((function(e,n){return Number(e)-Number(n)})).map((function(e){return n[e]})):n}(t):e[n]=t,e}),Object.create(null))):i},n.stringify=function(e,n){var t=function(e){switch(e.arrayFormat){case"index":return function(n,t,i){return null===t?[a(n,e),"[",i,"]"].join(""):[a(n,e),"[",a(i,e),"]=",a(t,e)].join("")};case"bracket":return function(n,t){return null===t?a(n,e):[a(n,e),"[]=",a(t,e)].join("")};default:return function(n,t){return null===t?a(n,e):[a(n,e),"=",a(t,e)].join("")}}}(n=r({encode:!0,strict:!0,arrayFormat:"none"},n));return e?Object.keys(e).sort().map((function(i){var r=e[i];if(void 0===r)return"";if(null===r)return a(i,n);if(Array.isArray(r)){var o=[];return r.slice().forEach((function(e){void 0!==e&&o.push(t(i,e,o.length))})),o.join("&")}return a(i,n)+"="+a(r,n)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,n,t){"use strict";var i=t(0),r=t.n(i),a=(t(423),t(433)),o=t.n(a);t(134);n.a=function(e){var n=e.children,t=e.headingDepth,a=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,c={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+o.a.stringify(c),p=Object(i.useState)(null),b=p[0],d=p[1];return r.a.createElement("div",{className:"steps steps--h"+t},n,!a&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,n,t){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/a4459aa8.3d7164cb.js.LICENSE.txt b/a3cf753a.4cb494e4.js.LICENSE.txt similarity index 100% rename from a4459aa8.3d7164cb.js.LICENSE.txt rename to a3cf753a.4cb494e4.js.LICENSE.txt diff --git a/ff0cde69.3d36ebd5.js b/a4401f0f.4084085e.js similarity index 93% rename from ff0cde69.3d36ebd5.js rename to a4401f0f.4084085e.js index 92ee357c64..aa6710e0d6 100644 --- a/ff0cde69.3d36ebd5.js +++ b/a4401f0f.4084085e.js @@ -1,2 +1,2 @@ -/*! For license information please see ff0cde69.3d36ebd5.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[262],{414:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),o=(n(0),n(422)),i=n(426),c=n(431),l={last_modified_on:"2021-07-22",$schema:"/.meta/.schemas/guides.json",title:"Creating API clients using OpenAPI Tools",description:"How to quickly create a Qovery API client in your language",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Creating API clients using OpenAPI Tools",description:"How to quickly create a Qovery API client in your language",permalink:"/guides/tutorial/generate-qovery-api-client",readingTime:"4 min read",source:"@site/guides/tutorial/generate-qovery-api-client.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Creating API clients using OpenAPI Tools",truncated:!1,prevItem:{title:"Create your Staging environment from your Production environment on AWS",permalink:"/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws"},nextItem:{title:"Customizing Preview URL with Qovery CLI",permalink:"/guides/tutorial/customizing-preview-url-with-qovery-cli"}},u=[{value:"Integration",id:"integration",children:[{value:"Generating API client code",id:"generating-api-client-code",children:[]},{value:"Steps",id:"steps",children:[]},{value:"Under the hood",id:"under-the-hood",children:[]},{value:"Example",id:"example",children:[]}]},{value:"Summary",id:"summary",children:[]}],p={rightToc:u};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"While releasing the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/blog/one-week-before-the-launch-of-qovery-v2-beta-whats-new#open-api"}),"latest major update of Qovery"),", we realized that we need to open our API to our users in order to make them able to\nbuild integrations and customizations they need in their development workflows. This month, we launched a BETA version of the Qovery V2 platform, and alongside this, we ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"made our beta API open")," and ready to play with and experiment."),Object(o.b)("h2",{id:"integration"},"Integration"),Object(o.b)("p",null,"To integrate with the new API, one has a choice of reading the documentation and doing all the necessary plumbing by himself. However, at Qovery, we value developer experience, so we decided to make this process easier and more streamlined."),Object(o.b)("h3",{id:"generating-api-client-code"},"Generating API client code"),Object(o.b)("p",null,"Our API specification is made in a way that makes it very easy to generate API clients in ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/OpenAPITools/openapi-generator#overview"}),"any of the many supported languages"),". We also prepared a script to make this process seamless - all you need to do is to clone our open API repository and run one command to generate the newest client version."),Object(o.b)("h3",{id:"steps"},"Steps"),Object(o.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have installed ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://nodejs.org/en/"}),"Node/NPM")),Object(o.b)("li",{parentName:"ul"},"You have installed ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://github.com/OpenAPITools/openapi-generator#17---npm"}),"Open API Generator")))),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"clone-the-repository"},"Clone the repository"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"$ git clone https://github.com/Qovery/qovery-openapi-spec.git\n$ cd qovery-openapi-spec\n"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"generate-the-client-code"},"Generate the client code"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"$ QOVERY_CLIENT_LANGUAGE=go npm run generate\n")),Object(o.b)("p",null,"where: ",Object(o.b)("strong",{parentName:"p"},"$QOVERY_CLIENT_LANGUAGE")," is the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/OpenAPITools/openapi-generator#overview"}),"language of your choice"),".")),Object(o.b)("li",null,Object(o.b)("h4",{id:"list-the-generated-files"},"List the generated files"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"$ ls out/client\n")),Object(o.b)("p",null,"This folder contains all the files necessary to interact with ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API"),", as well as its documentation. To use it in your project, you can create a repository to store the client files and then import them as a dependency in your project. This part is highly dependant on the language and technology you are using, so it's not covered in this post.")))),Object(o.b)("h3",{id:"under-the-hood"},"Under the hood"),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"npm run generate -- $LANGUAGE")," command under the hood uses the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/OpenAPITools/openapi-generator"}),"open-api-generator")," and a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://swagger.io/specification/"}),"Open API specification")," created to define Qovery API.\nYou can see the specification after cloning ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-openapi-spec"}),"our open api repository")," and running ",Object(o.b)("inlineCode",{parentName:"p"},"npm run build")," in ",Object(o.b)("inlineCode",{parentName:"p"},"_build/openapi.yaml")," file."),Object(o.b)("p",null,"The clients are generated using the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github/OpenAPITools/openapi-generator"}),"open-api-generator")," and the specification file - ",Object(o.b)("inlineCode",{parentName:"p"},"_build/openapi.yaml"),"."),Object(o.b)("h3",{id:"example"},"Example"),Object(o.b)("p",null,"As an example of generated API client, let's use the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli"}),"Qovery CLI"),". The ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/using-qovery/interface/cli/"}),"command-line interface")," of Qovery is using a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-client-go"}),"Go API Client")," that was generated following the steps from this article.\nAfter generating the client, we simply published the ",Object(o.b)("inlineCode",{parentName:"p"},"out/client")," folder as a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-client-go"}),"Git Repository")," and then simply imported the code in the CLI application as a dependency:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-go"}),'package utils\n\nimport (\n "github.com/qovery/qovery-client-go"\n)\n')),Object(o.b)("p",null,"This allowed us to use the generated client code to interact with ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API")," very easily:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-go"}),'token, err := GetAccessToken()\nif err != nil {\n return err\n}\n\nauth := context.WithValue(context.Background(), qovery.ContextAccessToken, string(token))\nclient := qovery.NewAPIClient(qovery.NewConfiguration())\n\norganizations, res, err := client.OrganizationMainCallsApi.ListOrganization(auth).Execute()\nif err != nil {\n return err\n}\nif res.StatusCode >= 400 {\n return errors.New("Received " + res.Status + " response while listing organizations. ")\n}\n')),Object(o.b)("h2",{id:"summary"},"Summary"),Object(o.b)("p",null,Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-openapi-spec.git"}),"Qovery Open API specification")," allows creating ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API")," stubs extremely quickly. At Qovery, we officially support only ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-client-go"}),"Golang Client"),", but if you use a different language, you can generate your own client in a matter of seconds following the steps of this article."))}b.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=r,h=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return n?a.a.createElement(h,c({ref:t},s,{components:n})):a.a.createElement(h,c({ref:t},s))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(r.useState)(null),p=u[0],b=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see a4401f0f.4084085e.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[163],{315:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),o=(n(0),n(425)),i=n(429),c=n(434),l={last_modified_on:"2021-07-22",$schema:"/.meta/.schemas/guides.json",title:"Creating API clients using OpenAPI Tools",description:"How to quickly create a Qovery API client in your language",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Creating API clients using OpenAPI Tools",description:"How to quickly create a Qovery API client in your language",permalink:"/guides/tutorial/generate-qovery-api-client",readingTime:"4 min read",source:"@site/guides/tutorial/generate-qovery-api-client.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Creating API clients using OpenAPI Tools",truncated:!1,prevItem:{title:"Create your Staging environment from your Production environment on AWS",permalink:"/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws"},nextItem:{title:"Customizing Preview URL with Qovery CLI",permalink:"/guides/tutorial/customizing-preview-url-with-qovery-cli"}},u=[{value:"Integration",id:"integration",children:[{value:"Generating API client code",id:"generating-api-client-code",children:[]},{value:"Steps",id:"steps",children:[]},{value:"Under the hood",id:"under-the-hood",children:[]},{value:"Example",id:"example",children:[]}]},{value:"Summary",id:"summary",children:[]}],p={rightToc:u};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"While releasing the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/blog/one-week-before-the-launch-of-qovery-v2-beta-whats-new#open-api"}),"latest major update of Qovery"),", we realized that we need to open our API to our users in order to make them able to\nbuild integrations and customizations they need in their development workflows. This month, we launched a BETA version of the Qovery V2 platform, and alongside this, we ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"made our beta API open")," and ready to play with and experiment."),Object(o.b)("h2",{id:"integration"},"Integration"),Object(o.b)("p",null,"To integrate with the new API, one has a choice of reading the documentation and doing all the necessary plumbing by himself. However, at Qovery, we value developer experience, so we decided to make this process easier and more streamlined."),Object(o.b)("h3",{id:"generating-api-client-code"},"Generating API client code"),Object(o.b)("p",null,"Our API specification is made in a way that makes it very easy to generate API clients in ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/OpenAPITools/openapi-generator#overview"}),"any of the many supported languages"),". We also prepared a script to make this process seamless - all you need to do is to clone our open API repository and run one command to generate the newest client version."),Object(o.b)("h3",{id:"steps"},"Steps"),Object(o.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have installed ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://nodejs.org/en/"}),"Node/NPM")),Object(o.b)("li",{parentName:"ul"},"You have installed ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://github.com/OpenAPITools/openapi-generator#17---npm"}),"Open API Generator")))),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"clone-the-repository"},"Clone the repository"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"$ git clone https://github.com/Qovery/qovery-openapi-spec.git\n$ cd qovery-openapi-spec\n"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"generate-the-client-code"},"Generate the client code"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"$ QOVERY_CLIENT_LANGUAGE=go npm run generate\n")),Object(o.b)("p",null,"where: ",Object(o.b)("strong",{parentName:"p"},"$QOVERY_CLIENT_LANGUAGE")," is the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/OpenAPITools/openapi-generator#overview"}),"language of your choice"),".")),Object(o.b)("li",null,Object(o.b)("h4",{id:"list-the-generated-files"},"List the generated files"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"$ ls out/client\n")),Object(o.b)("p",null,"This folder contains all the files necessary to interact with ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API"),", as well as its documentation. To use it in your project, you can create a repository to store the client files and then import them as a dependency in your project. This part is highly dependant on the language and technology you are using, so it's not covered in this post.")))),Object(o.b)("h3",{id:"under-the-hood"},"Under the hood"),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"npm run generate -- $LANGUAGE")," command under the hood uses the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/OpenAPITools/openapi-generator"}),"open-api-generator")," and a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://swagger.io/specification/"}),"Open API specification")," created to define Qovery API.\nYou can see the specification after cloning ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-openapi-spec"}),"our open api repository")," and running ",Object(o.b)("inlineCode",{parentName:"p"},"npm run build")," in ",Object(o.b)("inlineCode",{parentName:"p"},"_build/openapi.yaml")," file."),Object(o.b)("p",null,"The clients are generated using the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github/OpenAPITools/openapi-generator"}),"open-api-generator")," and the specification file - ",Object(o.b)("inlineCode",{parentName:"p"},"_build/openapi.yaml"),"."),Object(o.b)("h3",{id:"example"},"Example"),Object(o.b)("p",null,"As an example of generated API client, let's use the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli"}),"Qovery CLI"),". The ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/using-qovery/interface/cli/"}),"command-line interface")," of Qovery is using a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-client-go"}),"Go API Client")," that was generated following the steps from this article.\nAfter generating the client, we simply published the ",Object(o.b)("inlineCode",{parentName:"p"},"out/client")," folder as a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-client-go"}),"Git Repository")," and then simply imported the code in the CLI application as a dependency:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-go"}),'package utils\n\nimport (\n "github.com/qovery/qovery-client-go"\n)\n')),Object(o.b)("p",null,"This allowed us to use the generated client code to interact with ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API")," very easily:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-go"}),'token, err := GetAccessToken()\nif err != nil {\n return err\n}\n\nauth := context.WithValue(context.Background(), qovery.ContextAccessToken, string(token))\nclient := qovery.NewAPIClient(qovery.NewConfiguration())\n\norganizations, res, err := client.OrganizationMainCallsApi.ListOrganization(auth).Execute()\nif err != nil {\n return err\n}\nif res.StatusCode >= 400 {\n return errors.New("Received " + res.Status + " response while listing organizations. ")\n}\n')),Object(o.b)("h2",{id:"summary"},"Summary"),Object(o.b)("p",null,Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-openapi-spec.git"}),"Qovery Open API specification")," allows creating ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API")," stubs extremely quickly. At Qovery, we officially support only ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-client-go"}),"Golang Client"),", but if you use a different language, you can generate your own client in a matter of seconds following the steps of this article."))}b.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=r,h=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return n?a.a.createElement(h,c({ref:t},s,{components:n})):a.a.createElement(h,c({ref:t},s))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(r.useState)(null),p=u[0],b=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/a4a09dfe.3ef2868d.js.LICENSE.txt b/a4401f0f.4084085e.js.LICENSE.txt similarity index 100% rename from a4a09dfe.3ef2868d.js.LICENSE.txt rename to a4401f0f.4084085e.js.LICENSE.txt diff --git a/a4459aa8.3d7164cb.js b/a4459aa8.1148d970.js similarity index 92% rename from a4459aa8.3d7164cb.js rename to a4459aa8.1148d970.js index 53fd110aee..6fae007852 100644 --- a/a4459aa8.3d7164cb.js +++ b/a4459aa8.1148d970.js @@ -1,2 +1,2 @@ -/*! For license information please see a4459aa8.3d7164cb.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[161],{313:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return o})),t.d(n,"metadata",(function(){return c})),t.d(n,"rightToc",(function(){return l})),t.d(n,"default",(function(){return p}));var a=t(1),r=t(9),i=(t(0),t(422)),o=(t(421),t(426),t(429),{last_modified_on:"2021-12-27",$schema:"/.meta/.schemas/guides.json",title:"Managing Environment Variables in React (create-react-app)",description:"How to manage environemnt variables in applications bootstrapped with create-react-app",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","language: javascript"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Managing Environment Variables in React (create-react-app)",description:"How to manage environemnt variables in applications bootstrapped with create-react-app",permalink:"/guides/tutorial/managing-env-variables-in-create-react-app",readingTime:"5 min read",source:"@site/guides/tutorial/managing-env-variables-in-create-react-app.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"language: javascript",permalink:"/guides/tags/language-javascript"}],title:"Managing Environment Variables in React (create-react-app)",truncated:!1,prevItem:{title:"Kubernetes observability and monitoring with Datadog",permalink:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog"},nextItem:{title:"Microservices",permalink:"/guides/advanced/microservices"}},l=[{value:"Code Repository",id:"code-repository",children:[]},{value:"Environment Variables",id:"environment-variables",children:[{value:"Warning!",id:"warning",children:[]}]},{value:"Deployment",id:"deployment",children:[]},{value:"Adding Environment Variable",id:"adding-environment-variable",children:[]},{value:"Going Prod",id:"going-prod",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],s={rightToc:l};function p(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},s,t,{components:n,mdxType:"MDXLayout"}),Object(i.b)("p",null,"In this short guide, we'll go trough managing Secrets/Environment Variables in React applications created using ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app")," and deployed on Qovery."),Object(i.b)("p",null,"Most of the guides you can find online propose quite complex solutions with creating your own bash scripts to set up env variables in apps created by ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app")," - this guide will show you an easier alternative and a way to Dockerize your React app in production-ready way."),Object(i.b)("h2",{id:"code-repository"},"Code Repository"),Object(i.b)("p",null,"In this guide we'll use ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/cra-test"}),"https://github.com/pjeziorowski/cra-test")," repository - it's a sample application bootstrapped using ",Object(i.b)("inlineCode",{parentName:"p"},"npx create-react-app my-app")," command."),Object(i.b)("p",null,"After the application structure is generated, we dockerize the application by adding a ",Object(i.b)("inlineCode",{parentName:"p"},"Dockerfile")," with the following content:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'# Docker Image which is used as foundation to create\n# a custom Docker Image with this Dockerfile\nFROM node:10\n\n# A directory within the virtualized Docker environment\nWORKDIR /usr/src/app\n\n# Copies package.json and package-lock.json to Docker environment\nCOPY package*.json ./\n\n# Installs all node packages\nRUN npm install\n\n# Copies everything over to Docker environment\nCOPY . .\n\n# Uses port which is used by the actual application\nEXPOSE 3000\n\n# Finally runs the application\nCMD [ "npm", "start" ]\n')),Object(i.b)("p",null,"One more little thing that we change is creating a new constant that uses a value of ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_MSG")," environment variable to print a text on the website:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const msg = process.env.REACT_APP_MSG\n")),Object(i.b)("p",null,"And then, we print it in the UI:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'\n {msg}\n\n')),Object(i.b)("h2",{id:"environment-variables"},"Environment Variables"),Object(i.b)("p",null,"Let's now add a ",Object(i.b)("inlineCode",{parentName:"p"},".env")," file for the default environment variables for our React app. For this, we create a ",Object(i.b)("inlineCode",{parentName:"p"},".env")," file with the content:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'HOST="0.0.0.0"\nPORT="3000"\nREACT_APP_MSG="From .env"\n')),Object(i.b)("h3",{id:"warning"},"Warning!"),Object(i.b)("p",null,"For all custom environment variables in apps created via ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app"),", we need to use ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_")," prefix in env var names - it's a requirement, if we don't follow the convention, variables will not be accessible in our application!"),Object(i.b)("p",null,"Also, remember that all the values are accessible on the client-side (browser). You should not use it for any data that your users should not access in the browser."),Object(i.b)("h2",{id:"deployment"},"Deployment"),Object(i.b)("p",null,"Before overriding the default env vars hardcoded in our repository using Qovery, let's first deploy the app."),Object(i.b)("p",null,"To do so, add a new application using the code from previous steps. When configuring the application, don't forget to:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Use ",Object(i.b)("inlineCode",{parentName:"li"},"Docker")," build mode"),Object(i.b)("li",{parentName:"ul"},"Add port ",Object(i.b)("inlineCode",{parentName:"li"},"3000")," to expose the app on the internet")),Object(i.b)("p",null,"After the application is created, click on the ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," button in application actions."),Object(i.b)("p",null,"In a few minutes, your application should be up and running:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/cra-envs/1.png",alt:"create-react-app environment variables"})),Object(i.b)("p",null,"As you see, the text in the link ",Object(i.b)("strong",{parentName:"p"},"From .env file indicates that the value")),Object(i.b)("h2",{id:"adding-environment-variable"},"Adding Environment Variable"),Object(i.b)("p",null,"Now, let's override our ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_MSG")," environment variable (and the text we display in the UI)."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/cra-envs/2.png",alt:"create-react-app environment variables"})),Object(i.b)("p",null,"After adding a new variable, restart the application. In a minute or so, we should see that the message in our website is updated with the value of ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_MSG")," we added in Qovery Console:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/cra-envs/3.png",alt:"create-react-app environment variables"})),Object(i.b)("h2",{id:"going-prod"},"Going Prod"),Object(i.b)("p",null,"To optimize our application for production usage, we\u2019ll use a Nginx server to serve our frontend static content. To do so, we need to update our Dockerfile to the following:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'FROM node:14-alpine AS builder\nENV NODE_ENV production\n\nARG REACT_APP_MSG\nENV REACT_APP_MSG $REACT_APP_MSG\n\n# Add a work directory\nWORKDIR /app\n# Cache and Install dependencies\nCOPY package.json .\nCOPY yarn.lock .\nRUN yarn install --production\n# Copy app files\nCOPY . .\n# Build the app\nRUN yarn build\n\n# Bundle static assets with nginx\nFROM nginx:1.21.0-alpine as production\nENV NODE_ENV production\n# Copy built assets from builder\nCOPY --from=builder /app/build /usr/share/nginx/html\n# Add your nginx.conf\nCOPY nginx.conf /etc/nginx/conf.d/default.conf\n# Expose port\nEXPOSE 3000\n# Start nginx\nCMD ["nginx", "-g", "daemon off;"]\n')),Object(i.b)("p",null,"It uses a Nginx server for hosting your application instead of starting a Node.js server, which is more optimal for production usage."),Object(i.b)("p",null,"Additionally, add a ",Object(i.b)("inlineCode",{parentName:"p"},"nginx.conf")," file with this content to configure your app:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"server {\n listen 80;\n\n location / {\n root /usr/share/nginx/html/;\n include /etc/nginx/mime.types;\n try_files $uri $uri/ /index.html;\n }\n}\n")),Object(i.b)("p",null,"Now, commit and push your changes - your ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app")," is handling env vars properly and is optimized for production usage."),Object(i.b)("h2",{id:"conclusion"},"Conclusion"),Object(i.b)("p",null,"In the guide, we went through managing environment variables in react / create-react-apps without resorting to using any bash scripts and host it on Qovery using Ngnix server."))}p.isMDXComponent=!0},420:function(e,n,t){var a;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=r.a.createContext({}),p=function(e){var n=r.a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):c({},n,{},e)),t},u=function(e){var n=p(e.components);return r.a.createElement(s.Provider,{value:n},e.children)},b={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},d=Object(a.forwardRef)((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=p(t),d=a,m=u["".concat(o,".").concat(d)]||u[d]||b[d]||i;return t?r.a.createElement(m,c({ref:n},s,{components:t})):r.a.createElement(m,c({ref:n},s))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=d;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,o[1]=c;for(var s=2;s1?arguments[1]:void 0,t),l=o>2?arguments[2]:void 0,s=void 0===l?t:r(l,t);s>c;)n[c++]=e;return n}},425:function(e,n,t){var a=t(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||t(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},426:function(e,n,t){"use strict";t(425);var a=t(0),r=t.n(a),i=t(421);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},427:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),c=t(430),l=t(20),s=t.n(l);n.a=function(e){var n,t=e.to,l=e.href,p=t||l,u=Object(c.a)(p),b=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&n&&n.disconnect()}}),[p,d,u]),p&&u?i.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(p),b.current=!0)},innerRef:function(e){var t,a;d&&e&&u&&(t=e,a=function(){window.docusaurus.prefetch(p)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),a())}))}))).observe(t))},to:p})):i.a.createElement("a",Object(a.a)({},e,{href:p}))}},429:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(427),o=t(420),c=t.n(o);t(133);n.a=function(e){var n=e.children,t=e.className,a=e.badge,o=e.leftIcon,l=e.rightIcon,s=e.size,p=e.target,u=e.to,b=c()("jump-to","jump-to--"+s,t),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},o&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+o})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",n),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:u,target:p,className:b},d):r.a.createElement(i.a,{to:u,className:b},d)}},430:function(e,n,t){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see a4459aa8.1148d970.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[164],{316:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return o})),t.d(n,"metadata",(function(){return c})),t.d(n,"rightToc",(function(){return l})),t.d(n,"default",(function(){return p}));var a=t(1),r=t(9),i=(t(0),t(425)),o=(t(424),t(429),t(431),{last_modified_on:"2021-12-27",$schema:"/.meta/.schemas/guides.json",title:"Managing Environment Variables in React (create-react-app)",description:"How to manage environemnt variables in applications bootstrapped with create-react-app",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","language: javascript"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Managing Environment Variables in React (create-react-app)",description:"How to manage environemnt variables in applications bootstrapped with create-react-app",permalink:"/guides/tutorial/managing-env-variables-in-create-react-app",readingTime:"5 min read",source:"@site/guides/tutorial/managing-env-variables-in-create-react-app.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"language: javascript",permalink:"/guides/tags/language-javascript"}],title:"Managing Environment Variables in React (create-react-app)",truncated:!1,prevItem:{title:"Kubernetes observability and monitoring with Datadog",permalink:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog"},nextItem:{title:"Microservices",permalink:"/guides/advanced/microservices"}},l=[{value:"Code Repository",id:"code-repository",children:[]},{value:"Environment Variables",id:"environment-variables",children:[{value:"Warning!",id:"warning",children:[]}]},{value:"Deployment",id:"deployment",children:[]},{value:"Adding Environment Variable",id:"adding-environment-variable",children:[]},{value:"Going Prod",id:"going-prod",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],s={rightToc:l};function p(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},s,t,{components:n,mdxType:"MDXLayout"}),Object(i.b)("p",null,"In this short guide, we'll go trough managing Secrets/Environment Variables in React applications created using ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app")," and deployed on Qovery."),Object(i.b)("p",null,"Most of the guides you can find online propose quite complex solutions with creating your own bash scripts to set up env variables in apps created by ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app")," - this guide will show you an easier alternative and a way to Dockerize your React app in production-ready way."),Object(i.b)("h2",{id:"code-repository"},"Code Repository"),Object(i.b)("p",null,"In this guide we'll use ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/cra-test"}),"https://github.com/pjeziorowski/cra-test")," repository - it's a sample application bootstrapped using ",Object(i.b)("inlineCode",{parentName:"p"},"npx create-react-app my-app")," command."),Object(i.b)("p",null,"After the application structure is generated, we dockerize the application by adding a ",Object(i.b)("inlineCode",{parentName:"p"},"Dockerfile")," with the following content:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'# Docker Image which is used as foundation to create\n# a custom Docker Image with this Dockerfile\nFROM node:10\n\n# A directory within the virtualized Docker environment\nWORKDIR /usr/src/app\n\n# Copies package.json and package-lock.json to Docker environment\nCOPY package*.json ./\n\n# Installs all node packages\nRUN npm install\n\n# Copies everything over to Docker environment\nCOPY . .\n\n# Uses port which is used by the actual application\nEXPOSE 3000\n\n# Finally runs the application\nCMD [ "npm", "start" ]\n')),Object(i.b)("p",null,"One more little thing that we change is creating a new constant that uses a value of ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_MSG")," environment variable to print a text on the website:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const msg = process.env.REACT_APP_MSG\n")),Object(i.b)("p",null,"And then, we print it in the UI:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'\n {msg}\n\n')),Object(i.b)("h2",{id:"environment-variables"},"Environment Variables"),Object(i.b)("p",null,"Let's now add a ",Object(i.b)("inlineCode",{parentName:"p"},".env")," file for the default environment variables for our React app. For this, we create a ",Object(i.b)("inlineCode",{parentName:"p"},".env")," file with the content:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'HOST="0.0.0.0"\nPORT="3000"\nREACT_APP_MSG="From .env"\n')),Object(i.b)("h3",{id:"warning"},"Warning!"),Object(i.b)("p",null,"For all custom environment variables in apps created via ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app"),", we need to use ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_")," prefix in env var names - it's a requirement, if we don't follow the convention, variables will not be accessible in our application!"),Object(i.b)("p",null,"Also, remember that all the values are accessible on the client-side (browser). You should not use it for any data that your users should not access in the browser."),Object(i.b)("h2",{id:"deployment"},"Deployment"),Object(i.b)("p",null,"Before overriding the default env vars hardcoded in our repository using Qovery, let's first deploy the app."),Object(i.b)("p",null,"To do so, add a new application using the code from previous steps. When configuring the application, don't forget to:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Use ",Object(i.b)("inlineCode",{parentName:"li"},"Docker")," build mode"),Object(i.b)("li",{parentName:"ul"},"Add port ",Object(i.b)("inlineCode",{parentName:"li"},"3000")," to expose the app on the internet")),Object(i.b)("p",null,"After the application is created, click on the ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," button in application actions."),Object(i.b)("p",null,"In a few minutes, your application should be up and running:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/cra-envs/1.png",alt:"create-react-app environment variables"})),Object(i.b)("p",null,"As you see, the text in the link ",Object(i.b)("strong",{parentName:"p"},"From .env file indicates that the value")),Object(i.b)("h2",{id:"adding-environment-variable"},"Adding Environment Variable"),Object(i.b)("p",null,"Now, let's override our ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_MSG")," environment variable (and the text we display in the UI)."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/cra-envs/2.png",alt:"create-react-app environment variables"})),Object(i.b)("p",null,"After adding a new variable, restart the application. In a minute or so, we should see that the message in our website is updated with the value of ",Object(i.b)("inlineCode",{parentName:"p"},"REACT_APP_MSG")," we added in Qovery Console:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/cra-envs/3.png",alt:"create-react-app environment variables"})),Object(i.b)("h2",{id:"going-prod"},"Going Prod"),Object(i.b)("p",null,"To optimize our application for production usage, we\u2019ll use a Nginx server to serve our frontend static content. To do so, we need to update our Dockerfile to the following:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'FROM node:14-alpine AS builder\nENV NODE_ENV production\n\nARG REACT_APP_MSG\nENV REACT_APP_MSG $REACT_APP_MSG\n\n# Add a work directory\nWORKDIR /app\n# Cache and Install dependencies\nCOPY package.json .\nCOPY yarn.lock .\nRUN yarn install --production\n# Copy app files\nCOPY . .\n# Build the app\nRUN yarn build\n\n# Bundle static assets with nginx\nFROM nginx:1.21.0-alpine as production\nENV NODE_ENV production\n# Copy built assets from builder\nCOPY --from=builder /app/build /usr/share/nginx/html\n# Add your nginx.conf\nCOPY nginx.conf /etc/nginx/conf.d/default.conf\n# Expose port\nEXPOSE 3000\n# Start nginx\nCMD ["nginx", "-g", "daemon off;"]\n')),Object(i.b)("p",null,"It uses a Nginx server for hosting your application instead of starting a Node.js server, which is more optimal for production usage."),Object(i.b)("p",null,"Additionally, add a ",Object(i.b)("inlineCode",{parentName:"p"},"nginx.conf")," file with this content to configure your app:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"server {\n listen 80;\n\n location / {\n root /usr/share/nginx/html/;\n include /etc/nginx/mime.types;\n try_files $uri $uri/ /index.html;\n }\n}\n")),Object(i.b)("p",null,"Now, commit and push your changes - your ",Object(i.b)("inlineCode",{parentName:"p"},"create-react-app")," is handling env vars properly and is optimized for production usage."),Object(i.b)("h2",{id:"conclusion"},"Conclusion"),Object(i.b)("p",null,"In the guide, we went through managing environment variables in react / create-react-apps without resorting to using any bash scripts and host it on Qovery using Ngnix server."))}p.isMDXComponent=!0},423:function(e,n,t){var a;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=r.a.createContext({}),p=function(e){var n=r.a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):c({},n,{},e)),t},u=function(e){var n=p(e.components);return r.a.createElement(s.Provider,{value:n},e.children)},b={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},d=Object(a.forwardRef)((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=p(t),d=a,m=u["".concat(o,".").concat(d)]||u[d]||b[d]||i;return t?r.a.createElement(m,c({ref:n},s,{components:t})):r.a.createElement(m,c({ref:n},s))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=d;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,o[1]=c;for(var s=2;s1?arguments[1]:void 0,t),l=o>2?arguments[2]:void 0,s=void 0===l?t:r(l,t);s>c;)n[c++]=e;return n}},428:function(e,n,t){var a=t(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||t(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,n,t){"use strict";t(428);var a=t(0),r=t.n(a),i=t(424);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},430:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),c=t(432),l=t(20),s=t.n(l);n.a=function(e){var n,t=e.to,l=e.href,p=t||l,u=Object(c.a)(p),b=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&n&&n.disconnect()}}),[p,d,u]),p&&u?i.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(p),b.current=!0)},innerRef:function(e){var t,a;d&&e&&u&&(t=e,a=function(){window.docusaurus.prefetch(p)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),a())}))}))).observe(t))},to:p})):i.a.createElement("a",Object(a.a)({},e,{href:p}))}},431:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(430),o=t(423),c=t.n(o);t(133);n.a=function(e){var n=e.children,t=e.className,a=e.badge,o=e.leftIcon,l=e.rightIcon,s=e.size,p=e.target,u=e.to,b=c()("jump-to","jump-to--"+s,t),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},o&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+o})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",n),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:u,target:p,className:b},d):r.a.createElement(i.a,{to:u,className:b},d)}},432:function(e,n,t){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/a4c8ecc0.d76b8560.js.LICENSE.txt b/a4459aa8.1148d970.js.LICENSE.txt similarity index 100% rename from a4c8ecc0.d76b8560.js.LICENSE.txt rename to a4459aa8.1148d970.js.LICENSE.txt diff --git a/a4a09dfe.3ef2868d.js b/a4a09dfe.8565575d.js similarity index 95% rename from a4a09dfe.3ef2868d.js rename to a4a09dfe.8565575d.js index d228264e3c..9823c5241d 100644 --- a/a4a09dfe.3ef2868d.js +++ b/a4a09dfe.8565575d.js @@ -1,2 +1,2 @@ -/*! For license information please see a4a09dfe.3ef2868d.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[162],{314:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return l})),t.d(n,"metadata",(function(){return b})),t.d(n,"rightToc",(function(){return s})),t.d(n,"default",(function(){return m}));var r=t(1),o=t(9),i=(t(0),t(422)),a=(t(429),t(421)),c=t(426),l={last_modified_on:"2023-09-27",title:"Environment",description:"Learn how to configure your Environments on Qovery"},b={id:"using-qovery/configuration/environment",title:"Environment",description:"Learn how to configure your Environments on Qovery",source:"@site/docs/using-qovery/configuration/environment.md",permalink:"/docs/using-qovery/configuration/environment",sidebar:"docs",previous:{title:"Project",permalink:"/docs/using-qovery/configuration/project"},next:{title:"Application",permalink:"/docs/using-qovery/configuration/application"}},s=[{value:"Types of environment",id:"types-of-environment",children:[]},{value:"Create an environment",id:"create-an-environment",children:[]},{value:"Editing the environment settings",id:"editing-the-environment-settings",children:[{value:"General settings",id:"general-settings",children:[]},{value:"Deployment Rule",id:"deployment-rule",children:[]},{value:"Deployment Pipeline",id:"deployment-pipeline",children:[]},{value:"Preview environment",id:"preview-environment",children:[]}]},{value:"Clone environment",id:"clone-environment",children:[]},{value:"Terraform exporter",id:"terraform-exporter",children:[]},{value:"Deploy an environment",id:"deploy-an-environment",children:[]},{value:"Delete an environment",id:"delete-an-environment",children:[]}],p={rightToc:s};function m(e){var n=e.components,t=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(r.a)({},p,t,{components:n,mdxType:"MDXLayout"}),Object(i.b)(c.a,{name:"documentation",mdxType:"Assumptions"},Object(i.b)("p",null,"You have created a ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/project/"}),"Project"),".")),Object(i.b)("p",null,"An ",Object(i.b)("strong",{parentName:"p"},"Environment")," is a group of ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/"}),"applications")," and ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/"}),"databases")," running within the same namespace. A ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/project/"}),"Project")," can have multiple ",Object(i.b)("strong",{parentName:"p"},"Environments"),"."),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Applications and databases from an Environment are isolated from other Environments.")),Object(i.b)("h2",{id:"types-of-environment"},"Types of environment"),Object(i.b)("p",null,"There are different types of environments that can be defined within Qovery. Types of environment are also called ",Object(i.b)("inlineCode",{parentName:"p"},"mode"),", to label it and share with others in the organization how to use it.\nHere is the mode you should set depending of the use of your Environment."),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"environment mode"),Object(i.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"recommended mode"),Object(i.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"why"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Production"),Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Production environment should not be stopped or deleted by anyone."),Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Staging"),Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Staging environment reflects how things work and is sometimes as critical as production for companies."),Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Development"),Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Development environment is a working environment that could be used to develop and test new features and fixes."),Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}))))),Object(i.b)("p",null,"A special mode ",Object(i.b)("inlineCode",{parentName:"p"},"Preview")," exists and it is automatically set when a ",Object(i.b)("inlineCode",{parentName:"p"},"Preview Environment")," is created on a new pull request. Have a look at ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"#preview-environment"}),"this section")," to know more about preview environments."),Object(i.b)("h2",{id:"create-an-environment"},"Create an environment"),Object(i.b)("p",null,"You can create a new environment by clicking on the ",Object(i.b)("inlineCode",{parentName:"p"},"Create environment")," button of the Environment list page."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/environment/create_environment_1.png",alt:"Create an environment"})),Object(i.b)("p",null,"A modal will appear that will allow you to specify following parameters"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"name"),": Give a name to your environment that is easily recognizable by anyone from your team. It is good practice to name your environment ",Object(i.b)("inlineCode",{parentName:"li"},"production"),", ",Object(i.b)("inlineCode",{parentName:"li"},"main")," or ",Object(i.b)("inlineCode",{parentName:"li"},"master"),", ",Object(i.b)("inlineCode",{parentName:"li"},"staging"),", ",Object(i.b)("inlineCode",{parentName:"li"},"dev"),", ",Object(i.b)("inlineCode",{parentName:"li"},"fix/xxx"),", ",Object(i.b)("inlineCode",{parentName:"li"},"feat/xxx"),", depending on the purpose of your environment."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"mode"),": Specify environment mode. See ",Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"#types-of-environment"}),"Types of environment")," section. If ",Object(i.b)("inlineCode",{parentName:"li"},"automatic")," is chosen, the mode will be automatically selected based on the configured deployment rules. See the ",Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/deployment-rule/#project-deployment-rules"}),"Project Deployment Rules section")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"cluster")," : Specify the organization cluster on which this new environment will be deployed. If ",Object(i.b)("inlineCode",{parentName:"li"},"automatic")," is chosen, the cluster will be automatically selected based on the configured deployment rules. See the ",Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/deployment-rule/#project-deployment-rules"}),"Project Deployment Rules section"))),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/environment/create_environment_2.png",alt:"Create an environment - Modal"})),Object(i.b)("p",null,"Once created you can start adding your services within it depending on your need:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/application/"}),"Application"),": generic long-running workload"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cronjob/"}),"Cronjob"),": scheduled task"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"Lifecycle Job"),": generic task to be executed at environment start/stop/delete."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/database/"}),"Database"),": managed or container database")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/environment/create_service.png",alt:"Create Service"})),Object(i.b)("h2",{id:"editing-the-environment-settings"},"Editing the environment settings"),Object(i.b)("p",null,"You can access the environment settings by opening the ",Object(i.b)("inlineCode",{parentName:"p"},"SETTINGS")," tab."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/environment/environment_settings.png",alt:"Environment settings tab"})),Object(i.b)("h3",{id:"general-settings"},"General settings"),Object(i.b)("p",null,"On the ",Object(i.b)("inlineCode",{parentName:"p"},"General")," tab, you will be able to update your environment name. It will also display the environment mode and the cluster assigned to your environment."),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Please note that the associated cluster is not editable after the environment was provisioned. If you need to edit it, you have to ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"#clone-environment"}),"clone the environment")," on the desired cluster")),Object(i.b)("h3",{id:"deployment-rule"},"Deployment Rule"),Object(i.b)("p",null,"Using Deployment Rules is a good practice to drastically ",Object(i.b)("strong",{parentName:"p"},"reduce your cost"),". To know more of the benefit of using them, have a look at the ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/deployment-rule/"}),"Deployment Rules section"),"."),Object(i.b)("p",null,"A default deployment configuration is applied to your environment when it's created but you can modify this default behaviour by creating a ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/deployment-rule/#project-deployment-rules"}),"dedicated rule at project level")," that will affect any new environment created and matching the condition."),Object(i.b)("p",null,"Once created, you can edit the deployment rule of the environment from the deployment rules settings."),Object(i.b)("p",null,"Below you can find the description of the deployment rule settings that can be modified for a specific environment"),Object(i.b)("h4",{id:"start--stop"},"Start & Stop"),Object(i.b)("p",null,"The start and stop section allow you to override the default settings applied by the project rule to precisely set up when the environment should be deployed and cleaned up."),Object(i.b)("h3",{id:"deployment-pipeline"},"Deployment Pipeline"),Object(i.b)("p",null,"This section allows you to configure the deployment pipeline to be executed when a deployment on the environment is triggered. More in particular, you can define the deployment order of each service within your environment."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/environment/deployment_pipeline.png",alt:"Deployment Pipeline"})),Object(i.b)("p",null,"You can get more information about the Qovery deployment pipeline and how it works within ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deployment-pipeline/"}),"this section"),"."),Object(i.b)("h4",{id:"editing-deployment-order"},"Editing deployment order"),Object(i.b)("p",null,"You can edit the order simply by drag and drop the service from one stage to another."),Object(i.b)("p",null,"You can also modify the order of an entire stage by opening the ",Object(i.b)("inlineCode",{parentName:"p"},"3 dots menu")," of the stage and clicking on ",Object(i.b)("inlineCode",{parentName:"p"},"Edit order")),Object(i.b)("h4",{id:"adding-a-new-stage"},"Adding a new stage"),Object(i.b)("p",null,"You can add a new stage by pressing the ",Object(i.b)("inlineCode",{parentName:"p"},"Add stage")," button. A name and a description are required to create the new stage."),Object(i.b)("h4",{id:"editing-deployment-stage"},"Editing deployment stage"),Object(i.b)("p",null,"You can modify the name and the description of a stage by opening the ",Object(i.b)("inlineCode",{parentName:"p"},"3 dots menu")," of the stage and clicking on ",Object(i.b)("inlineCode",{parentName:"p"},"Edit order")),Object(i.b)("h3",{id:"preview-environment"},"Preview environment"),Object(i.b)("p",null,"Use Preview Environment to get early feedback on your application changes by creating a dedicated environment for each of your pull requests. Your production environment runs 24/7, where your other environments may not need to run all day long. E.g. you may need to run Environments to get early feedback on your application changes before the changes are merged into production. This is what we call ",Object(i.b)("strong",{parentName:"p"},"Preview Environment"),"."),Object(i.b)("blockquote",null,Object(i.b)("p",{parentName:"blockquote"}," Sometimes ",Object(i.b)("strong",{parentName:"p"},"Preview Environment")," is also known as ",Object(i.b)("strong",{parentName:"p"},"Ephemeral Environment"),", ",Object(i.b)("strong",{parentName:"p"},"Temporary Environment"),", ",Object(i.b)("strong",{parentName:"p"},"Development Environment"),", ",Object(i.b)("strong",{parentName:"p"},"Review App"),".")),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"The feature works only for application deployed from a git repository but you can still re-create the same behaviour with container images by integrating your CI. Have a look at ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/"}),"this section")," on how to.")),Object(i.b)(a.a,{type:"success",mdxType:"Alert"},Object(i.b)("p",null,"Check out ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners/"}),"this step-by-step guide to get started with the Preview Environments"))),Object(i.b)("p",null,"The preview environment section allows you to manage the complete setup of your preview environment feature"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/environments/preview_environment.png",alt:"Preview Environment Settings"})),Object(i.b)("h4",{id:"turn-on-preview-environments"},"Turn on Preview Environments"),Object(i.b)("p",null,"it allows you to enable the preview environment feature for the current environment. Any PR opened on a service belonging to this environment will trigger the preview environment flow."),Object(i.b)("h4",{id:"create-on-demand"},"Create on demand"),Object(i.b)("p",null,"You can define the behaviour to follow for the creation of the preview environments:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"On Demand (Flag enabled)"),Object(i.b)("li",{parentName:"ul"},"On every PR (Flag disabled)")),Object(i.b)("p",null,Object(i.b)("em",{parentName:"p"},"On Demand Flow")),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"A message is dropped on the PR asking you if you want to create a preview environment or not. You will get the list of environments where the preview env feature is activated (in case you have multiple environments) and the command to add as a comment of your PR to trigger the preview."),Object(i.b)("li",{parentName:"ol"},"you will decide weather to create a preview environment or not by typing the right command as a comment within the PR"),Object(i.b)("li",{parentName:"ol"},"once the command is added in the comments, the preview creation is triggered and your preview environment is created and its deployment starts"),Object(i.b)("li",{parentName:"ol"},"once the deployment is completed, an additional comment will be posted in the PR, providing you with URLs to access your services.")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/environments/preview_env_flow_ondemand.png",alt:"Preview Environment Settings"})),Object(i.b)("p",null,Object(i.b)("em",{parentName:"p"},"On every PR Flow"),"\nSame as above but the preview environment creation flow is triggered automatically without any user intervention (only step 3 and 4)"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/environments/Preview_Environment_Github_Bot_Message.png",alt:"Preview Environment Github Bot Message"})),Object(i.b)("h4",{id:"auto-delete"},"Auto-delete"),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Auto-delete")," feature allows you to control if your applications should be, by default, automatically deleted after branch merging or deletion."),Object(i.b)("h4",{id:"service-list"},"Service List"),Object(i.b)("p",null,"By default the preview environment feature is activated on any services of the environment connected to a git repository. In this sectoin you can decide to activate/desactivate the feature for a specific service."),Object(i.b)("h2",{id:"clone-environment"},"Clone environment"),Object(i.b)("p",null,"Cloning an existing environnment is convenient for those use cases:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Make a demo without impacting the original environment."),Object(i.b)("li",{parentName:"ul"},"Validate a feature on a dedicated environment.")),Object(i.b)("p",null,"Cloning an environment is possible directly from the 3 dots menu of your environment."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/environment/clone_environment.png",alt:"Environment Clone"})),Object(i.b)("p",null,"When cloning an environment, every configuration of the original environment will be copied except for:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/application/#domains"}),"Application custom domains"),": custom domains are not cloned to avoid collision."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/environment-variable/#built_in-variables"}),"Application BUILT_IN variables"),": Since completely new services will be create, the original built_in variables will be replaced. Aliases and overrides are preserved during the clone operation.")),Object(i.b)("h2",{id:"terraform-exporter"},"Terraform exporter"),Object(i.b)("p",null,"You can export the configuration of your environment as a Terraform manifest via the ",Object(i.b)("inlineCode",{parentName:"p"},"Export as Terraform")," option. This is helpful when you want to manage your configuration via Terraform: instead of creating the terraform manifest by hand, you can build the setup via the Qovery interface and export is as a Terraform file"),Object(i.b)("p",null,"The export will contain the Terraform definition of the environment, the services within it but as well all the other resources linked to the environment (organization, cluster, project)."),Object(i.b)("p",null,"You can decide wether or not the export should contain or not the secrets defined within the Qovery console."),Object(i.b)("p",null,"Here's a video explaining how it works:"),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/4642112b9f2846789fb0ba8fc14726b5",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)("h2",{id:"deploy-an-environment"},"Deploy an environment"),Object(i.b)("p",null,"Have a look at the ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/"}),"Deployment Management")," section for more information on how to deploy your environment."),Object(i.b)("h2",{id:"delete-an-environment"},"Delete an environment"),Object(i.b)(a.a,{type:"danger",mdxType:"Alert"},Object(i.b)("p",null,"This is a non-recoverable operation. By deleting your environment, all your running applications and data within the environment are deleted.")),Object(i.b)("p",null,"To delete your environment, you must go in the ",Object(i.b)("inlineCode",{parentName:"p"},"settings")," > ",Object(i.b)("inlineCode",{parentName:"p"},"Danger zone")," and delete your Environment."))}m.isMDXComponent=!0},420:function(e,n,t){var r;!function(){"use strict";var t={}.hasOwnProperty;function o(){for(var e=[],n=0;n=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var b=o.a.createContext({}),s=function(e){var n=o.a.useContext(b),t=n;return e&&(t="function"==typeof e?e(n):c({},n,{},e)),t},p=function(e){var n=s(e.components);return o.a.createElement(b.Provider,{value:n},e.children)},m={inlineCode:"code",wrapper:function(e){var n=e.children;return o.a.createElement(o.a.Fragment,{},n)}},u=Object(r.forwardRef)((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,a=e.parentName,b=l(e,["components","mdxType","originalType","parentName"]),p=s(t),u=r,d=p["".concat(a,".").concat(u)]||p[u]||m[u]||i;return t?o.a.createElement(d,c({ref:n},b,{components:t})):o.a.createElement(d,c({ref:n},b))}));function d(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,a=new Array(i);a[0]=u;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,a[1]=c;for(var b=2;b1?arguments[1]:void 0,t),l=a>2?arguments[2]:void 0,b=void 0===l?t:o(l,t);b>c;)n[c++]=e;return n}},425:function(e,n,t){var r=t(28).f,o=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in o||t(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},426:function(e,n,t){"use strict";t(425);var r=t(0),o=t.n(r),i=t(421);n.a=function(e){var n=e.children,t=e.name;return o.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},427:function(e,n,t){"use strict";var r=t(1),o=t(0),i=t.n(o),a=t(39),c=t(430),l=t(20),b=t.n(l);n.a=function(e){var n,t=e.to,l=e.href,s=t||l,p=Object(c.a)(s),m=Object(o.useRef)(!1),u=b.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!u&&p&&window.docusaurus.prefetch(s),function(){u&&n&&n.disconnect()}}),[s,u,p]),s&&p?i.a.createElement(a.b,Object(r.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(s),m.current=!0)},innerRef:function(e){var t,r;u&&e&&p&&(t=e,r=function(){window.docusaurus.prefetch(s)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),r())}))}))).observe(t))},to:s})):i.a.createElement("a",Object(r.a)({},e,{href:s}))}},429:function(e,n,t){"use strict";var r=t(0),o=t.n(r),i=t(427),a=t(420),c=t.n(a);t(133);n.a=function(e){var n=e.children,t=e.className,r=e.badge,a=e.leftIcon,l=e.rightIcon,b=e.size,s=e.target,p=e.to,m=c()("jump-to","jump-to--"+b,t),u=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},a&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+a})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",n),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?o.a.createElement("a",{href:p,target:s,className:m},u):o.a.createElement(i.a,{to:p,className:m},u)}},430:function(e,n,t){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return r}))}}]); \ No newline at end of file +/*! For license information please see a4a09dfe.8565575d.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[165],{317:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return l})),t.d(n,"metadata",(function(){return b})),t.d(n,"rightToc",(function(){return s})),t.d(n,"default",(function(){return m}));var r=t(1),o=t(9),i=(t(0),t(425)),a=(t(431),t(424)),c=t(429),l={last_modified_on:"2023-09-27",title:"Environment",description:"Learn how to configure your Environments on Qovery"},b={id:"using-qovery/configuration/environment",title:"Environment",description:"Learn how to configure your Environments on Qovery",source:"@site/docs/using-qovery/configuration/environment.md",permalink:"/docs/using-qovery/configuration/environment",sidebar:"docs",previous:{title:"Project",permalink:"/docs/using-qovery/configuration/project"},next:{title:"Application",permalink:"/docs/using-qovery/configuration/application"}},s=[{value:"Types of environment",id:"types-of-environment",children:[]},{value:"Create an environment",id:"create-an-environment",children:[]},{value:"Editing the environment settings",id:"editing-the-environment-settings",children:[{value:"General settings",id:"general-settings",children:[]},{value:"Deployment Rule",id:"deployment-rule",children:[]},{value:"Deployment Pipeline",id:"deployment-pipeline",children:[]},{value:"Preview environment",id:"preview-environment",children:[]}]},{value:"Clone environment",id:"clone-environment",children:[]},{value:"Terraform exporter",id:"terraform-exporter",children:[]},{value:"Deploy an environment",id:"deploy-an-environment",children:[]},{value:"Delete an environment",id:"delete-an-environment",children:[]}],p={rightToc:s};function m(e){var n=e.components,t=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(r.a)({},p,t,{components:n,mdxType:"MDXLayout"}),Object(i.b)(c.a,{name:"documentation",mdxType:"Assumptions"},Object(i.b)("p",null,"You have created a ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/project/"}),"Project"),".")),Object(i.b)("p",null,"An ",Object(i.b)("strong",{parentName:"p"},"Environment")," is a group of ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/"}),"applications")," and ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/"}),"databases")," running within the same namespace. A ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/project/"}),"Project")," can have multiple ",Object(i.b)("strong",{parentName:"p"},"Environments"),"."),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Applications and databases from an Environment are isolated from other Environments.")),Object(i.b)("h2",{id:"types-of-environment"},"Types of environment"),Object(i.b)("p",null,"There are different types of environments that can be defined within Qovery. Types of environment are also called ",Object(i.b)("inlineCode",{parentName:"p"},"mode"),", to label it and share with others in the organization how to use it.\nHere is the mode you should set depending of the use of your Environment."),Object(i.b)("table",null,Object(i.b)("thead",{parentName:"table"},Object(i.b)("tr",{parentName:"thead"},Object(i.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"environment mode"),Object(i.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"recommended mode"),Object(i.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"why"))),Object(i.b)("tbody",{parentName:"table"},Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Production"),Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Production environment should not be stopped or deleted by anyone."),Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Staging"),Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Staging environment reflects how things work and is sometimes as critical as production for companies."),Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}))),Object(i.b)("tr",{parentName:"tbody"},Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Development"),Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Development environment is a working environment that could be used to develop and test new features and fixes."),Object(i.b)("td",Object(r.a)({parentName:"tr"},{align:null}))))),Object(i.b)("p",null,"A special mode ",Object(i.b)("inlineCode",{parentName:"p"},"Preview")," exists and it is automatically set when a ",Object(i.b)("inlineCode",{parentName:"p"},"Preview Environment")," is created on a new pull request. Have a look at ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"#preview-environment"}),"this section")," to know more about preview environments."),Object(i.b)("h2",{id:"create-an-environment"},"Create an environment"),Object(i.b)("p",null,"You can create a new environment by clicking on the ",Object(i.b)("inlineCode",{parentName:"p"},"Create environment")," button of the Environment list page."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/environment/create_environment_1.png",alt:"Create an environment"})),Object(i.b)("p",null,"A modal will appear that will allow you to specify following parameters"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"name"),": Give a name to your environment that is easily recognizable by anyone from your team. It is good practice to name your environment ",Object(i.b)("inlineCode",{parentName:"li"},"production"),", ",Object(i.b)("inlineCode",{parentName:"li"},"main")," or ",Object(i.b)("inlineCode",{parentName:"li"},"master"),", ",Object(i.b)("inlineCode",{parentName:"li"},"staging"),", ",Object(i.b)("inlineCode",{parentName:"li"},"dev"),", ",Object(i.b)("inlineCode",{parentName:"li"},"fix/xxx"),", ",Object(i.b)("inlineCode",{parentName:"li"},"feat/xxx"),", depending on the purpose of your environment."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"mode"),": Specify environment mode. See ",Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"#types-of-environment"}),"Types of environment")," section. If ",Object(i.b)("inlineCode",{parentName:"li"},"automatic")," is chosen, the mode will be automatically selected based on the configured deployment rules. See the ",Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/deployment-rule/#project-deployment-rules"}),"Project Deployment Rules section")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"cluster")," : Specify the organization cluster on which this new environment will be deployed. If ",Object(i.b)("inlineCode",{parentName:"li"},"automatic")," is chosen, the cluster will be automatically selected based on the configured deployment rules. See the ",Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/deployment-rule/#project-deployment-rules"}),"Project Deployment Rules section"))),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/environment/create_environment_2.png",alt:"Create an environment - Modal"})),Object(i.b)("p",null,"Once created you can start adding your services within it depending on your need:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/application/"}),"Application"),": generic long-running workload"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cronjob/"}),"Cronjob"),": scheduled task"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"Lifecycle Job"),": generic task to be executed at environment start/stop/delete."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/database/"}),"Database"),": managed or container database")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/environment/create_service.png",alt:"Create Service"})),Object(i.b)("h2",{id:"editing-the-environment-settings"},"Editing the environment settings"),Object(i.b)("p",null,"You can access the environment settings by opening the ",Object(i.b)("inlineCode",{parentName:"p"},"SETTINGS")," tab."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/environment/environment_settings.png",alt:"Environment settings tab"})),Object(i.b)("h3",{id:"general-settings"},"General settings"),Object(i.b)("p",null,"On the ",Object(i.b)("inlineCode",{parentName:"p"},"General")," tab, you will be able to update your environment name. It will also display the environment mode and the cluster assigned to your environment."),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Please note that the associated cluster is not editable after the environment was provisioned. If you need to edit it, you have to ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"#clone-environment"}),"clone the environment")," on the desired cluster")),Object(i.b)("h3",{id:"deployment-rule"},"Deployment Rule"),Object(i.b)("p",null,"Using Deployment Rules is a good practice to drastically ",Object(i.b)("strong",{parentName:"p"},"reduce your cost"),". To know more of the benefit of using them, have a look at the ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/deployment-rule/"}),"Deployment Rules section"),"."),Object(i.b)("p",null,"A default deployment configuration is applied to your environment when it's created but you can modify this default behaviour by creating a ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/deployment-rule/#project-deployment-rules"}),"dedicated rule at project level")," that will affect any new environment created and matching the condition."),Object(i.b)("p",null,"Once created, you can edit the deployment rule of the environment from the deployment rules settings."),Object(i.b)("p",null,"Below you can find the description of the deployment rule settings that can be modified for a specific environment"),Object(i.b)("h4",{id:"start--stop"},"Start & Stop"),Object(i.b)("p",null,"The start and stop section allow you to override the default settings applied by the project rule to precisely set up when the environment should be deployed and cleaned up."),Object(i.b)("h3",{id:"deployment-pipeline"},"Deployment Pipeline"),Object(i.b)("p",null,"This section allows you to configure the deployment pipeline to be executed when a deployment on the environment is triggered. More in particular, you can define the deployment order of each service within your environment."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/environment/deployment_pipeline.png",alt:"Deployment Pipeline"})),Object(i.b)("p",null,"You can get more information about the Qovery deployment pipeline and how it works within ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deployment-pipeline/"}),"this section"),"."),Object(i.b)("h4",{id:"editing-deployment-order"},"Editing deployment order"),Object(i.b)("p",null,"You can edit the order simply by drag and drop the service from one stage to another."),Object(i.b)("p",null,"You can also modify the order of an entire stage by opening the ",Object(i.b)("inlineCode",{parentName:"p"},"3 dots menu")," of the stage and clicking on ",Object(i.b)("inlineCode",{parentName:"p"},"Edit order")),Object(i.b)("h4",{id:"adding-a-new-stage"},"Adding a new stage"),Object(i.b)("p",null,"You can add a new stage by pressing the ",Object(i.b)("inlineCode",{parentName:"p"},"Add stage")," button. A name and a description are required to create the new stage."),Object(i.b)("h4",{id:"editing-deployment-stage"},"Editing deployment stage"),Object(i.b)("p",null,"You can modify the name and the description of a stage by opening the ",Object(i.b)("inlineCode",{parentName:"p"},"3 dots menu")," of the stage and clicking on ",Object(i.b)("inlineCode",{parentName:"p"},"Edit order")),Object(i.b)("h3",{id:"preview-environment"},"Preview environment"),Object(i.b)("p",null,"Use Preview Environment to get early feedback on your application changes by creating a dedicated environment for each of your pull requests. Your production environment runs 24/7, where your other environments may not need to run all day long. E.g. you may need to run Environments to get early feedback on your application changes before the changes are merged into production. This is what we call ",Object(i.b)("strong",{parentName:"p"},"Preview Environment"),"."),Object(i.b)("blockquote",null,Object(i.b)("p",{parentName:"blockquote"}," Sometimes ",Object(i.b)("strong",{parentName:"p"},"Preview Environment")," is also known as ",Object(i.b)("strong",{parentName:"p"},"Ephemeral Environment"),", ",Object(i.b)("strong",{parentName:"p"},"Temporary Environment"),", ",Object(i.b)("strong",{parentName:"p"},"Development Environment"),", ",Object(i.b)("strong",{parentName:"p"},"Review App"),".")),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"The feature works only for application deployed from a git repository but you can still re-create the same behaviour with container images by integrating your CI. Have a look at ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/"}),"this section")," on how to.")),Object(i.b)(a.a,{type:"success",mdxType:"Alert"},Object(i.b)("p",null,"Check out ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners/"}),"this step-by-step guide to get started with the Preview Environments"))),Object(i.b)("p",null,"The preview environment section allows you to manage the complete setup of your preview environment feature"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/environments/preview_environment.png",alt:"Preview Environment Settings"})),Object(i.b)("h4",{id:"turn-on-preview-environments"},"Turn on Preview Environments"),Object(i.b)("p",null,"it allows you to enable the preview environment feature for the current environment. Any PR opened on a service belonging to this environment will trigger the preview environment flow."),Object(i.b)("h4",{id:"create-on-demand"},"Create on demand"),Object(i.b)("p",null,"You can define the behaviour to follow for the creation of the preview environments:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"On Demand (Flag enabled)"),Object(i.b)("li",{parentName:"ul"},"On every PR (Flag disabled)")),Object(i.b)("p",null,Object(i.b)("em",{parentName:"p"},"On Demand Flow")),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"A message is dropped on the PR asking you if you want to create a preview environment or not. You will get the list of environments where the preview env feature is activated (in case you have multiple environments) and the command to add as a comment of your PR to trigger the preview."),Object(i.b)("li",{parentName:"ol"},"you will decide weather to create a preview environment or not by typing the right command as a comment within the PR"),Object(i.b)("li",{parentName:"ol"},"once the command is added in the comments, the preview creation is triggered and your preview environment is created and its deployment starts"),Object(i.b)("li",{parentName:"ol"},"once the deployment is completed, an additional comment will be posted in the PR, providing you with URLs to access your services.")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/environments/preview_env_flow_ondemand.png",alt:"Preview Environment Settings"})),Object(i.b)("p",null,Object(i.b)("em",{parentName:"p"},"On every PR Flow"),"\nSame as above but the preview environment creation flow is triggered automatically without any user intervention (only step 3 and 4)"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/environments/Preview_Environment_Github_Bot_Message.png",alt:"Preview Environment Github Bot Message"})),Object(i.b)("h4",{id:"auto-delete"},"Auto-delete"),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Auto-delete")," feature allows you to control if your applications should be, by default, automatically deleted after branch merging or deletion."),Object(i.b)("h4",{id:"service-list"},"Service List"),Object(i.b)("p",null,"By default the preview environment feature is activated on any services of the environment connected to a git repository. In this sectoin you can decide to activate/desactivate the feature for a specific service."),Object(i.b)("h2",{id:"clone-environment"},"Clone environment"),Object(i.b)("p",null,"Cloning an existing environnment is convenient for those use cases:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Make a demo without impacting the original environment."),Object(i.b)("li",{parentName:"ul"},"Validate a feature on a dedicated environment.")),Object(i.b)("p",null,"Cloning an environment is possible directly from the 3 dots menu of your environment."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/environment/clone_environment.png",alt:"Environment Clone"})),Object(i.b)("p",null,"When cloning an environment, every configuration of the original environment will be copied except for:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/application/#domains"}),"Application custom domains"),": custom domains are not cloned to avoid collision."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/environment-variable/#built_in-variables"}),"Application BUILT_IN variables"),": Since completely new services will be create, the original built_in variables will be replaced. Aliases and overrides are preserved during the clone operation.")),Object(i.b)("h2",{id:"terraform-exporter"},"Terraform exporter"),Object(i.b)("p",null,"You can export the configuration of your environment as a Terraform manifest via the ",Object(i.b)("inlineCode",{parentName:"p"},"Export as Terraform")," option. This is helpful when you want to manage your configuration via Terraform: instead of creating the terraform manifest by hand, you can build the setup via the Qovery interface and export is as a Terraform file"),Object(i.b)("p",null,"The export will contain the Terraform definition of the environment, the services within it but as well all the other resources linked to the environment (organization, cluster, project)."),Object(i.b)("p",null,"You can decide wether or not the export should contain or not the secrets defined within the Qovery console."),Object(i.b)("p",null,"Here's a video explaining how it works:"),Object(i.b)("div",{class:"video-container"},Object(i.b)("p",{align:"center"},Object(i.b)("iframe",{src:"https://www.loom.com/embed/4642112b9f2846789fb0ba8fc14726b5",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(i.b)("h2",{id:"deploy-an-environment"},"Deploy an environment"),Object(i.b)("p",null,"Have a look at the ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/"}),"Deployment Management")," section for more information on how to deploy your environment."),Object(i.b)("h2",{id:"delete-an-environment"},"Delete an environment"),Object(i.b)(a.a,{type:"danger",mdxType:"Alert"},Object(i.b)("p",null,"This is a non-recoverable operation. By deleting your environment, all your running applications and data within the environment are deleted.")),Object(i.b)("p",null,"To delete your environment, you must go in the ",Object(i.b)("inlineCode",{parentName:"p"},"settings")," > ",Object(i.b)("inlineCode",{parentName:"p"},"Danger zone")," and delete your Environment."))}m.isMDXComponent=!0},423:function(e,n,t){var r;!function(){"use strict";var t={}.hasOwnProperty;function o(){for(var e=[],n=0;n=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var b=o.a.createContext({}),s=function(e){var n=o.a.useContext(b),t=n;return e&&(t="function"==typeof e?e(n):c({},n,{},e)),t},p=function(e){var n=s(e.components);return o.a.createElement(b.Provider,{value:n},e.children)},m={inlineCode:"code",wrapper:function(e){var n=e.children;return o.a.createElement(o.a.Fragment,{},n)}},u=Object(r.forwardRef)((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,a=e.parentName,b=l(e,["components","mdxType","originalType","parentName"]),p=s(t),u=r,d=p["".concat(a,".").concat(u)]||p[u]||m[u]||i;return t?o.a.createElement(d,c({ref:n},b,{components:t})):o.a.createElement(d,c({ref:n},b))}));function d(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,a=new Array(i);a[0]=u;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,a[1]=c;for(var b=2;b1?arguments[1]:void 0,t),l=a>2?arguments[2]:void 0,b=void 0===l?t:o(l,t);b>c;)n[c++]=e;return n}},428:function(e,n,t){var r=t(28).f,o=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in o||t(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,n,t){"use strict";t(428);var r=t(0),o=t.n(r),i=t(424);n.a=function(e){var n=e.children,t=e.name;return o.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},430:function(e,n,t){"use strict";var r=t(1),o=t(0),i=t.n(o),a=t(39),c=t(432),l=t(20),b=t.n(l);n.a=function(e){var n,t=e.to,l=e.href,s=t||l,p=Object(c.a)(s),m=Object(o.useRef)(!1),u=b.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!u&&p&&window.docusaurus.prefetch(s),function(){u&&n&&n.disconnect()}}),[s,u,p]),s&&p?i.a.createElement(a.b,Object(r.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(s),m.current=!0)},innerRef:function(e){var t,r;u&&e&&p&&(t=e,r=function(){window.docusaurus.prefetch(s)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),r())}))}))).observe(t))},to:s})):i.a.createElement("a",Object(r.a)({},e,{href:s}))}},431:function(e,n,t){"use strict";var r=t(0),o=t.n(r),i=t(430),a=t(423),c=t.n(a);t(133);n.a=function(e){var n=e.children,t=e.className,r=e.badge,a=e.leftIcon,l=e.rightIcon,b=e.size,s=e.target,p=e.to,m=c()("jump-to","jump-to--"+b,t),u=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},a&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+a})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",n),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?o.a.createElement("a",{href:p,target:s,className:m},u):o.a.createElement(i.a,{to:p,className:m},u)}},432:function(e,n,t){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/a8a9c166.26c10c96.js.LICENSE.txt b/a4a09dfe.8565575d.js.LICENSE.txt similarity index 100% rename from a8a9c166.26c10c96.js.LICENSE.txt rename to a4a09dfe.8565575d.js.LICENSE.txt diff --git a/acaf40e9.7fe44568.js b/a4c8ecc0.9c2a8a54.js similarity index 95% rename from acaf40e9.7fe44568.js rename to a4c8ecc0.9c2a8a54.js index 0f2cc016b5..cbd8fecec8 100644 --- a/acaf40e9.7fe44568.js +++ b/a4c8ecc0.9c2a8a54.js @@ -1,2 +1,2 @@ -/*! For license information please see acaf40e9.7fe44568.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[170],{322:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return c})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),o=(n(0),n(422)),i=(n(421),n(426),n(429),{last_modified_on:"2022-03-09",$schema:"/.meta/.schemas/guides.json",title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2",readingTime:"8 min read",source:"@site/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",truncated:!1,prevItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1"},nextItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3"}},c=[{value:"Architecture",id:"architecture",children:[]},{value:"Hosting AppWrite Cloud",id:"hosting-appwrite-cloud",children:[]},{value:"Deploying AppWrite Cloud on Qovery",id:"deploying-appwrite-cloud-on-qovery",children:[{value:"Postgres",id:"postgres",children:[]},{value:"Hasura",id:"hasura",children:[]},{value:"Functions",id:"functions",children:[]},{value:"Deploy the environment",id:"deploy-the-environment",children:[]}]},{value:"Database Structure",id:"database-structure",children:[]},{value:"AppWrite Cloud API",id:"appwrite-cloud-api",children:[]},{value:"Testing AppWrite Cloud Backend",id:"testing-appwrite-cloud-backend",children:[{value:"Signup",id:"signup",children:[]},{value:"Create Project",id:"create-project",children:[]},{value:"Start / Stop Project",id:"start--stop-project",children:[]}]},{value:"AppWrite Cloud API domain",id:"appwrite-cloud-api-domain",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],s={rightToc:c};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"In the second part of the\xa0",Object(o.b)("em",{parentName:"p"},"Case Study with AppWrite"),", we will create the backend part of our AppWrite Cloud. The backend will communicate with Qovery API to request the infrastructure (",Object(o.b)("inlineCode",{parentName:"p"},"AppWrite")," instances and their dependencies, i.e. ",Object(o.b)("inlineCode",{parentName:"p"},"MariaDB")," and ",Object(o.b)("inlineCode",{parentName:"p"},"Redis"),") for AppWrite Cloud users. Qovery will take care of provisioning, managing, and running AppWrite instances and databases, while AppWrite Cloud will take care of providing a nice UI and other utilities for the users wanting to deploy AppWrite on a cloud-managed solution."),Object(o.b)("h2",{id:"architecture"},"Architecture"),Object(o.b)("p",null,"The backend of AppWrite Cloud will make use of a low-code tool ",Object(o.b)("inlineCode",{parentName:"p"},"Hasura"),". Hasura is an open-source project that allows building backend apps with minimal effort while still providing fast performance. It also allows executing custom business logic using cloud functions. Our Hasura backend will use ",Object(o.b)("inlineCode",{parentName:"p"},"PostgreSQL")," as its data store. In the first stage, the AppWrite Cloud backend will contain information about users and their projects. For all tasks related to running and managing the underlying infrastructure, it will call Qovery API and delegate those tasks to Qovery so that AppWrite Cloud can stay focused on delivering to their users what they really want - an excellent experience AppWrite, instead of wasting time on reinventing the wheel of managing the infrastructure."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-1.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"For all business logic, we will use the ",Object(o.b)("inlineCode",{parentName:"p"},"Async Actions")," feature of Hasura. In this approach, the Hasura backend calls external functions over the network and lets them perform any business logic required. The async functions can be hosted anywhere, as long as they conform to the contract required by Hasura."),Object(o.b)("h2",{id:"hosting-appwrite-cloud"},"Hosting AppWrite Cloud"),Object(o.b)("p",null,"Besides, hosting all the managed AppWrite projects of AppWrite Cloud users, Qovery can also host the whole AppWrite Cloud backend itself. Indeed, in this case study, we'll go through all the steps required to deploy AppWrite Cloud on Qovery."),Object(o.b)("h2",{id:"deploying-appwrite-cloud-on-qovery"},"Deploying AppWrite Cloud on Qovery"),Object(o.b)("p",null,"To deploy the AppWrite Cloud, we need to deploy a Hasura backend, a PostgreSQL database for Hasura, and our Go server for handling the custom business logic."),Object(o.b)("h3",{id:"postgres"},"Postgres"),Object(o.b)("p",null,"First, let's deploy our database. To do so, use Qovery Console to create a new project and environment, then click ",Object(o.b)("inlineCode",{parentName:"p"},"Add Database")," button and choose PostgreSQL ",Object(o.b)("inlineCode",{parentName:"p"},"v12"),"."),Object(o.b)("h3",{id:"hasura"},"Hasura"),Object(o.b)("p",null,"To deploy Hasura, fork this repository\xa0",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/hasura"}),"https://github.com/Qovery/hasura"),". Use ",Object(o.b)("inlineCode",{parentName:"p"},"DOCKER")," build mode and Port ",Object(o.b)("inlineCode",{parentName:"p"},"8080"),". Then, in the Environment Variables section, add the following variables:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_ENABLE_CONSOLE")," - true"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_ADMIN_SECRET")," - your Hasura admin secret (value up to you)"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_JWT_SECRET"))),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "type": "HS256",\n "key": "$KEY"\n}\n')),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"where ",Object(o.b)("inlineCode",{parentName:"li"},"$KEY")," is a minimum 32 character long string"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_DATABASE_URL")," - an alias to your previously created PostgreSQL URL")),Object(o.b)("h3",{id:"functions"},"Functions"),Object(o.b)("p",null,"Now, let's deploy our Go server. To do so, you can fork this repository\xa0",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/appwrite-functions"}),"https://github.com/pjeziorowski/appwrite-functions"),"."),Object(o.b)("p",null,"Create a new app using ",Object(o.b)("inlineCode",{parentName:"p"},"DOCKER")," build mode and Port ",Object(o.b)("inlineCode",{parentName:"p"},"3000"),"."),Object(o.b)("p",null,"Now, we need to set up a few environment variables:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"ORGANIZATION_ID_QOVERY")," - organization ID used as your AppWrite Cloud on Qovery"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"API_TOKEN_QOVERY")," - API token to use to interact with Qovery API"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_API_URL")," - location of your Hasura backend instance"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"SECRET")," - key to sign tokens, use the same value as in ",Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_JWT_SECRET")," key section"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_API_TOKEN")," - admin secret token of your Hasura instance")),Object(o.b)("h3",{id:"deploy-the-environment"},"Deploy the environment"),Object(o.b)("p",null,"After your project is set up as described above, deploy the whole environment, and your AppWrite Cloud backend will be ready to play and test."),Object(o.b)("h2",{id:"database-structure"},"Database Structure"),Object(o.b)("p",null,"All we need to store in the AppWrite Cloud database at the moment is users and their projects. For this, we will create a user table and project table that will contain AppWrite URLs and project names."),Object(o.b)("p",null,"To import the structure of the tables into the Hasura backend, you can use the metadata file located here ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/hasura/blob/main/appwrite-cloud-metadata.json"}),"hasura/appwrite-cloud-metadata.json at main \xb7 Qovery/hasura")),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"user")," table contains sign-in information (email and hashed password):"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-2.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"whereas the ",Object(o.b)("inlineCode",{parentName:"p"},"project")," table contains basic information about the project in AppWrite Cloud, URL to AppWrite instance as well as its mapping to a project in Qovery:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-3.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h2",{id:"appwrite-cloud-api"},"AppWrite Cloud API"),Object(o.b)("p",null,"The initial version of the API will allow to:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Signup")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Signin")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Create/Start/Stop/Delete AppWrite Instances"))),Object(o.b)("p",null,"The API will be exposed using Hasura Actions. Actions delegate the custom logic to handler functions we deployed in our Go server. Hasura will delegate the work of contacting the Qovery API to those functions."),Object(o.b)("p",null,"All the Actions were already imported into Hasura using the same metadata file as we used to import the structure of the tables."),Object(o.b)("p",null,"When you navigate to ",Object(o.b)("inlineCode",{parentName:"p"},"Actions")," section in Hasura, you'll see actions definition similar to this one:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-4.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"The functions serving those actions in our Golang app look more or less like this:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-go"}),'func stopProject(args StopProjectArgs, userId string) (response StopProjectOutput, err error) {\n log.Printf("received stop project request %v", args)\n\n response = StopProjectOutput{\n Ok: false,\n }\n\n // try to stop a project using Qovery API\n err = callQoveryApi(args.Input.Id)\n if err != nil {\n return response, err\n }\n\n response.Ok = true\n\n return response, nil\n}\n')),Object(o.b)("p",null,"You can see the whole code in your forked repository on ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/appwrite-functions"}),"Github"),"."),Object(o.b)("h2",{id:"testing-appwrite-cloud-backend"},"Testing AppWrite Cloud Backend"),Object(o.b)("h3",{id:"signup"},"Signup"),Object(o.b)("p",null,"After a few minutes of deployment, the first version of our managed cloud solution should be ready. Let's use the Hasura GraphQL API to create a new user."),Object(o.b)("p",null,"To do so, open your Hasura by clicking the Open button in your Hasura application. Then, run the following mutation in the GraphQL explorer:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'mutation {\n Signup(input: {email: "pjeziorowski@qovery.com", password: "mysecret"}) {\n accessToken\n }\n}\n')),Object(o.b)("p",null,"You'll end up with a response like this:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "data": {\n "Signup": {\n "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLXVzZXItaWQiOiIyIiwieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoiYWRtaW4iLCJ4LWhhc3VyYS1hbGxvd2VkLXJvbGVzIjpbImFkbWluIl19LCJleHAiOjE2Mzc0ODAxNDR9.aNv72YwjWXkKItDPxQOe5bB7LPo8ZCZ0Gqb3mR6_KQI"\n }\n }\n}\n')),Object(o.b)("p",null,"Great! We have just created our first user and received a token to interact with AppWrite Cloud API."),Object(o.b)("h3",{id:"create-project"},"Create Project"),Object(o.b)("p",null,"Now, let's create our first managed AppWrite instance. In headers, include ",Object(o.b)("inlineCode",{parentName:"p"},"Authorization")," header with the ",Object(o.b)("inlineCode",{parentName:"p"},"Bearer token")," received when signing up:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'mutation {\n CreateProject(input: {name: "myproject"}) {\n id\n name\n url\n }\n}\n')),Object(o.b)("p",null,"You should see a response similar to this one:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "data": {\n "CreateProject": {\n "id": 10,\n "name": "myproject",\n "url": ""\n }\n }\n}\n')),Object(o.b)("p",null,"Great! In the response, we have received the URL we can use to access our managed AppWrite instance."),Object(o.b)("p",null,"When we peek into Qovery UI, we see the created project for our managed AppWrite:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-5.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h3",{id:"start--stop-project"},"Start / Stop Project"),Object(o.b)("p",null,"It's the time to start our project. To do so, run the following mutation:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),"mutation {\n StartProject(input: {id: 10}) {\n ok\n }\n}\n")),Object(o.b)("p",null,"We should get this response:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "data": {\n "StartProject": {\n "ok": true\n }\n }\n}\n')),Object(o.b)("p",null,"And looking into Qovery, we'll see our environment is starting:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-6.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"After a few minutes, our AppWrite instance should be available up and running using the URL from the previous response. We can also list our projects to get all projects' URLs:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),"{\n project(where: {user: {id: {_eq: 1}}}) {\n id\n name\n url\n }\n}\n")),Object(o.b)("p",null,"Response:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "data": {\n "project": [\n {\n "id": 9,\n "name": "appwrite1",\n "url": "https://zd3da7904-z24aae066-gtw.oom.sh"\n },\n {\n "id": 10,\n "name": "myproject",\n "url": "https://zf3f05b5a-zab0fb2f8-gtw.oom.sh"\n }\n ]\n }\n}\n')),Object(o.b)("h2",{id:"appwrite-cloud-api-domain"},"AppWrite Cloud API domain"),Object(o.b)("p",null,"Now, as the last step of this part of tutorial, let's set up a custom domain for our AppWrite Cloud."),Object(o.b)("p",null,"To do so, all we need to do is to follow a few simple steps:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Navigate to the Hasura GraphQL API application in Qovery Console"),Object(o.b)("li",{parentName:"ol"},"Click ",Object(o.b)("inlineCode",{parentName:"li"},"Add")," button and select ",Object(o.b)("inlineCode",{parentName:"li"},"Custom Domain"))),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-7.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("ol",{start:3},Object(o.b)("li",{parentName:"ol"},"Type the name of desired domain, click ",Object(o.b)("inlineCode",{parentName:"li"},"Add")," and copy the ",Object(o.b)("inlineCode",{parentName:"li"},"Value")," displayed in the box below")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-8.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("ol",{start:4},Object(o.b)("li",{parentName:"ol"},"Add a ",Object(o.b)("inlineCode",{parentName:"li"},"CNAME")," record with value copied in the previous step in your domain provider DNS management settings")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-9.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("ol",{start:5},Object(o.b)("li",{parentName:"ol"},"Restart ",Object(o.b)("inlineCode",{parentName:"li"},"Hasura")," application")),Object(o.b)("p",null,"Congratulations, your AppWrite Cloud API will be exposed using your custom domain shortly."),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"In this tutorial, we have managed to bootstrap the backend for our AppWrite Cloud solution. Users can register, log in, create and deploy managed AppWrite projects. In the following steps, we will add more functionalities to our AppWrite Cloud offering, set up a nice to use web User Interface and continue adding new features to AppWrite Cloud on top of Qovery."))}p.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),p=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},u=function(e){var t=p(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),u=p(n),d=a,m=u["".concat(i,".").concat(d)]||u[d]||b[d]||o;return n?r.a.createElement(m,l({ref:t},s,{components:n})):r.a.createElement(m,l({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,i[1]=l;for(var s=2;s1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,s=void 0===c?n:r(c,n);s>l;)t[l++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(430),c=n(20),s=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,p=n||c,u=Object(l.a)(p),b=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&t&&t.disconnect()}}),[p,d,u]),p&&u?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(p),b.current=!0)},innerRef:function(e){var n,a;d&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:p})):o.a.createElement("a",Object(a.a)({},e,{href:p}))}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),i=n(420),l=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,s=e.size,p=e.target,u=e.to,b=l()("jump-to","jump-to--"+s,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:u,target:p,className:b},d):r.a.createElement(o.a,{to:u,className:b},d)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see a4c8ecc0.9c2a8a54.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[166],{318:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return c})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),o=(n(0),n(425)),i=(n(424),n(429),n(431),{last_modified_on:"2022-03-09",$schema:"/.meta/.schemas/guides.json",title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2",readingTime:"8 min read",source:"@site/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",truncated:!1,prevItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1"},nextItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3"}},c=[{value:"Architecture",id:"architecture",children:[]},{value:"Hosting AppWrite Cloud",id:"hosting-appwrite-cloud",children:[]},{value:"Deploying AppWrite Cloud on Qovery",id:"deploying-appwrite-cloud-on-qovery",children:[{value:"Postgres",id:"postgres",children:[]},{value:"Hasura",id:"hasura",children:[]},{value:"Functions",id:"functions",children:[]},{value:"Deploy the environment",id:"deploy-the-environment",children:[]}]},{value:"Database Structure",id:"database-structure",children:[]},{value:"AppWrite Cloud API",id:"appwrite-cloud-api",children:[]},{value:"Testing AppWrite Cloud Backend",id:"testing-appwrite-cloud-backend",children:[{value:"Signup",id:"signup",children:[]},{value:"Create Project",id:"create-project",children:[]},{value:"Start / Stop Project",id:"start--stop-project",children:[]}]},{value:"AppWrite Cloud API domain",id:"appwrite-cloud-api-domain",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],s={rightToc:c};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"In the second part of the\xa0",Object(o.b)("em",{parentName:"p"},"Case Study with AppWrite"),", we will create the backend part of our AppWrite Cloud. The backend will communicate with Qovery API to request the infrastructure (",Object(o.b)("inlineCode",{parentName:"p"},"AppWrite")," instances and their dependencies, i.e. ",Object(o.b)("inlineCode",{parentName:"p"},"MariaDB")," and ",Object(o.b)("inlineCode",{parentName:"p"},"Redis"),") for AppWrite Cloud users. Qovery will take care of provisioning, managing, and running AppWrite instances and databases, while AppWrite Cloud will take care of providing a nice UI and other utilities for the users wanting to deploy AppWrite on a cloud-managed solution."),Object(o.b)("h2",{id:"architecture"},"Architecture"),Object(o.b)("p",null,"The backend of AppWrite Cloud will make use of a low-code tool ",Object(o.b)("inlineCode",{parentName:"p"},"Hasura"),". Hasura is an open-source project that allows building backend apps with minimal effort while still providing fast performance. It also allows executing custom business logic using cloud functions. Our Hasura backend will use ",Object(o.b)("inlineCode",{parentName:"p"},"PostgreSQL")," as its data store. In the first stage, the AppWrite Cloud backend will contain information about users and their projects. For all tasks related to running and managing the underlying infrastructure, it will call Qovery API and delegate those tasks to Qovery so that AppWrite Cloud can stay focused on delivering to their users what they really want - an excellent experience AppWrite, instead of wasting time on reinventing the wheel of managing the infrastructure."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-1.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"For all business logic, we will use the ",Object(o.b)("inlineCode",{parentName:"p"},"Async Actions")," feature of Hasura. In this approach, the Hasura backend calls external functions over the network and lets them perform any business logic required. The async functions can be hosted anywhere, as long as they conform to the contract required by Hasura."),Object(o.b)("h2",{id:"hosting-appwrite-cloud"},"Hosting AppWrite Cloud"),Object(o.b)("p",null,"Besides, hosting all the managed AppWrite projects of AppWrite Cloud users, Qovery can also host the whole AppWrite Cloud backend itself. Indeed, in this case study, we'll go through all the steps required to deploy AppWrite Cloud on Qovery."),Object(o.b)("h2",{id:"deploying-appwrite-cloud-on-qovery"},"Deploying AppWrite Cloud on Qovery"),Object(o.b)("p",null,"To deploy the AppWrite Cloud, we need to deploy a Hasura backend, a PostgreSQL database for Hasura, and our Go server for handling the custom business logic."),Object(o.b)("h3",{id:"postgres"},"Postgres"),Object(o.b)("p",null,"First, let's deploy our database. To do so, use Qovery Console to create a new project and environment, then click ",Object(o.b)("inlineCode",{parentName:"p"},"Add Database")," button and choose PostgreSQL ",Object(o.b)("inlineCode",{parentName:"p"},"v12"),"."),Object(o.b)("h3",{id:"hasura"},"Hasura"),Object(o.b)("p",null,"To deploy Hasura, fork this repository\xa0",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/hasura"}),"https://github.com/Qovery/hasura"),". Use ",Object(o.b)("inlineCode",{parentName:"p"},"DOCKER")," build mode and Port ",Object(o.b)("inlineCode",{parentName:"p"},"8080"),". Then, in the Environment Variables section, add the following variables:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_ENABLE_CONSOLE")," - true"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_ADMIN_SECRET")," - your Hasura admin secret (value up to you)"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_JWT_SECRET"))),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "type": "HS256",\n "key": "$KEY"\n}\n')),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"where ",Object(o.b)("inlineCode",{parentName:"li"},"$KEY")," is a minimum 32 character long string"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_DATABASE_URL")," - an alias to your previously created PostgreSQL URL")),Object(o.b)("h3",{id:"functions"},"Functions"),Object(o.b)("p",null,"Now, let's deploy our Go server. To do so, you can fork this repository\xa0",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/appwrite-functions"}),"https://github.com/pjeziorowski/appwrite-functions"),"."),Object(o.b)("p",null,"Create a new app using ",Object(o.b)("inlineCode",{parentName:"p"},"DOCKER")," build mode and Port ",Object(o.b)("inlineCode",{parentName:"p"},"3000"),"."),Object(o.b)("p",null,"Now, we need to set up a few environment variables:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"ORGANIZATION_ID_QOVERY")," - organization ID used as your AppWrite Cloud on Qovery"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"API_TOKEN_QOVERY")," - API token to use to interact with Qovery API"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_API_URL")," - location of your Hasura backend instance"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"SECRET")," - key to sign tokens, use the same value as in ",Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_JWT_SECRET")," key section"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_API_TOKEN")," - admin secret token of your Hasura instance")),Object(o.b)("h3",{id:"deploy-the-environment"},"Deploy the environment"),Object(o.b)("p",null,"After your project is set up as described above, deploy the whole environment, and your AppWrite Cloud backend will be ready to play and test."),Object(o.b)("h2",{id:"database-structure"},"Database Structure"),Object(o.b)("p",null,"All we need to store in the AppWrite Cloud database at the moment is users and their projects. For this, we will create a user table and project table that will contain AppWrite URLs and project names."),Object(o.b)("p",null,"To import the structure of the tables into the Hasura backend, you can use the metadata file located here ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/hasura/blob/main/appwrite-cloud-metadata.json"}),"hasura/appwrite-cloud-metadata.json at main \xb7 Qovery/hasura")),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"user")," table contains sign-in information (email and hashed password):"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-2.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"whereas the ",Object(o.b)("inlineCode",{parentName:"p"},"project")," table contains basic information about the project in AppWrite Cloud, URL to AppWrite instance as well as its mapping to a project in Qovery:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-3.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h2",{id:"appwrite-cloud-api"},"AppWrite Cloud API"),Object(o.b)("p",null,"The initial version of the API will allow to:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Signup")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Signin")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Create/Start/Stop/Delete AppWrite Instances"))),Object(o.b)("p",null,"The API will be exposed using Hasura Actions. Actions delegate the custom logic to handler functions we deployed in our Go server. Hasura will delegate the work of contacting the Qovery API to those functions."),Object(o.b)("p",null,"All the Actions were already imported into Hasura using the same metadata file as we used to import the structure of the tables."),Object(o.b)("p",null,"When you navigate to ",Object(o.b)("inlineCode",{parentName:"p"},"Actions")," section in Hasura, you'll see actions definition similar to this one:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-4.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"The functions serving those actions in our Golang app look more or less like this:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-go"}),'func stopProject(args StopProjectArgs, userId string) (response StopProjectOutput, err error) {\n log.Printf("received stop project request %v", args)\n\n response = StopProjectOutput{\n Ok: false,\n }\n\n // try to stop a project using Qovery API\n err = callQoveryApi(args.Input.Id)\n if err != nil {\n return response, err\n }\n\n response.Ok = true\n\n return response, nil\n}\n')),Object(o.b)("p",null,"You can see the whole code in your forked repository on ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/appwrite-functions"}),"Github"),"."),Object(o.b)("h2",{id:"testing-appwrite-cloud-backend"},"Testing AppWrite Cloud Backend"),Object(o.b)("h3",{id:"signup"},"Signup"),Object(o.b)("p",null,"After a few minutes of deployment, the first version of our managed cloud solution should be ready. Let's use the Hasura GraphQL API to create a new user."),Object(o.b)("p",null,"To do so, open your Hasura by clicking the Open button in your Hasura application. Then, run the following mutation in the GraphQL explorer:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'mutation {\n Signup(input: {email: "pjeziorowski@qovery.com", password: "mysecret"}) {\n accessToken\n }\n}\n')),Object(o.b)("p",null,"You'll end up with a response like this:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "data": {\n "Signup": {\n "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLXVzZXItaWQiOiIyIiwieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoiYWRtaW4iLCJ4LWhhc3VyYS1hbGxvd2VkLXJvbGVzIjpbImFkbWluIl19LCJleHAiOjE2Mzc0ODAxNDR9.aNv72YwjWXkKItDPxQOe5bB7LPo8ZCZ0Gqb3mR6_KQI"\n }\n }\n}\n')),Object(o.b)("p",null,"Great! We have just created our first user and received a token to interact with AppWrite Cloud API."),Object(o.b)("h3",{id:"create-project"},"Create Project"),Object(o.b)("p",null,"Now, let's create our first managed AppWrite instance. In headers, include ",Object(o.b)("inlineCode",{parentName:"p"},"Authorization")," header with the ",Object(o.b)("inlineCode",{parentName:"p"},"Bearer token")," received when signing up:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'mutation {\n CreateProject(input: {name: "myproject"}) {\n id\n name\n url\n }\n}\n')),Object(o.b)("p",null,"You should see a response similar to this one:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "data": {\n "CreateProject": {\n "id": 10,\n "name": "myproject",\n "url": ""\n }\n }\n}\n')),Object(o.b)("p",null,"Great! In the response, we have received the URL we can use to access our managed AppWrite instance."),Object(o.b)("p",null,"When we peek into Qovery UI, we see the created project for our managed AppWrite:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-5.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h3",{id:"start--stop-project"},"Start / Stop Project"),Object(o.b)("p",null,"It's the time to start our project. To do so, run the following mutation:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),"mutation {\n StartProject(input: {id: 10}) {\n ok\n }\n}\n")),Object(o.b)("p",null,"We should get this response:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "data": {\n "StartProject": {\n "ok": true\n }\n }\n}\n')),Object(o.b)("p",null,"And looking into Qovery, we'll see our environment is starting:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-6.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"After a few minutes, our AppWrite instance should be available up and running using the URL from the previous response. We can also list our projects to get all projects' URLs:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),"{\n project(where: {user: {id: {_eq: 1}}}) {\n id\n name\n url\n }\n}\n")),Object(o.b)("p",null,"Response:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "data": {\n "project": [\n {\n "id": 9,\n "name": "appwrite1",\n "url": "https://zd3da7904-z24aae066-gtw.oom.sh"\n },\n {\n "id": 10,\n "name": "myproject",\n "url": "https://zf3f05b5a-zab0fb2f8-gtw.oom.sh"\n }\n ]\n }\n}\n')),Object(o.b)("h2",{id:"appwrite-cloud-api-domain"},"AppWrite Cloud API domain"),Object(o.b)("p",null,"Now, as the last step of this part of tutorial, let's set up a custom domain for our AppWrite Cloud."),Object(o.b)("p",null,"To do so, all we need to do is to follow a few simple steps:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Navigate to the Hasura GraphQL API application in Qovery Console"),Object(o.b)("li",{parentName:"ol"},"Click ",Object(o.b)("inlineCode",{parentName:"li"},"Add")," button and select ",Object(o.b)("inlineCode",{parentName:"li"},"Custom Domain"))),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-7.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("ol",{start:3},Object(o.b)("li",{parentName:"ol"},"Type the name of desired domain, click ",Object(o.b)("inlineCode",{parentName:"li"},"Add")," and copy the ",Object(o.b)("inlineCode",{parentName:"li"},"Value")," displayed in the box below")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-8.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("ol",{start:4},Object(o.b)("li",{parentName:"ol"},"Add a ",Object(o.b)("inlineCode",{parentName:"li"},"CNAME")," record with value copied in the previous step in your domain provider DNS management settings")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-9.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("ol",{start:5},Object(o.b)("li",{parentName:"ol"},"Restart ",Object(o.b)("inlineCode",{parentName:"li"},"Hasura")," application")),Object(o.b)("p",null,"Congratulations, your AppWrite Cloud API will be exposed using your custom domain shortly."),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"In this tutorial, we have managed to bootstrap the backend for our AppWrite Cloud solution. Users can register, log in, create and deploy managed AppWrite projects. In the following steps, we will add more functionalities to our AppWrite Cloud offering, set up a nice to use web User Interface and continue adding new features to AppWrite Cloud on top of Qovery."))}p.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),p=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},u=function(e){var t=p(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),u=p(n),d=a,m=u["".concat(i,".").concat(d)]||u[d]||b[d]||o;return n?r.a.createElement(m,l({ref:t},s,{components:n})):r.a.createElement(m,l({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,i[1]=l;for(var s=2;s1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,s=void 0===c?n:r(c,n);s>l;)t[l++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(432),c=n(20),s=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,p=n||c,u=Object(l.a)(p),b=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&t&&t.disconnect()}}),[p,d,u]),p&&u?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(p),b.current=!0)},innerRef:function(e){var n,a;d&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:p})):o.a.createElement("a",Object(a.a)({},e,{href:p}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),i=n(423),l=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,s=e.size,p=e.target,u=e.to,b=l()("jump-to","jump-to--"+s,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:u,target:p,className:b},d):r.a.createElement(o.a,{to:u,className:b},d)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/a960914c.8855b9d2.js.LICENSE.txt b/a4c8ecc0.9c2a8a54.js.LICENSE.txt similarity index 100% rename from a960914c.8855b9d2.js.LICENSE.txt rename to a4c8ecc0.9c2a8a54.js.LICENSE.txt diff --git a/a81fb19d.2e1b1819.js b/a81fb19d.370fd69c.js similarity index 97% rename from a81fb19d.2e1b1819.js rename to a81fb19d.370fd69c.js index e1993fd30f..ba9ce4577a 100644 --- a/a81fb19d.2e1b1819.js +++ b/a81fb19d.370fd69c.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[164],{316:function(a){a.exports=JSON.parse('{"type-guide":{"allTagsPath":"/guides/tags","slug":"type-guide","name":"type: guide","count":25,"permalink":"/guides/tags/type-guide"},"technology-qovery":{"allTagsPath":"/guides/tags","slug":"technology-qovery","name":"technology: qovery","count":39,"permalink":"/guides/tags/technology-qovery"},"type-tutorial":{"allTagsPath":"/guides/tags","slug":"type-tutorial","name":"type: tutorial","count":40,"permalink":"/guides/tags/type-tutorial"},"cloud-provider-aws":{"allTagsPath":"/guides/tags","slug":"cloud-provider-aws","name":"cloud_provider: aws","count":12,"permalink":"/guides/tags/cloud-provider-aws"},"language-rust":{"allTagsPath":"/guides/tags","slug":"language-rust","name":"language: rust","count":2,"permalink":"/guides/tags/language-rust"},"language-javascript":{"allTagsPath":"/guides/tags","slug":"language-javascript","name":"language: javascript","count":2,"permalink":"/guides/tags/language-javascript"},"framework-rails":{"allTagsPath":"/guides/tags","slug":"framework-rails","name":"framework: rails","count":1,"permalink":"/guides/tags/framework-rails"},"language-ruby":{"allTagsPath":"/guides/tags","slug":"language-ruby","name":"language: ruby","count":1,"permalink":"/guides/tags/language-ruby"},"database-postgresql":{"allTagsPath":"/guides/tags","slug":"database-postgresql","name":"database: postgresql","count":3,"permalink":"/guides/tags/database-postgresql"},"technology-helm":{"allTagsPath":"/guides/tags","slug":"technology-helm","name":"technology: helm","count":1,"permalink":"/guides/tags/technology-helm"},"technology-github":{"allTagsPath":"/guides/tags","slug":"technology-github","name":"technology: github","count":1,"permalink":"/guides/tags/technology-github"},"technology-docker":{"allTagsPath":"/guides/tags","slug":"technology-docker","name":"technology: docker","count":1,"permalink":"/guides/tags/technology-docker"},"provider-kubernetes":{"allTagsPath":"/guides/tags","slug":"provider-kubernetes","name":"provider: kubernetes","count":1,"permalink":"/guides/tags/provider-kubernetes"},"cloud-provider-azure":{"allTagsPath":"/guides/tags","slug":"cloud-provider-azure","name":"cloud_provider: azure","count":1,"permalink":"/guides/tags/cloud-provider-azure"},"cloud-provider-scaleway":{"allTagsPath":"/guides/tags","slug":"cloud-provider-scaleway","name":"cloud_provider: scaleway","count":1,"permalink":"/guides/tags/cloud-provider-scaleway"},"cloud-provider-gcp":{"allTagsPath":"/guides/tags","slug":"cloud-provider-gcp","name":"cloud_provider: gcp","count":1,"permalink":"/guides/tags/cloud-provider-gcp"},"technology-terraform":{"allTagsPath":"/guides/tags","slug":"technology-terraform","name":"technology: terraform","count":1,"permalink":"/guides/tags/technology-terraform"},"language-kotlin":{"allTagsPath":"/guides/tags","slug":"language-kotlin","name":"language: kotlin","count":1,"permalink":"/guides/tags/language-kotlin"}}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[167],{319:function(a){a.exports=JSON.parse('{"type-guide":{"allTagsPath":"/guides/tags","slug":"type-guide","name":"type: guide","count":25,"permalink":"/guides/tags/type-guide"},"technology-qovery":{"allTagsPath":"/guides/tags","slug":"technology-qovery","name":"technology: qovery","count":39,"permalink":"/guides/tags/technology-qovery"},"type-tutorial":{"allTagsPath":"/guides/tags","slug":"type-tutorial","name":"type: tutorial","count":40,"permalink":"/guides/tags/type-tutorial"},"cloud-provider-aws":{"allTagsPath":"/guides/tags","slug":"cloud-provider-aws","name":"cloud_provider: aws","count":12,"permalink":"/guides/tags/cloud-provider-aws"},"language-rust":{"allTagsPath":"/guides/tags","slug":"language-rust","name":"language: rust","count":2,"permalink":"/guides/tags/language-rust"},"language-javascript":{"allTagsPath":"/guides/tags","slug":"language-javascript","name":"language: javascript","count":2,"permalink":"/guides/tags/language-javascript"},"framework-rails":{"allTagsPath":"/guides/tags","slug":"framework-rails","name":"framework: rails","count":1,"permalink":"/guides/tags/framework-rails"},"language-ruby":{"allTagsPath":"/guides/tags","slug":"language-ruby","name":"language: ruby","count":1,"permalink":"/guides/tags/language-ruby"},"database-postgresql":{"allTagsPath":"/guides/tags","slug":"database-postgresql","name":"database: postgresql","count":3,"permalink":"/guides/tags/database-postgresql"},"technology-helm":{"allTagsPath":"/guides/tags","slug":"technology-helm","name":"technology: helm","count":1,"permalink":"/guides/tags/technology-helm"},"technology-github":{"allTagsPath":"/guides/tags","slug":"technology-github","name":"technology: github","count":1,"permalink":"/guides/tags/technology-github"},"technology-docker":{"allTagsPath":"/guides/tags","slug":"technology-docker","name":"technology: docker","count":1,"permalink":"/guides/tags/technology-docker"},"provider-kubernetes":{"allTagsPath":"/guides/tags","slug":"provider-kubernetes","name":"provider: kubernetes","count":1,"permalink":"/guides/tags/provider-kubernetes"},"cloud-provider-azure":{"allTagsPath":"/guides/tags","slug":"cloud-provider-azure","name":"cloud_provider: azure","count":1,"permalink":"/guides/tags/cloud-provider-azure"},"cloud-provider-scaleway":{"allTagsPath":"/guides/tags","slug":"cloud-provider-scaleway","name":"cloud_provider: scaleway","count":1,"permalink":"/guides/tags/cloud-provider-scaleway"},"cloud-provider-gcp":{"allTagsPath":"/guides/tags","slug":"cloud-provider-gcp","name":"cloud_provider: gcp","count":1,"permalink":"/guides/tags/cloud-provider-gcp"},"technology-terraform":{"allTagsPath":"/guides/tags","slug":"technology-terraform","name":"technology: terraform","count":1,"permalink":"/guides/tags/technology-terraform"},"language-kotlin":{"allTagsPath":"/guides/tags","slug":"language-kotlin","name":"language: kotlin","count":1,"permalink":"/guides/tags/language-kotlin"}}')}}]); \ No newline at end of file diff --git a/da253275.e887eb13.js b/a8a9c166.bfdff01f.js similarity index 87% rename from da253275.e887eb13.js rename to a8a9c166.bfdff01f.js index 10eae35bd1..5226709a25 100644 --- a/da253275.e887eb13.js +++ b/a8a9c166.bfdff01f.js @@ -1,2 +1,2 @@ -/*! For license information please see da253275.e887eb13.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[226],{378:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return f}));var r=n(1),o=n(9),a=(n(0),n(422)),i=(n(431),n(426),n(421)),c={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Costs Control",description:"Learn how to keep control of your costs with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Costs Control",description:"Learn how to keep control of your costs with Qovery",permalink:"/guides/advanced/costs-control",readingTime:"1 min read",source:"@site/guides/advanced/costs-control.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Costs Control",truncated:!1,prevItem:{title:"Continuous Integration",permalink:"/guides/advanced/continuous-integration"},nextItem:{title:"Create a blazingly fast REST API in Rust (Part 1/2)",permalink:"/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1"}},s=[{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function f(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},"WIP"),Object(a.b)("h2",{id:"qa"},"Q&A"),Object(a.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}f.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},f=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),f=l(n),d=r,m=f["".concat(i,".").concat(d)]||f[d]||p[d]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:o(u,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),f=l[0],p=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!f&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see a8a9c166.bfdff01f.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[168],{320:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return f}));var r=n(1),o=n(9),a=(n(0),n(425)),i=(n(434),n(429),n(424)),c={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Costs Control",description:"Learn how to keep control of your costs with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Costs Control",description:"Learn how to keep control of your costs with Qovery",permalink:"/guides/advanced/costs-control",readingTime:"1 min read",source:"@site/guides/advanced/costs-control.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Costs Control",truncated:!1,prevItem:{title:"Continuous Integration",permalink:"/guides/advanced/continuous-integration"},nextItem:{title:"Create a blazingly fast REST API in Rust (Part 1/2)",permalink:"/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1"}},s=[{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function f(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},"WIP"),Object(a.b)("h2",{id:"qa"},"Q&A"),Object(a.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}f.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},f=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),f=l(n),d=r,m=f["".concat(i,".").concat(d)]||f[d]||p[d]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:o(u,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),f=l[0],p=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!f&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/a9994e72.93876bcd.js.LICENSE.txt b/a8a9c166.bfdff01f.js.LICENSE.txt similarity index 100% rename from a9994e72.93876bcd.js.LICENSE.txt rename to a8a9c166.bfdff01f.js.LICENSE.txt diff --git a/a960914c.8855b9d2.js b/a960914c.6f472a70.js similarity index 96% rename from a960914c.8855b9d2.js rename to a960914c.6f472a70.js index d6acf24023..4b969c81b5 100644 --- a/a960914c.8855b9d2.js +++ b/a960914c.6f472a70.js @@ -1,2 +1,2 @@ -/*! For license information please see a960914c.8855b9d2.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[166],{318:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return c})),a.d(t,"rightToc",(function(){return o})),a.d(t,"default",(function(){return m}));var n=a(1),r=a(9),l=(a(0),a(422)),b=(a(429),a(421)),i=(a(426),{last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"How to deploy Helm charts",description:"Use jobs to simply deploy Helm charts with Qovery (Kubecost example)",author_github:"https://github.com/deimosfr",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to deploy Helm charts",description:"Use jobs to simply deploy Helm charts with Qovery (Kubecost example)",permalink:"/guides/tutorial/how-to-deploy-helm-charts",readingTime:"7 min read",source:"@site/guides/tutorial/how-to-deploy-helm-charts.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to deploy Helm charts",truncated:!1,prevItem:{title:"How to deploy a Rust REST API application on AWS with ease",permalink:"/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease"},nextItem:{title:"How to integrate Qovery with GitHub Actions",permalink:"/guides/tutorial/how-to-integrate-qovery-with-github-actions"}},o=[{value:"Choose a deployment method",id:"choose-a-deployment-method",children:[]},{value:"Lifecycle job parameters for Helm charts",id:"lifecycle-job-parameters-for-helm-charts",children:[]},{value:"Chart deployment",id:"chart-deployment",children:[{value:"From a 3rd party or Artifact Hub",id:"from-a-3rd-party-or-artifact-hub",children:[]},{value:"From a Helm chart from a Git repository",id:"from-a-helm-chart-from-a-git-repository",children:[]},{value:"Lifecycle Job and Timeout management",id:"lifecycle-job-and-timeout-management",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],p={rightToc:o};function m(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(l.b)("wrapper",Object(n.a)({},p,a,{components:t,mdxType:"MDXLayout"}),Object(l.b)("p",null,Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://helm.sh/docs/"}),"Helm")," is one of the most known tools to deploy on Kubernetes. It has several very useful features, Qovery uses it behind the scene to deploy some of its components. But you can also deploy Helm charts by your self if you wish."),Object(l.b)("p",null,"Installing a chart can be useful for specific use cases:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"When you want to deploy some specific objects on Kubernetes."),Object(l.b)("li",{parentName:"ul"},"When a third-party vendor requires an installation with Helm."),Object(l.b)("li",{parentName:"ul"},"When some specific configuration has to be set and does not fit into an application or container proposed by Qovery.")),Object(l.b)("h2",{id:"choose-a-deployment-method"},"Choose a deployment method"),Object(l.b)("p",null,"There are several ways to deploy a chart:"),Object(l.b)("ol",null,Object(l.b)("li",{parentName:"ol"},"You can find a lot of Helm charts on the ",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://artifacthub.io/"}),"Artifact Hub")),Object(l.b)("li",{parentName:"ol"},"You can deploy a Helm chart from a third-party provider (",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.datadoghq.com/"}),"Datadog"),", ",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.kubecost.com/"}),"Kubecost"),"...)"),Object(l.b)("li",{parentName:"ol"},"You can deploy a Helm chart from a private or public Git repository (",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/Qovery/helm-freeze"}),"Helm freeze")," is useful in this case)")),Object(l.b)("p",null,"We will make an example with all of these methods, so you can choose the one that suits you best.\nIn all the examples, we will make use of the Lifecycle jobs to manage the deployment of your helm chart (install and uninstall). The Lifecycle job configuration will be different depending on the method you have chosen."),Object(l.b)("h2",{id:"lifecycle-job-parameters-for-helm-charts"},"Lifecycle job parameters for Helm charts"),Object(l.b)(b.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,"Qovery provides a Helm container, simplifying the Helm chart deployments, but you can do it your way if you prefer. The container image is ",Object(l.b)("inlineCode",{parentName:"p"},"qoveryrd/helm"),".")),Object(l.b)("p",null,"From the Qovery Helm container, several options exist and are accessible through environment variables to help you to configure the chart deployment:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Name"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Required"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm repository name"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_URL")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm chart URL (if none is specified, Artifact Hub will be used)"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"default")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_PATH")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The local repository PATH or name from Artifact Hub"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_RELEASE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The release name of the chart deployment (should be unique in a given namespace)"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_VALUES")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm chart values file path, containing your custom settings to override from the default values"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_TIMEOUT_SEC")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm timeout in seconds, to install and uninstall chart"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"180")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_MAX_HISTORY")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The number of releases history. Useful to be able to rollback"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"50")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_DRY_RUN")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Enable or disable ",Object(l.b)("inlineCode",{parentName:"td"},"dry run")," for testing purpose"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_SHOW_DIFF")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Enable or disable ",Object(l.b)("inlineCode",{parentName:"td"},"helm diff")," between the currently deployed version and the requested one"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_ADDITIONAL_PARAMS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Additional Helm CLI parameters to add to the command line"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_KUBERNETES_NAMESPACE")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Kubernetes namespace name in which this chart will be deployed"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"$QOVERY_KUBERNETES_NAMESPACE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Kubeconfig file path location"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no*")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG_B64")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The encoded base64 Kubeconfig content. It will be decoded and used in ",Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG")," environment variable"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no*")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG_GET_EKS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Set to ",Object(l.b)("inlineCode",{parentName:"td"},"true")," to get the Kubeconfig from AWS API. It will be used as ",Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG")," environment variable"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no*")))),Object(l.b)(b.a,{type:"warning",mdxType:"Alert"},Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG"),", ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_B64")," or ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_GET_EKS")," are required to be set to access Kubernetes cluster")),Object(l.b)("h2",{id:"chart-deployment"},"Chart deployment"),Object(l.b)("p",null,"In this tutorial, ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://docs.kubecost.com/install-and-configure/install"}),"Kubecost")," will be the chart to deploy. You can deploy it in an environment where other applications are already deployed or create a dedicated one for this purpose (tooling, monitoring...)."),Object(l.b)(b.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,"You will have to configure the ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG"),", ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_B64")," or ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_GET_EKS")," environment variable to be able to deploy the chart. It is mandatory to ensure Helm will be able to connect to your Kubernetes cluster.\nYou may also have to push AWS credentials (with ",Object(l.b)("inlineCode",{parentName:"p"},"eks:DescribeCluster")," permissions) or use ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/use-aws-iam-roles-with-qovery"}),"AWS IAM roles"),".")),Object(l.b)("h3",{id:"from-a-3rd-party-or-artifact-hub"},"From a 3rd party or Artifact Hub"),Object(l.b)("p",null,"First of all, create a ",Object(l.b)("inlineCode",{parentName:"p"},"Lifecycle Job"),":"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_container.png",alt:"create lifecycle job"})),Object(l.b)("p",null,"Then select the ",Object(l.b)("inlineCode",{parentName:"p"},"Start")," event, and add ",Object(l.b)("inlineCode",{parentName:"p"},'["install"]')," in the command arguments. In the ",Object(l.b)("inlineCode",{parentName:"p"},"Delete")," event, add ",Object(l.b)("inlineCode",{parentName:"p"},'["uninstall"]'),". And configure them to run the install during the Start"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_event.png",alt:"lifecycle event"})),Object(l.b)("p",null,"Click on continue and go up to the environment variables."),Object(l.b)("p",null,"Qovery Helm image to deploy Helm charts, proposes several options to be set with the help of environment variables:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_URL")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"https://kubecost.github.io/cost-analyzer/")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_PATH")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost/cost-analyzer")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_RELEASE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_KUBERNETES_NAMESPACE")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")))),Object(l.b)("p",null,"Additionally, you can set the ",Object(l.b)("inlineCode",{parentName:"p"},"Kubecost token")," if you have a license with additional Helm args like:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_ADDITIONAL_PARAMS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},'--set kubecostToken="xxx"')),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")))),Object(l.b)("h3",{id:"from-a-helm-chart-from-a-git-repository"},"From a Helm chart from a Git repository"),Object(l.b)("p",null,"If you prefer using a ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://en.wikipedia.org/wiki/DevOps#GitOps"}),"GitOps")," approach, having all your charts, etc... in a single Git repository, it is possible to deploy your charts this way."),Object(l.b)("p",null,"From a very simple repository where we could have a helm-freeze configuration looking like this:"),Object(l.b)("pre",null,Object(l.b)("code",Object(n.a)({parentName:"pre"},{className:"language-yaml"}),"charts:\n - name: cost-analyzer\n version: 1.99.0\n repo_name: kubecost\n\nrepos:\n - name: stable\n url: https://charts.helm.sh/stable\n - name: kubecost\n url: https://kubecost.github.io/cost-analyzer/\n\ndestinations:\n - name: default\n path: ./charts\n")),Object(l.b)("p",null,"Running ",Object(l.b)("inlineCode",{parentName:"p"},"helm-freeze sync")," will download the chart ",Object(l.b)("inlineCode",{parentName:"p"},"cost-analyzer")," into the charts folder. You can then use this simple ",Object(l.b)("inlineCode",{parentName:"p"},"Dockerfile")," which will add all the content of this git repository inside a container:"),Object(l.b)("pre",null,Object(l.b)("code",Object(n.a)({parentName:"pre"},{}),'FROM qoveryrd/helm:1.0\nADD . /helm\nENTRYPOINT ["/helm/run.sh"]\n')),Object(l.b)("p",null,"Finally, add the ",Object(l.b)("inlineCode",{parentName:"p"},"run.sh")," file from the ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/helm"}),"Qovery Helm image")," inside your repository. Commit now everything. To summarize, in your Git repository you should have:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"charts"),": a folder containing all the charts (here cost-analyzer chart)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"Dockerfile"),": helping you to deploy helm chart and containing all your charts"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"helm-freeze.yaml"),": configuration file for helm-freeze"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"run.sh"),": the container start script")),Object(l.b)("p",null,"We are now ready to create a ",Object(l.b)("inlineCode",{parentName:"p"},"Lifecycle job")," and select your repository:"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_git.png",alt:"create lifecycle job"})),Object(l.b)("p",null,"Then select the ",Object(l.b)("inlineCode",{parentName:"p"},"Start")," event, and add ",Object(l.b)("inlineCode",{parentName:"p"},'["install"]')," in the command arguments. In the ",Object(l.b)("inlineCode",{parentName:"p"},"Delete")," event, add ",Object(l.b)("inlineCode",{parentName:"p"},'["uninstall"]'),". And configure them to run the install during the Start"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_event.png",alt:"lifecycle event"})),Object(l.b)("p",null,"Set the environment variables to point to the chart to deploy with the release name and other required information:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_PATH")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"/helm/charts/cost-analyzer")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_RELEASE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_KUBERNETES_NAMESPACE")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")))),Object(l.b)("p",null,"Additionally, you can set the ",Object(l.b)("inlineCode",{parentName:"p"},"Kubecost token")," if you have a license with additional Helm args like:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_ADDITIONAL_PARAMS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},'--set kubecostToken="xxx"')),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")))),Object(l.b)("h3",{id:"lifecycle-job-and-timeout-management"},"Lifecycle Job and Timeout management"),Object(l.b)(b.a,{type:"warning",mdxType:"Alert"},Object(l.b)("p",null,Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://helm.sh/docs/intro/using_helm/#helpful-options-for-installupgraderollback"}),"Helm timeout")," and Qovery Lifecycle job should be correctly set to avoid board effects!"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"Qovery Liefcycle Job timeout > ( Helm deployment timeout + Helm rollback time )"))),Object(l.b)("p",null,"The default Helm timeout set by Qovery is 3 minutes. Qovery enables Helm options:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"--wait"),": to wait for all resources to be in a ready state before marking the release as successful"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"--atomic"),": to roll back the release if the deployment fails")),Object(l.b)("p",null,"Because of the atomic check, the rollback can take more than 5 minutes. By default, Qovery set the default Lifecycle timeout to 3 minutes, to avoid falling into this issue, but there is no guarantee, it depends on what resources are deployed:"),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Qovery strongly recommends leveraging the default Qovery Lifecycle Job timeout or reducing the default Helm timeout to ensure the rollback will occur properly in case of failure.")),Object(l.b)("h2",{id:"conclusion"},"Conclusion"),Object(l.b)("p",null,"As you can see, deploying Helm charts with Qovery is straightforward. Qovery Lifecycle jobs and its Qovery Helm image should help you a lot if you familiarize yourself with it and its options."))}m.isMDXComponent=!0},420:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var o=r.a.createContext({}),p=function(e){var t=r.a.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):i({},t,{},e)),a},m=function(e){var t=p(e.components);return r.a.createElement(o.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},u=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,l=e.originalType,b=e.parentName,o=c(e,["components","mdxType","originalType","parentName"]),m=p(a),u=n,s=m["".concat(b,".").concat(u)]||m[u]||d[u]||l;return a?r.a.createElement(s,i({ref:t},o,{components:a})):r.a.createElement(s,i({ref:t},o))}));function s(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var l=a.length,b=new Array(l);b[0]=u;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i.mdxType="string"==typeof e?e:n,b[1]=i;for(var o=2;o1?arguments[1]:void 0,a),c=b>2?arguments[2]:void 0,o=void 0===c?a:r(c,a);o>i;)t[i++]=e;return t}},425:function(e,t,a){var n=a(28).f,r=Function.prototype,l=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(l)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var n=a(0),r=a.n(n),l=a(421);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(l.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},427:function(e,t,a){"use strict";var n=a(1),r=a(0),l=a.n(r),b=a(39),i=a(430),c=a(20),o=a.n(c);t.a=function(e){var t,a=e.to,c=e.href,p=a||c,m=Object(i.a)(p),d=Object(r.useRef)(!1),u=o.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!u&&m&&window.docusaurus.prefetch(p),function(){u&&t&&t.disconnect()}}),[p,u,m]),p&&m?l.a.createElement(b.b,Object(n.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(p),d.current=!0)},innerRef:function(e){var a,n;u&&e&&m&&(a=e,n=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:p})):l.a.createElement("a",Object(n.a)({},e,{href:p}))}},429:function(e,t,a){"use strict";var n=a(0),r=a.n(n),l=a(427),b=a(420),i=a.n(b);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,b=e.leftIcon,c=e.rightIcon,o=e.size,p=e.target,m=e.to,d=i()("jump-to","jump-to--"+o,a),u=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},b&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+b})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:m,target:p,className:d},u):r.a.createElement(l.a,{to:m,className:d},u)}},430:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))}}]); \ No newline at end of file +/*! For license information please see a960914c.6f472a70.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[169],{321:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return c})),a.d(t,"rightToc",(function(){return o})),a.d(t,"default",(function(){return m}));var n=a(1),r=a(9),l=(a(0),a(425)),b=(a(431),a(424)),i=(a(429),{last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"How to deploy Helm charts",description:"Use jobs to simply deploy Helm charts with Qovery (Kubecost example)",author_github:"https://github.com/deimosfr",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to deploy Helm charts",description:"Use jobs to simply deploy Helm charts with Qovery (Kubecost example)",permalink:"/guides/tutorial/how-to-deploy-helm-charts",readingTime:"7 min read",source:"@site/guides/tutorial/how-to-deploy-helm-charts.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to deploy Helm charts",truncated:!1,prevItem:{title:"How to deploy a Rust REST API application on AWS with ease",permalink:"/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease"},nextItem:{title:"How to integrate Qovery with GitHub Actions",permalink:"/guides/tutorial/how-to-integrate-qovery-with-github-actions"}},o=[{value:"Choose a deployment method",id:"choose-a-deployment-method",children:[]},{value:"Lifecycle job parameters for Helm charts",id:"lifecycle-job-parameters-for-helm-charts",children:[]},{value:"Chart deployment",id:"chart-deployment",children:[{value:"From a 3rd party or Artifact Hub",id:"from-a-3rd-party-or-artifact-hub",children:[]},{value:"From a Helm chart from a Git repository",id:"from-a-helm-chart-from-a-git-repository",children:[]},{value:"Lifecycle Job and Timeout management",id:"lifecycle-job-and-timeout-management",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],p={rightToc:o};function m(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(l.b)("wrapper",Object(n.a)({},p,a,{components:t,mdxType:"MDXLayout"}),Object(l.b)("p",null,Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://helm.sh/docs/"}),"Helm")," is one of the most known tools to deploy on Kubernetes. It has several very useful features, Qovery uses it behind the scene to deploy some of its components. But you can also deploy Helm charts by your self if you wish."),Object(l.b)("p",null,"Installing a chart can be useful for specific use cases:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"When you want to deploy some specific objects on Kubernetes."),Object(l.b)("li",{parentName:"ul"},"When a third-party vendor requires an installation with Helm."),Object(l.b)("li",{parentName:"ul"},"When some specific configuration has to be set and does not fit into an application or container proposed by Qovery.")),Object(l.b)("h2",{id:"choose-a-deployment-method"},"Choose a deployment method"),Object(l.b)("p",null,"There are several ways to deploy a chart:"),Object(l.b)("ol",null,Object(l.b)("li",{parentName:"ol"},"You can find a lot of Helm charts on the ",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://artifacthub.io/"}),"Artifact Hub")),Object(l.b)("li",{parentName:"ol"},"You can deploy a Helm chart from a third-party provider (",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.datadoghq.com/"}),"Datadog"),", ",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.kubecost.com/"}),"Kubecost"),"...)"),Object(l.b)("li",{parentName:"ol"},"You can deploy a Helm chart from a private or public Git repository (",Object(l.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/Qovery/helm-freeze"}),"Helm freeze")," is useful in this case)")),Object(l.b)("p",null,"We will make an example with all of these methods, so you can choose the one that suits you best.\nIn all the examples, we will make use of the Lifecycle jobs to manage the deployment of your helm chart (install and uninstall). The Lifecycle job configuration will be different depending on the method you have chosen."),Object(l.b)("h2",{id:"lifecycle-job-parameters-for-helm-charts"},"Lifecycle job parameters for Helm charts"),Object(l.b)(b.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,"Qovery provides a Helm container, simplifying the Helm chart deployments, but you can do it your way if you prefer. The container image is ",Object(l.b)("inlineCode",{parentName:"p"},"qoveryrd/helm"),".")),Object(l.b)("p",null,"From the Qovery Helm container, several options exist and are accessible through environment variables to help you to configure the chart deployment:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Name"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Default Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Required"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm repository name"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_URL")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm chart URL (if none is specified, Artifact Hub will be used)"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"default")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_PATH")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The local repository PATH or name from Artifact Hub"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_RELEASE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The release name of the chart deployment (should be unique in a given namespace)"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_VALUES")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm chart values file path, containing your custom settings to override from the default values"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_TIMEOUT_SEC")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Helm timeout in seconds, to install and uninstall chart"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"180")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_MAX_HISTORY")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The number of releases history. Useful to be able to rollback"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"50")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_DRY_RUN")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Enable or disable ",Object(l.b)("inlineCode",{parentName:"td"},"dry run")," for testing purpose"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_SHOW_DIFF")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Enable or disable ",Object(l.b)("inlineCode",{parentName:"td"},"helm diff")," between the currently deployed version and the requested one"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_ADDITIONAL_PARAMS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Additional Helm CLI parameters to add to the command line"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_KUBERNETES_NAMESPACE")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Kubernetes namespace name in which this chart will be deployed"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"$QOVERY_KUBERNETES_NAMESPACE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The Kubeconfig file path location"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no*")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG_B64")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"The encoded base64 Kubeconfig content. It will be decoded and used in ",Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG")," environment variable"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null})),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no*")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG_GET_EKS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Set to ",Object(l.b)("inlineCode",{parentName:"td"},"true")," to get the Kubeconfig from AWS API. It will be used as ",Object(l.b)("inlineCode",{parentName:"td"},"KUBECONFIG")," environment variable"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no*")))),Object(l.b)(b.a,{type:"warning",mdxType:"Alert"},Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG"),", ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_B64")," or ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_GET_EKS")," are required to be set to access Kubernetes cluster")),Object(l.b)("h2",{id:"chart-deployment"},"Chart deployment"),Object(l.b)("p",null,"In this tutorial, ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://docs.kubecost.com/install-and-configure/install"}),"Kubecost")," will be the chart to deploy. You can deploy it in an environment where other applications are already deployed or create a dedicated one for this purpose (tooling, monitoring...)."),Object(l.b)(b.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,"You will have to configure the ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG"),", ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_B64")," or ",Object(l.b)("inlineCode",{parentName:"p"},"KUBECONFIG_GET_EKS")," environment variable to be able to deploy the chart. It is mandatory to ensure Helm will be able to connect to your Kubernetes cluster.\nYou may also have to push AWS credentials (with ",Object(l.b)("inlineCode",{parentName:"p"},"eks:DescribeCluster")," permissions) or use ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/use-aws-iam-roles-with-qovery"}),"AWS IAM roles"),".")),Object(l.b)("h3",{id:"from-a-3rd-party-or-artifact-hub"},"From a 3rd party or Artifact Hub"),Object(l.b)("p",null,"First of all, create a ",Object(l.b)("inlineCode",{parentName:"p"},"Lifecycle Job"),":"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_container.png",alt:"create lifecycle job"})),Object(l.b)("p",null,"Then select the ",Object(l.b)("inlineCode",{parentName:"p"},"Start")," event, and add ",Object(l.b)("inlineCode",{parentName:"p"},'["install"]')," in the command arguments. In the ",Object(l.b)("inlineCode",{parentName:"p"},"Delete")," event, add ",Object(l.b)("inlineCode",{parentName:"p"},'["uninstall"]'),". And configure them to run the install during the Start"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_event.png",alt:"lifecycle event"})),Object(l.b)("p",null,"Click on continue and go up to the environment variables."),Object(l.b)("p",null,"Qovery Helm image to deploy Helm charts, proposes several options to be set with the help of environment variables:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_ADD_URL")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"https://kubecost.github.io/cost-analyzer/")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_PATH")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost/cost-analyzer")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_RELEASE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_KUBERNETES_NAMESPACE")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")))),Object(l.b)("p",null,"Additionally, you can set the ",Object(l.b)("inlineCode",{parentName:"p"},"Kubecost token")," if you have a license with additional Helm args like:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_ADDITIONAL_PARAMS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},'--set kubecostToken="xxx"')),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")))),Object(l.b)("h3",{id:"from-a-helm-chart-from-a-git-repository"},"From a Helm chart from a Git repository"),Object(l.b)("p",null,"If you prefer using a ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://en.wikipedia.org/wiki/DevOps#GitOps"}),"GitOps")," approach, having all your charts, etc... in a single Git repository, it is possible to deploy your charts this way."),Object(l.b)("p",null,"From a very simple repository where we could have a helm-freeze configuration looking like this:"),Object(l.b)("pre",null,Object(l.b)("code",Object(n.a)({parentName:"pre"},{className:"language-yaml"}),"charts:\n - name: cost-analyzer\n version: 1.99.0\n repo_name: kubecost\n\nrepos:\n - name: stable\n url: https://charts.helm.sh/stable\n - name: kubecost\n url: https://kubecost.github.io/cost-analyzer/\n\ndestinations:\n - name: default\n path: ./charts\n")),Object(l.b)("p",null,"Running ",Object(l.b)("inlineCode",{parentName:"p"},"helm-freeze sync")," will download the chart ",Object(l.b)("inlineCode",{parentName:"p"},"cost-analyzer")," into the charts folder. You can then use this simple ",Object(l.b)("inlineCode",{parentName:"p"},"Dockerfile")," which will add all the content of this git repository inside a container:"),Object(l.b)("pre",null,Object(l.b)("code",Object(n.a)({parentName:"pre"},{}),'FROM qoveryrd/helm:1.0\nADD . /helm\nENTRYPOINT ["/helm/run.sh"]\n')),Object(l.b)("p",null,"Finally, add the ",Object(l.b)("inlineCode",{parentName:"p"},"run.sh")," file from the ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/helm"}),"Qovery Helm image")," inside your repository. Commit now everything. To summarize, in your Git repository you should have:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"charts"),": a folder containing all the charts (here cost-analyzer chart)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"Dockerfile"),": helping you to deploy helm chart and containing all your charts"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"helm-freeze.yaml"),": configuration file for helm-freeze"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"run.sh"),": the container start script")),Object(l.b)("p",null,"We are now ready to create a ",Object(l.b)("inlineCode",{parentName:"p"},"Lifecycle job")," and select your repository:"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_git.png",alt:"create lifecycle job"})),Object(l.b)("p",null,"Then select the ",Object(l.b)("inlineCode",{parentName:"p"},"Start")," event, and add ",Object(l.b)("inlineCode",{parentName:"p"},'["install"]')," in the command arguments. In the ",Object(l.b)("inlineCode",{parentName:"p"},"Delete")," event, add ",Object(l.b)("inlineCode",{parentName:"p"},'["uninstall"]'),". And configure them to run the install during the Start"),Object(l.b)("p",{Valign:"center"},Object(l.b)("img",{src:"/img/helm/helm_event.png",alt:"lifecycle event"})),Object(l.b)("p",null,"Set the environment variables to point to the chart to deploy with the release name and other required information:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_REPO_PATH")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"/helm/charts/cost-analyzer")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_RELEASE_NAME")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_KUBERNETES_NAMESPACE")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"kubecost")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")))),Object(l.b)("p",null,"Additionally, you can set the ",Object(l.b)("inlineCode",{parentName:"p"},"Kubecost token")," if you have a license with additional Helm args like:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Variable"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Value"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Secret"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},"HELM_ADDITIONAL_PARAMS")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("inlineCode",{parentName:"td"},'--set kubecostToken="xxx"')),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"yes")))),Object(l.b)("h3",{id:"lifecycle-job-and-timeout-management"},"Lifecycle Job and Timeout management"),Object(l.b)(b.a,{type:"warning",mdxType:"Alert"},Object(l.b)("p",null,Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://helm.sh/docs/intro/using_helm/#helpful-options-for-installupgraderollback"}),"Helm timeout")," and Qovery Lifecycle job should be correctly set to avoid board effects!"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"Qovery Liefcycle Job timeout > ( Helm deployment timeout + Helm rollback time )"))),Object(l.b)("p",null,"The default Helm timeout set by Qovery is 3 minutes. Qovery enables Helm options:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"--wait"),": to wait for all resources to be in a ready state before marking the release as successful"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"--atomic"),": to roll back the release if the deployment fails")),Object(l.b)("p",null,"Because of the atomic check, the rollback can take more than 5 minutes. By default, Qovery set the default Lifecycle timeout to 3 minutes, to avoid falling into this issue, but there is no guarantee, it depends on what resources are deployed:"),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Qovery strongly recommends leveraging the default Qovery Lifecycle Job timeout or reducing the default Helm timeout to ensure the rollback will occur properly in case of failure.")),Object(l.b)("h2",{id:"conclusion"},"Conclusion"),Object(l.b)("p",null,"As you can see, deploying Helm charts with Qovery is straightforward. Qovery Lifecycle jobs and its Qovery Helm image should help you a lot if you familiarize yourself with it and its options."))}m.isMDXComponent=!0},423:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var o=r.a.createContext({}),p=function(e){var t=r.a.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):i({},t,{},e)),a},m=function(e){var t=p(e.components);return r.a.createElement(o.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},u=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,l=e.originalType,b=e.parentName,o=c(e,["components","mdxType","originalType","parentName"]),m=p(a),u=n,s=m["".concat(b,".").concat(u)]||m[u]||d[u]||l;return a?r.a.createElement(s,i({ref:t},o,{components:a})):r.a.createElement(s,i({ref:t},o))}));function s(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var l=a.length,b=new Array(l);b[0]=u;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i.mdxType="string"==typeof e?e:n,b[1]=i;for(var o=2;o1?arguments[1]:void 0,a),c=b>2?arguments[2]:void 0,o=void 0===c?a:r(c,a);o>i;)t[i++]=e;return t}},428:function(e,t,a){var n=a(28).f,r=Function.prototype,l=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(l)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var n=a(0),r=a.n(n),l=a(424);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(l.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},430:function(e,t,a){"use strict";var n=a(1),r=a(0),l=a.n(r),b=a(39),i=a(432),c=a(20),o=a.n(c);t.a=function(e){var t,a=e.to,c=e.href,p=a||c,m=Object(i.a)(p),d=Object(r.useRef)(!1),u=o.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!u&&m&&window.docusaurus.prefetch(p),function(){u&&t&&t.disconnect()}}),[p,u,m]),p&&m?l.a.createElement(b.b,Object(n.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(p),d.current=!0)},innerRef:function(e){var a,n;u&&e&&m&&(a=e,n=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:p})):l.a.createElement("a",Object(n.a)({},e,{href:p}))}},431:function(e,t,a){"use strict";var n=a(0),r=a.n(n),l=a(430),b=a(423),i=a.n(b);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,b=e.leftIcon,c=e.rightIcon,o=e.size,p=e.target,m=e.to,d=i()("jump-to","jump-to--"+o,a),u=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},b&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+b})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:m,target:p,className:d},u):r.a.createElement(l.a,{to:m,className:d},u)}},432:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))}}]); \ No newline at end of file diff --git a/ac2c90fd.02f5bb51.js.LICENSE.txt b/a960914c.6f472a70.js.LICENSE.txt similarity index 100% rename from ac2c90fd.02f5bb51.js.LICENSE.txt rename to a960914c.6f472a70.js.LICENSE.txt diff --git a/a9994e72.93876bcd.js b/a9994e72.b72e40bc.js similarity index 93% rename from a9994e72.93876bcd.js rename to a9994e72.b72e40bc.js index 6c87ad913b..0b689c4114 100644 --- a/a9994e72.93876bcd.js +++ b/a9994e72.b72e40bc.js @@ -1,2 +1,2 @@ -/*! For license information please see a9994e72.93876bcd.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[167],{319:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return d}));var r=n(1),o=n(9),a=(n(0),n(422)),i=n(421),c=n(429),l=n(426),u={last_modified_on:"2022-05-04",$schema:"/.meta/.schemas/guides.json",title:"How to write a Dockerfile",description:"How to write your first Dockerfile in order to deploy your application with Qovery",author_github:"https://github.com/MacLikorne",tags:["type: tutorial","technology: docker"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to write a Dockerfile",description:"How to write your first Dockerfile in order to deploy your application with Qovery",permalink:"/guides/tutorial/how-to-write-a-dockerfile",readingTime:"5 min read",source:"@site/guides/tutorial/how-to-write-a-dockerfile.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: docker",permalink:"/guides/tags/technology-docker"}],title:"How to write a Dockerfile",truncated:!1,prevItem:{title:"How To Use Lifecycle Job To Deploy Any Kind Of Resources",permalink:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources"},nextItem:{title:"Import your environment variables with the Qovery CLI",permalink:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli"}},p=[{value:"My Sweet Dockerfile",id:"my-sweet-dockerfile",children:[{value:"FROM",id:"from",children:[]},{value:"WORKDIR",id:"workdir",children:[]},{value:"COPY",id:"copy",children:[]},{value:"RUN",id:"run",children:[]},{value:"EXPOSE",id:"expose",children:[]},{value:"CMD",id:"cmd",children:[]},{value:"Build your image",id:"build-your-image",children:[]},{value:"Test your image",id:"test-your-image",children:[]}]},{value:"What's next?",id:"whats-next",children:[]}],b={rightToc:p};function d(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"With Qovery, there are two ways to build and deploy your application:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Without a Dockerfile in your repository: your application is built with ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://docs.qovery.com/docs/using-qovery/configuration/application/#option-1-buildpacks"}),"Buildpacks")),Object(a.b)("li",{parentName:"ol"},"With a Dockerfile: sometimes Buildpacks won't fit your specific setup, and you'll have to write your Dockerfile.")),Object(a.b)("p",null,"In this article, we'll see, step by step, how to quickly write a proper Dockerfile for any application you would like to deploy."),Object(a.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have installed the ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://docs.qovery.com/docs/using-qovery/interface/cli/"}),"Qovery CLI")),Object(a.b)("li",{parentName:"ul"},"You host your code on Github"))),Object(a.b)("hr",null),Object(a.b)("h2",{id:"my-sweet-dockerfile"},"My Sweet Dockerfile"),Object(a.b)("p",null,"If you read this, you probably don't know why Docker is used and what is the purpose of a Dockerfile."),Object(a.b)("p",null,"Docker is a container engine, building and using images to deploy applications in containers. It looks like virtualization, and each container could be compared to a virtual machine with the minimal setup to run an application."),Object(a.b)("p",null,"The Dockerfile is your image builder recipe. When Docker uses it, it will follow all instructions to ",Object(a.b)("strong",{parentName:"p"},"build your application and run it"),"."),Object(a.b)("p",null,"The first step is to create a file named ",Object(a.b)("strong",{parentName:"p"},"Dockerfile")," at your project root level so Qovery would be able to find and use it."),Object(a.b)("p",null,"Also, to avoid unwanted files from your repository (images, .idea, DS_Store etc.), you need to add a ",Object(a.b)("strong",{parentName:"p"},".dockerignore"),". It will prevent heavy copy tasks of useless files, mostly your project dependencies and libraries you'll get back to with your package manager."),Object(a.b)("p",null,"The ",Object(a.b)("strong",{parentName:"p"},".dockerignore")," file works like the ",Object(a.b)("strong",{parentName:"p"},".gitignore"),", so add all the path of the useless files and folders in it."),Object(a.b)("h3",{id:"from"},"FROM"),Object(a.b)("p",null,"The first line you'll add in your Dockerfile is ",Object(a.b)("strong",{parentName:"p"},"FROM"),"."),Object(a.b)("p",null,"It will pull an already existing image from ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.docker.com/"}),"Docker Hub"),". You should most of the time use an image that fits your application language (Node, Python, Java, etc.), but you can go a step backward and begin with a simple Linux image."),Object(a.b)("p",null,"Your Dockerfile's first line should look like this:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM :\n")),Object(a.b)("p",null,"For example, with ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.docker.com/_/python"}),"python"),":"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM python:3\n")),Object(a.b)("h3",{id:"workdir"},"WORKDIR"),Object(a.b)("p",null,"Since most of the images are Linux-based, a good practice is to set up a directory you'll work in. That's the purpose of the ",Object(a.b)("strong",{parentName:"p"},"WORKDIR")," line. It defines a directory and moves you in:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM :\nWORKDIR /app\n")),Object(a.b)("p",null,"If you now work with a relative path (./), it will be in the ",Object(a.b)("em",{parentName:"p"},"app")," directory."),Object(a.b)("h3",{id:"copy"},"COPY"),Object(a.b)("p",null,"Now you have defined your base image and your working directory, it's time to add your code in. ",Object(a.b)("strong",{parentName:"p"},"COPY")," works like ",Object(a.b)("strong",{parentName:"p"},"cp")," linux command. First argument is the source and second one is the destination."),Object(a.b)("p",null,"It's time to copy your source code in the image."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM :\nWORKDIR /app\nCOPY . .\n")),Object(a.b)("p",null,"Here, the elements of your ",Object(a.b)("strong",{parentName:"p"},"root")," folder from your current directory will be added inside the ",Object(a.b)("strong",{parentName:"p"},"/app")," folder."),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"You can use your current repository relative path (",Object(a.b)("strong",{parentName:"p"},".")," can be replaced by ",Object(a.b)("strong",{parentName:"p"},"./"),") if you want to add specific element (except the content of ",Object(a.b)("strong",{parentName:"p"},".dockerignore"),") to your image relative path (as we are already in the ",Object(a.b)("strong",{parentName:"p"},"/app")," folder, we can use ",Object(a.b)("strong",{parentName:"p"},"./"),").")),Object(a.b)("h3",{id:"run"},"RUN"),Object(a.b)("p",null,"One does not simply get source code to run an application."),Object(a.b)("p",null,"Most of the time, you have some stuff to do before an application execution like downloading/installing peer dependencies and build your application."),Object(a.b)("p",null,"That's the purpose of ",Object(a.b)("strong",{parentName:"p"},"RUN")," lines; it will execute a command and wait to finish the task to go forward."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),'FROM :\nWORKDIR /app\nCOPY . .\nRUN echo "Installing or doing stuff."\nRUN \n')),Object(a.b)("p",null,"You can set as many ",Object(a.b)("strong",{parentName:"p"},"RUN")," lines as you need."),Object(a.b)("h3",{id:"expose"},"EXPOSE"),Object(a.b)("p",null,"If your app needs to be reached from outside the container, you have to open its listening port. ",Object(a.b)("strong",{parentName:"p"},"EXPOSE")," is made for this."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),'FROM :\nWORKDIR /app\nCOPY . .\nRUN echo "Installing or doing stuff"\nRUN \nEXPOSE \n')),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Typical mistakes are made application configuration side. Ensure your application will listen on all interfaces ",Object(a.b)("strong",{parentName:"p"},"0.0.0.0")," and not only localhost ",Object(a.b)("strong",{parentName:"p"},"127.0.0.1"),".")),Object(a.b)("h3",{id:"cmd"},"CMD"),Object(a.b)("p",null,"Your application is now ready to run."),Object(a.b)("p",null,"The last thing to do is to specify how to execute it. Add the ",Object(a.b)("strong",{parentName:"p"},"CMD")," line with the same command with all the arguments you use locally to launch your application."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),'FROM :\nWORKDIR /app\nCOPY . .\nRUN echo "Installing or doing stuff"\nRUN \nEXPOSE \nCMD [ "", "", "" ]\n')),Object(a.b)("p",null,"Like a local usage, you can set as many arguments as needed."),Object(a.b)("h3",{id:"build-your-image"},"Build your image"),Object(a.b)("p",null,"When Qovery uses your Dockerfile, it first builds it before running it."),Object(a.b)("p",null,"If the build fails, Qovery won't be able to launch our application. To simplify debugging, you can build your image locally if you have Docker installed on your computer."),Object(a.b)("p",null,"Open a terminal and set the path at the Dockerfile location, and use the command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"cd ~/my/folder/where/my/code/is\ndocker build .\n")),Object(a.b)("p",null,"It will build your image based on your Dockerfile. You'll see all the logs related to all lines you've added in the Dockerfile."),Object(a.b)("p",null,"If something goes wrong, it will be printed onto the terminal, and you'll be able to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://stackoverflow.com/"}),"debug it"),"."),Object(a.b)("h3",{id:"test-your-image"},"Test your image"),Object(a.b)("p",null,"If your image builds properly, you can now check how it will be handle by Qovery with the command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"qovery run\n")),Object(a.b)("h2",{id:"whats-next"},"What's next?"),Object(a.b)("p",null,"If you follow this tutorial and everything works perfectly, it's time to deploy your app on Qovery. You will find all the things you need to know ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.qovery.com/docs/using-qovery/configuration/"}),"here"),"."),Object(a.b)(c.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}d.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return n?o.a.createElement(m,c({ref:t},u,{components:n})):o.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,u=void 0===l?n:o(l,n);u>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(430),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,p=Object(c.a)(s),b=Object(o.useRef)(!1),d=u.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(s),function(){d&&t&&t.disconnect()}}),[s,d,p]),s&&p?a.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(s),b.current=!0)},innerRef:function(e){var n,r;d&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:s})):a.a.createElement("a",Object(r.a)({},e,{href:s}))}},429:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,p=e.to,b=c()("jump-to","jump-to--"+u,n),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?o.a.createElement("a",{href:p,target:s,className:b},d):o.a.createElement(a.a,{to:p,className:b},d)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file +/*! For license information please see a9994e72.b72e40bc.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[170],{322:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return d}));var r=n(1),o=n(9),a=(n(0),n(425)),i=n(424),c=n(431),l=n(429),u={last_modified_on:"2022-05-04",$schema:"/.meta/.schemas/guides.json",title:"How to write a Dockerfile",description:"How to write your first Dockerfile in order to deploy your application with Qovery",author_github:"https://github.com/MacLikorne",tags:["type: tutorial","technology: docker"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to write a Dockerfile",description:"How to write your first Dockerfile in order to deploy your application with Qovery",permalink:"/guides/tutorial/how-to-write-a-dockerfile",readingTime:"5 min read",source:"@site/guides/tutorial/how-to-write-a-dockerfile.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: docker",permalink:"/guides/tags/technology-docker"}],title:"How to write a Dockerfile",truncated:!1,prevItem:{title:"How To Use Lifecycle Job To Deploy Any Kind Of Resources",permalink:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources"},nextItem:{title:"Import your environment variables with the Qovery CLI",permalink:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli"}},p=[{value:"My Sweet Dockerfile",id:"my-sweet-dockerfile",children:[{value:"FROM",id:"from",children:[]},{value:"WORKDIR",id:"workdir",children:[]},{value:"COPY",id:"copy",children:[]},{value:"RUN",id:"run",children:[]},{value:"EXPOSE",id:"expose",children:[]},{value:"CMD",id:"cmd",children:[]},{value:"Build your image",id:"build-your-image",children:[]},{value:"Test your image",id:"test-your-image",children:[]}]},{value:"What's next?",id:"whats-next",children:[]}],b={rightToc:p};function d(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"With Qovery, there are two ways to build and deploy your application:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Without a Dockerfile in your repository: your application is built with ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://docs.qovery.com/docs/using-qovery/configuration/application/#option-1-buildpacks"}),"Buildpacks")),Object(a.b)("li",{parentName:"ol"},"With a Dockerfile: sometimes Buildpacks won't fit your specific setup, and you'll have to write your Dockerfile.")),Object(a.b)("p",null,"In this article, we'll see, step by step, how to quickly write a proper Dockerfile for any application you would like to deploy."),Object(a.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have installed the ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://docs.qovery.com/docs/using-qovery/interface/cli/"}),"Qovery CLI")),Object(a.b)("li",{parentName:"ul"},"You host your code on Github"))),Object(a.b)("hr",null),Object(a.b)("h2",{id:"my-sweet-dockerfile"},"My Sweet Dockerfile"),Object(a.b)("p",null,"If you read this, you probably don't know why Docker is used and what is the purpose of a Dockerfile."),Object(a.b)("p",null,"Docker is a container engine, building and using images to deploy applications in containers. It looks like virtualization, and each container could be compared to a virtual machine with the minimal setup to run an application."),Object(a.b)("p",null,"The Dockerfile is your image builder recipe. When Docker uses it, it will follow all instructions to ",Object(a.b)("strong",{parentName:"p"},"build your application and run it"),"."),Object(a.b)("p",null,"The first step is to create a file named ",Object(a.b)("strong",{parentName:"p"},"Dockerfile")," at your project root level so Qovery would be able to find and use it."),Object(a.b)("p",null,"Also, to avoid unwanted files from your repository (images, .idea, DS_Store etc.), you need to add a ",Object(a.b)("strong",{parentName:"p"},".dockerignore"),". It will prevent heavy copy tasks of useless files, mostly your project dependencies and libraries you'll get back to with your package manager."),Object(a.b)("p",null,"The ",Object(a.b)("strong",{parentName:"p"},".dockerignore")," file works like the ",Object(a.b)("strong",{parentName:"p"},".gitignore"),", so add all the path of the useless files and folders in it."),Object(a.b)("h3",{id:"from"},"FROM"),Object(a.b)("p",null,"The first line you'll add in your Dockerfile is ",Object(a.b)("strong",{parentName:"p"},"FROM"),"."),Object(a.b)("p",null,"It will pull an already existing image from ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.docker.com/"}),"Docker Hub"),". You should most of the time use an image that fits your application language (Node, Python, Java, etc.), but you can go a step backward and begin with a simple Linux image."),Object(a.b)("p",null,"Your Dockerfile's first line should look like this:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM :\n")),Object(a.b)("p",null,"For example, with ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.docker.com/_/python"}),"python"),":"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM python:3\n")),Object(a.b)("h3",{id:"workdir"},"WORKDIR"),Object(a.b)("p",null,"Since most of the images are Linux-based, a good practice is to set up a directory you'll work in. That's the purpose of the ",Object(a.b)("strong",{parentName:"p"},"WORKDIR")," line. It defines a directory and moves you in:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM :\nWORKDIR /app\n")),Object(a.b)("p",null,"If you now work with a relative path (./), it will be in the ",Object(a.b)("em",{parentName:"p"},"app")," directory."),Object(a.b)("h3",{id:"copy"},"COPY"),Object(a.b)("p",null,"Now you have defined your base image and your working directory, it's time to add your code in. ",Object(a.b)("strong",{parentName:"p"},"COPY")," works like ",Object(a.b)("strong",{parentName:"p"},"cp")," linux command. First argument is the source and second one is the destination."),Object(a.b)("p",null,"It's time to copy your source code in the image."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM :\nWORKDIR /app\nCOPY . .\n")),Object(a.b)("p",null,"Here, the elements of your ",Object(a.b)("strong",{parentName:"p"},"root")," folder from your current directory will be added inside the ",Object(a.b)("strong",{parentName:"p"},"/app")," folder."),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"You can use your current repository relative path (",Object(a.b)("strong",{parentName:"p"},".")," can be replaced by ",Object(a.b)("strong",{parentName:"p"},"./"),") if you want to add specific element (except the content of ",Object(a.b)("strong",{parentName:"p"},".dockerignore"),") to your image relative path (as we are already in the ",Object(a.b)("strong",{parentName:"p"},"/app")," folder, we can use ",Object(a.b)("strong",{parentName:"p"},"./"),").")),Object(a.b)("h3",{id:"run"},"RUN"),Object(a.b)("p",null,"One does not simply get source code to run an application."),Object(a.b)("p",null,"Most of the time, you have some stuff to do before an application execution like downloading/installing peer dependencies and build your application."),Object(a.b)("p",null,"That's the purpose of ",Object(a.b)("strong",{parentName:"p"},"RUN")," lines; it will execute a command and wait to finish the task to go forward."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),'FROM :\nWORKDIR /app\nCOPY . .\nRUN echo "Installing or doing stuff."\nRUN \n')),Object(a.b)("p",null,"You can set as many ",Object(a.b)("strong",{parentName:"p"},"RUN")," lines as you need."),Object(a.b)("h3",{id:"expose"},"EXPOSE"),Object(a.b)("p",null,"If your app needs to be reached from outside the container, you have to open its listening port. ",Object(a.b)("strong",{parentName:"p"},"EXPOSE")," is made for this."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),'FROM :\nWORKDIR /app\nCOPY . .\nRUN echo "Installing or doing stuff"\nRUN \nEXPOSE \n')),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Typical mistakes are made application configuration side. Ensure your application will listen on all interfaces ",Object(a.b)("strong",{parentName:"p"},"0.0.0.0")," and not only localhost ",Object(a.b)("strong",{parentName:"p"},"127.0.0.1"),".")),Object(a.b)("h3",{id:"cmd"},"CMD"),Object(a.b)("p",null,"Your application is now ready to run."),Object(a.b)("p",null,"The last thing to do is to specify how to execute it. Add the ",Object(a.b)("strong",{parentName:"p"},"CMD")," line with the same command with all the arguments you use locally to launch your application."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),'FROM :\nWORKDIR /app\nCOPY . .\nRUN echo "Installing or doing stuff"\nRUN \nEXPOSE \nCMD [ "", "", "" ]\n')),Object(a.b)("p",null,"Like a local usage, you can set as many arguments as needed."),Object(a.b)("h3",{id:"build-your-image"},"Build your image"),Object(a.b)("p",null,"When Qovery uses your Dockerfile, it first builds it before running it."),Object(a.b)("p",null,"If the build fails, Qovery won't be able to launch our application. To simplify debugging, you can build your image locally if you have Docker installed on your computer."),Object(a.b)("p",null,"Open a terminal and set the path at the Dockerfile location, and use the command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"cd ~/my/folder/where/my/code/is\ndocker build .\n")),Object(a.b)("p",null,"It will build your image based on your Dockerfile. You'll see all the logs related to all lines you've added in the Dockerfile."),Object(a.b)("p",null,"If something goes wrong, it will be printed onto the terminal, and you'll be able to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://stackoverflow.com/"}),"debug it"),"."),Object(a.b)("h3",{id:"test-your-image"},"Test your image"),Object(a.b)("p",null,"If your image builds properly, you can now check how it will be handle by Qovery with the command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"qovery run\n")),Object(a.b)("h2",{id:"whats-next"},"What's next?"),Object(a.b)("p",null,"If you follow this tutorial and everything works perfectly, it's time to deploy your app on Qovery. You will find all the things you need to know ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.qovery.com/docs/using-qovery/configuration/"}),"here"),"."),Object(a.b)(c.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}d.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return n?o.a.createElement(m,c({ref:t},u,{components:n})):o.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,u=void 0===l?n:o(l,n);u>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(432),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,p=Object(c.a)(s),b=Object(o.useRef)(!1),d=u.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(s),function(){d&&t&&t.disconnect()}}),[s,d,p]),s&&p?a.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(s),b.current=!0)},innerRef:function(e){var n,r;d&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:s})):a.a.createElement("a",Object(r.a)({},e,{href:s}))}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,p=e.to,b=c()("jump-to","jump-to--"+u,n),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?o.a.createElement("a",{href:p,target:s,className:b},d):o.a.createElement(a.a,{to:p,className:b},d)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/acaf40e9.7fe44568.js.LICENSE.txt b/a9994e72.b72e40bc.js.LICENSE.txt similarity index 100% rename from acaf40e9.7fe44568.js.LICENSE.txt rename to a9994e72.b72e40bc.js.LICENSE.txt diff --git a/f7098925.fa52698d.js b/ab8f5b83.46371bbd.js similarity index 96% rename from f7098925.fa52698d.js rename to ab8f5b83.46371bbd.js index 2a56e44095..d07dc7f7d9 100644 --- a/f7098925.fa52698d.js +++ b/ab8f5b83.46371bbd.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[253],{405:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return p})),n.d(t,"metadata",(function(){return d})),n.d(t,"rightToc",(function(){return h})),n.d(t,"default",(function(){return g}));var a=n(1),r=n(9),o=(n(0),n(422)),i=n(421),l=n(429),s=n(431),c=n(434),b=n(441),u=n(426),p={last_modified_on:"2023-04-23",$schema:"/.meta/.schemas/guides.json",title:"URL Shortener API with Kotlin (Part 1/2)",description:"Create a URL shortener API with Kotlin, the micro-framework Ktor and PostgreSQL",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","language: kotlin","database: postgresql"],hide_pagination:!0},d={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"URL Shortener API with Kotlin (Part 1/2)",description:"Create a URL shortener API with Kotlin, the micro-framework Ktor and PostgreSQL",permalink:"/guides/tutorial/url-shortener-api-with-kotlin",readingTime:"14 min read",source:"@site/guides/tutorial/url-shortener-api-with-kotlin.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"language: kotlin",permalink:"/guides/tags/language-kotlin"},{label:"database: postgresql",permalink:"/guides/tags/database-postgresql"}],title:"URL Shortener API with Kotlin (Part 1/2)",truncated:!1,prevItem:{title:"Terraform",permalink:"/guides/advanced/terraform"},nextItem:{title:"Use an API gateway in front of multiple services",permalink:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services"}},h=[{value:"Introduction",id:"introduction",children:[]},{value:"What is a URL shortener?",id:"what-is-a-url-shortener",children:[]},{value:"Ktor principles",id:"ktor-principles",children:[{value:"Kotlin",id:"kotlin",children:[]},{value:"Functional programming",id:"functional-programming",children:[]},{value:"Asynchronous",id:"asynchronous",children:[]}]},{value:"HTTP Server",id:"http-server",children:[]},{value:"URL Encoder",id:"url-encoder",children:[{value:"Handle identifier collision",id:"handle-identifier-collision",children:[]}]},{value:"URL Decoder",id:"url-decoder",children:[]},{value:"Redirect",id:"redirect",children:[]},{value:"Stats: clicks over time",id:"stats-clicks-over-time",children:[]},{value:"Try the API",id:"try-the-api",children:[]},{value:"Connect to a PostgreSQL database with Exposed",id:"connect-to-a-postgresql-database-with-exposed",children:[]},{value:"Deploy in the Cloud with Qovery",id:"deploy-in-the-cloud-with-qovery",children:[{value:"Install Qovery CLI",id:"install-qovery-cli",children:[]},{value:"Sign up",id:"sign-up",children:[]},{value:"Create an application",id:"create-an-application",children:[]},{value:"Create a new project",id:"create-a-new-project",children:[]},{value:"Create a new environment",id:"create-a-new-environment",children:[]},{value:"Create a new application",id:"create-a-new-application",children:[]},{value:"Deploy a database",id:"deploy-a-database",children:[]},{value:"Connect to PostgreSQL",id:"connect-to-postgresql",children:[]},{value:"Deploy",id:"deploy",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],m={rightToc:h};function g(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},m,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"The source code for this post can be found on this ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/ktor-url-shortener"}),"github repo")),Object(o.b)("h2",{id:"introduction"},"Introduction"),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://ktor.io/"}),"Ktor")," is a brand new micro-framework created by the Jetbrains team, and running over the JVM. Jetbrains are the authors of ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://kotlinlang.org/"}),"Kotlin")," - which is now the official programming language for Android, and one of the most popular programming language on the JVM. Kotlin is gaining popularity on server-side and multi-platform application development."),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"Ktor is a framework for building asynchronous servers and clients in connected systems using the powerful Kotlin programming language.")),Object(o.b)("p",null,"In this article, you will learn:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"How to design a simple URL shortener."),Object(o.b)("li",{parentName:"ul"},"How to use the Ktor micro-framework with Kotlin"),Object(o.b)("li",{parentName:"ul"},"How to deploy a Ktor application")),Object(o.b)("p",null,"I have +4 years of experience using Spring, and I wanted to give a try to Ktor, which seems promising. Creating a URL shortener is an excellent way to start."),Object(o.b)("h2",{id:"what-is-a-url-shortener"},"What is a URL shortener?"),Object(o.b)("p",null,"A URL shortener is a simple tool that takes a long URL and turns it into a very short one"),Object(o.b)("p",null,Object(o.b)("img",Object(a.a)({parentName:"p"},{src:"https://uploads-ssl.webflow.com/5de176c0d41c9b4a1dbbb0aa/5e655859bc2ae5c7371efa36_urlshortener%20image.png",alt:"Flow of URL shortening - from original URL to short URL"}))),Object(o.b)("p",null,"It is commonly used for 3 reasons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Tracking clicks"),Object(o.b)("li",{parentName:"ul"},"Make URL much more concise."),Object(o.b)("li",{parentName:"ul"},"Hide original URL")),Object(o.b)("p",null,"One famous freemium provider is bit.ly (see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://uploads-ssl.webflow.com/5de176c0d41c9b4a1dbbb0aa/5e655a34bc2ae5452b1f124b_bitly.gif"}),"here"),")"),Object(o.b)("p",null,"In this article we will make a basic bit.ly like URL shortener. Let\u2019s go"),Object(o.b)("h2",{id:"ktor-principles"},"Ktor principles"),Object(o.b)("p",null,"Before starting I want to introduce the 3 main principles of Ktor."),Object(o.b)("h3",{id:"kotlin"},"Kotlin"),Object(o.b)("p",null,"Kotlin is the language used to develop on Ktor. It is an object-oriented and functional language. It is very stable and runs on the JVM. Kotlin is 100% interoperable with Java and allows you to benefit from its ecosystem (libraries, build system, etc.)."),Object(o.b)("h3",{id:"functional-programming"},"Functional programming"),Object(o.b)("p",null,"Ktor leverages the power of Kotlin and has a very functional approach. When writing code, everything seems obvious. It's very similar to what you can see on NodeJS. For me, coming from the Spring world, I find it very efficient to read and use."),Object(o.b)("h3",{id:"asynchronous"},"Asynchronous"),Object(o.b)("p",null,"Kotlin provides asynchronous code execution, thanks to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://kotlinlang.org/docs/reference/coroutines-overview.html"}),"coroutines"),". Ktor exploits this feature to its full potential, and even if you have the impression that you are writing code in a blocking manner, this is not the case. Ktor makes your life easier."),Object(o.b)("h2",{id:"http-server"},"HTTP Server"),Object(o.b)("p",null,"Here is a complete and simple example of how to expose an HTTP server (",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"http://localhost:8080"}),"http://localhost:8080"),") with Ktor."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'fun main(args: Array): Unit = io.ktor.server.netty.EngineMain.main(args)\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n routing {\n get("/") {\n call.respondText("Hello World", contentType = ContentType.Text.Plain)\n }\n }\n}\n')),Object(o.b)("h2",{id:"url-encoder"},"URL Encoder"),Object(o.b)("p",null,"The URL encoder will translate an incoming address into a smaller URL. The idea is to provide an ID that will identify the final URL. Using a hash function is perfect for this operation. However, the operation is non-reversible, meaning you can\u2019t retrieve the final URL by the generated identifier."),Object(o.b)("p",null,"Function to transform a long URL into a shorter URL"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// String extension\nfun String.encodeToID(): String {\n // hash String with MD5\n val hashBytes = MessageDigest.getInstance("MD5").digest(this.toByteArray(Charsets.UTF_8))\n // transform to human readable MD5 String\n val hashString = String.format("%032x", BigInteger(1, hashBytes))\n // truncate MD5 String\n val truncatedHashString = hashString.take(6)\n // return id\n return truncatedHashString\n}\n')),Object(o.b)("p",null,"We expose the function through the REST API"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// Request object\ndata class Request(val url: String) {\n fun toResponse(): Response = Response(url, url.encodeToID())\n}\n\n// Response object\ndata class Response(val originalURL: String, private val id: String) {\n val shortURL: String = "http://localhost:8080/$id"\n}\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n install(ContentNegotiation) {\n jackson {\n enable(SerializationFeature.INDENT_OUTPUT)\n propertyNamingStrategy = PropertyNamingStrategy.SNAKE_CASE\n }\n }\n\n // Hash Table Response object by ID\n val responseByID = mutableMapOf()\n\n routing {\n post("/api/v1/encode") {\n // Deserialize JSON body to Request object\n val request = call.receive()\n\n // find the Response object if it already exists\n val retrievedResponse = responseByID[request.url.encodeToID()]\n if (retrievedResponse != null) {\n // cache hit\n log.debug("cache hit $retrievedResponse")\n return@post call.respond(retrievedResponse)\n }\n\n // cache miss\n val response = request.toResponse()\n responseByID[request.url.encodeToID()] = response\n log.debug("cache miss $response")\n\n // Serialize Response object to JSON body\n call.respond(response)\n }\n }\n}\n')),Object(o.b)("h3",{id:"handle-identifier-collision"},"Handle identifier collision"),Object(o.b)("p",null,"Using a hash function makes no guarantee that it is not already being used. If it is in use, then you need to change it to another one. Note: even if the probability to have a collision is very low, you should handle this case."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// String extension (function signature has changed)\nfun String.encodeToID(truncateLength: Int = 6): String {\n // hash String with MD5\n val hashBytes = MessageDigest.getInstance("MD5").digest(this.toByteArray(Charsets.UTF_8))\n // transform to human readable MD5 String\n val hashString = String.format("%032x", BigInteger(1, hashBytes))\n // truncate MD5 String\n val truncatedHashString = hashString.take(truncateLength)\n // return id\n return truncatedHashString\n}\n\n//...\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n // ...\n // Hash Table Response object by id\n val responseByID = mutableMapOf()\n\n fun getIdentifier(url: String, truncateLength: Int = 6): String {\n val id = url.encodeToID()\n\n val retrievedResponse = responseByID[id]\n if (retrievedResponse?.originalURL != url) {\n // collision spotted !\n return getIdentifier(url, truncateLength + 1)\n }\n\n return id\n }\n\n routing {\n post("/api/v1/encode") {\n // Deserialize JSON body to Request object\n val request = call.receive()\n\n // find the Response object if it already exists\n val id = getID(request.url)\n val retrievedResponse = responseByID[id]\n if (retrievedResponse != null) {\n // cache hit\n log.debug("cache hit $retrievedResponse")\n return@post call.respond(retrievedResponse)\n }\n\n // cache miss\n val response = request.toResponse()\n responseByID[id] = response\n log.debug("cache miss $response")\n\n // Serialize Response object to JSON body\n call.respond(response)\n }\n }\n}\n')),Object(o.b)("h2",{id:"url-decoder"},"URL Decoder"),Object(o.b)("p",null,"Decoding the URL is the process of returning the original URL from the short URL. This is the reverse operation made by the URL Encoder"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),"val shortURL = getShortURL(request.url)\nval retrievedResponse = responseByID[shortURL]\nretrievedResponse?.originalURL // return original URL or null\n")),Object(o.b)("h2",{id:"redirect"},"Redirect"),Object(o.b)("p",null,"When a user clicks on a short URL, the user is redirected to the final URL. HTTP protocol allows to do this naturally by returning a 302 status code and a redirection URL."),Object(o.b)("p",null,"With Ktor the redirection is as simple as calling a method with the final URL as a parameter."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'call.respondRedirect("https://www.qovery.com")\n')),Object(o.b)("p",null,"What we expect is that when the user visits ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"http://localhost:8080/fbc951"}),"http://localhost:8080/fbc951")," he is redirected to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com"}),"https://www.qovery.com"),". If the URL is incorrect then redirect to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.google.com"}),"https://www.google.com")),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n // ...\n routing {\n get("/{id}") {\n val id = call.parameters["id"]\n val retrievedResponse = id?.let { responseByID[it] }\n\n if (id.isNullOrBlank() || retrievedResponse == null) {\n return@get call.respondRedirect("https://www.google.com")\n }\n\n log.debug("redirect to: $retrievedResponse")\n call.respondRedirect(retrievedResponse.originalURL)\n }\n // ...\n }\n}\n')),Object(o.b)("h2",{id:"stats-clicks-over-time"},"Stats: clicks over time"),Object(o.b)("p",null,"Something that is really useful on products like bit.ly is the stats provided (click over time, referrers, country of visitors). Here is how to store click over time and make them available through the API"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// added\ndata class Stat(val clicksOverTime: MutableList = mutableListOf())\n\n// Response object (modified with Stat)\ndata class Response(val originalURL: String, private val id: String, val stat: Stat = Stat()) {\n val shortURL: String = "http://localhost:8080/$id"\n}\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n install(ContentNegotiation) {\n jackson {\n // ...\n // add this line to return Date object as ISO8601 format\n disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)\n }\n }\n // ...\n routing {\n // ...\n get("/api/v1/url/{id}/stat") {\n val id = call.parameters["id"]\n val retrievedResponse = id?.let { responseByID[it] }\n\n if (id.isNullOrBlank() || retrievedResponse == null) {\n return@get call.respond(HttpStatusCode.NoContent)\n }\n\n call.respond(retrievedResponse.stat)\n }\n // ...\n }\n}\n')),Object(o.b)("h2",{id:"try-the-api"},"Try the API"),Object(o.b)("p",null,"Run the application"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ ./gradlew run\n//...\n2020-03-12 09:28:08.150 [main] INFO Application - No ktor.deployment.watch patterns specified, automatic reload is not active\n2020-03-12 09:28:08.606 [main] INFO Application - Responding at http://0.0.0.0:8080\n")),Object(o.b)("p",null,"Then execute the commands"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'# generate a short URL\n$ curl -X POST -d \'{"url": "https://www.qovery.com"}\' -H "Content-type: application/json" "http://localhost:8080/api/v1/encode"\n{\n "original_url": "https://www.qovery.com",\n "stat": {\n "clicks_over_time": []\n },\n "short_url": "http://localhost:8080/fbc951"\n}\n\n# generate 4 fake clicks\n$ curl -X GET \'http://localhost:8080/fbc951\'\n$ curl -X GET \'http://localhost:8080/fbc951\'\n$ curl -X GET \'http://localhost:8080/fbc951\'\n$ curl -X GET \'http://localhost:8080/fbc951\'\n\n# show stat\n$ curl -X GET \'http://localhost:8080/api/v1/url/fbc951/stat\'\n{\n "clicks_over_time": [\n "2020-03-11T21:10:52.354+0000",\n "2020-03-11T21:10:54.093+0000",\n "2020-03-11T21:12:34.987+0000",\n "2020-03-11T21:12:37.223+0000"\n ]\n}\n')),Object(o.b)("h2",{id:"connect-to-a-postgresql-database-with-exposed"},"Connect to a PostgreSQL database with Exposed"),Object(o.b)("p",null,"By storing the data in memory, we lose all the data every time the application restart. Which is problematic for running in production. To make the data persistent we will store it in a PostgreSQL database. We will have to add 1 new dependency - ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/JetBrains/Exposed"}),"Exposed"),". Exposed (with ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/brettwooldridge/HikariCP"}),"Hikari Connection Pool"),") is a lightweight SQL library on top of JDBC driver for Kotlin. With exposed it is possible to access databases in two flavours: typesafe SQL wrapping DSL and lightweight Data Access Objects (DAO)."),Object(o.b)("p",null,"Add the dependencies to your build.gradle (or POM.xml)"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'repositories {\n jcenter()\n}\n\ndependencies {\n // Connection Pool and PostgreSQL driver\n implementation("com.zaxxer:HikariCP:3.4.2")\n implementation("org.postgresql:postgresql:42.2.11")\n\n // Exposed\n implementation("org.jetbrains.exposed:exposed-core:0.22.1")\n implementation("org.jetbrains.exposed:exposed-dao:0.22.1")\n implementation("org.jetbrains.exposed:exposed-jdbc:0.22.1")\n implementation("org.jetbrains.exposed:exposed-java-time:0.22.1")\n}\n')),Object(o.b)("p",null,"We need to have 2 distincts tables, one containing all the final URLs with their correspond identifier"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'object ResponseTable : Table("response") {\n val id = varchar("id", 32)\n val originalURL = varchar("original_url", 2048)\n override val primaryKey: PrimaryKey = PrimaryKey(id)\n}\n')),Object(o.b)("p",null,"And a second one with all the clicking points"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'object ClickOverTimeTable : Table("click_over_time") {\n val id = integer("id").autoIncrement()\n val clickDate = datetime("click_date")\n val response = reference("response_id", onDelete = ReferenceOption.CASCADE, refColumn = ResponseTable.id)\n override val primaryKey: PrimaryKey = PrimaryKey(id)\n}\n')),Object(o.b)("p",null,"We need to create the tables as defined above programmatically"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'fun initDatabase() {\n val config = HikariConfig().apply {\n jdbcUrl = "jdbc:postgresql://127.0.0.1:5432/exposed"\n username = "exposed"\n password = "exposed"\n driverClassName = "org.postgresql.Driver"\n }\n\n Database.connect(HikariDataSource(config))\n\n transaction {\n // create tables if they do not exist\n SchemaUtils.createMissingTablesAndColumns(RequestTable, ClickOverTimeTable)\n }\n}\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n initDatabase()\n // ...\n}\n')),Object(o.b)("p",null,"We have to replace the Hash Table used to store the data by the PostgreSQL database (see the final code ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/ktor-url-shortener/blob/with_postgresql/src/Application.kt"}),"here"),")"),Object(o.b)("h2",{id:"deploy-in-the-cloud-with-qovery"},"Deploy in the Cloud with Qovery"),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com"}),"Qovery")," is going to help us to deploy the final application in the Cloud without the need to configure the CI/CD, network, security, load balancing, database and all the DevOps tasks"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"Qovery is a deployment platform that helps all developers to deploy their applications in the Cloud in just a few seconds")),Object(o.b)(u.a,{name:"tutorial",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Your code need to be hosted on Github/Gitlab/Bitbucket"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://ktor.io/quickstart/quickstart/docker.html"}),"Package your Ktor application to build and run it on Docker")))),Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"web",placeholder:"Select your interface",select:!1,size:null,values:[{group:"Interfaces",label:"Web",value:"web"},{group:"Interfaces",label:"CLI",value:"cli"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"web",mdxType:"TabItem"},Object(o.b)("li",null,Object(o.b)("p",null,"Sign in to the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web interface"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("a",{href:"https://onboarding.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.jpg",alt:"Qovery Sign-up page"}))))),Object(o.b)(b.a,{value:"cli",mdxType:"TabItem"},Object(o.b)("li",null,Object(o.b)("h3",{id:"install-qovery-cli"},"Install Qovery CLI"),Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"linux",placeholder:"Select your OS",select:!1,size:null,values:[{group:"Platforms",label:"Linux",value:"linux"},{group:"Platforms",label:"MacOS",value:"macos"},{group:"Platforms",label:"Windows",value:"windows"},{group:"Platforms",label:"Docker",value:"docker"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"universal",values:[{label:"*nix",value:"universal"},{label:"Arch Linux",value:"arch"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"universal",mdxType:"TabItem"},Object(o.b)("p",null,"To download and install Qovery CLI on any Linux distribution:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(b.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(b.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Linux manually by downloading the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(o.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(o.b)(b.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"homebrew",values:[{label:"Homebrew",value:"homebrew"},{label:"Script",value:"script"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"homebrew",mdxType:"TabItem"},Object(o.b)("p",null,"The common solution to install a command line binary on the MacOS is to use ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery brew repository\n$ brew tap Qovery/qovery-cli\n\n# Install the CLI\n$ brew install qovery-cli\n"))),Object(o.b)(b.a,{value:"script",mdxType:"TabItem"},Object(o.b)("p",null,"To download and install Qovery CLI from the command line:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(b.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Mac OS manually by downloading the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(o.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(o.b)(b.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"scoop",mdxType:"TabItem"},Object(o.b)("p",null,"The classic way to install binaries on Windows is to use ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery bucket\n$ scoop bucket add qovery https://github.com/Qovery/scoop-qovery-cli\n\n# Install the CLI\n$ scoop install qovery-cli\n"))),Object(o.b)(b.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Windows manually by downloading the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to\n",Object(o.b)("inlineCode",{parentName:"p"},"C:\\Windows"),".")))),Object(o.b)(b.a,{value:"docker",mdxType:"TabItem"},Object(o.b)("p",null,"Install Docker on your local machine and run the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Pull and Run the latest Qovery CLI\n$ docker run ghcr.io/qovery/qovery-cli:latest help\n")),Object(o.b)("p",null,"Change ",Object(o.b)("inlineCode",{parentName:"p"},"latest")," by the version you want to use. For example, to use the version 0.58.4, run:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ docker run ghcr.io/qovery/qovery-cli:0.58.4 help\n")),Object(o.b)("p",null,"Note: ",Object(o.b)("inlineCode",{parentName:"p"},"ghcr.io")," is the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/pkgs/container/qovery-cli"}),"GitHub Container Registry"),".")))),Object(o.b)("li",null,Object(o.b)("h3",{id:"sign-up"},"Sign up"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using an environment without access to GUI or a browser, you can use headless authentication instead:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth --headless\n"))),Object(o.b)("p",null,"Your browser window with sign-in options will open."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/qovery_signup.svg",alt:"Qovery Sign-up page"})),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/apps/qovery/installations/new"}),"Click here")," to authorize Qovery to clone and build your applications."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/github_signup.svg",alt:"Connect Github"})),Object(o.b)("p",null,"Congratulations, you are logged-in.")))),Object(o.b)("h3",{id:"create-an-application"},"Create an application"),Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h3",{id:"create-a-new-project"},"Create a new project"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/heroku/heroku-2.png",alt:"Migrate from Heroku"}))),Object(o.b)("li",null,Object(o.b)("h3",{id:"create-a-new-environment"},"Create a new environment"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/heroku/heroku-3.png",alt:"Migrate from Heroku"}))),Object(o.b)("li",null,Object(o.b)("h3",{id:"create-a-new-application"},"Create a new application"),Object(o.b)("p",null,"To follow the guide, ",Object(o.b)("a",{href:"https://github.com/evoxmusic/ktor-url-shortener.git"},"you can fork and use our repository")),Object(o.b)("p",null,"Use the forked repository (and branch ",Object(o.b)("strong",{parentName:"p"},"master"),") while creating the application in the repository field:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/rust/rust.png",alt:"Migrate from Heroku"}))),Object(o.b)("li",null,Object(o.b)("p",null,"After the application is created: "),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate application settings"),Object(o.b)("li",{parentName:"ul"},"Select ",Object(o.b)("strong",{parentName:"li"},"Port")),Object(o.b)("li",{parentName:"ul"},"Add port 8080")),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros-1.png",alt:"Microservices"})),Object(o.b)("p",null,"This will expose your application and make accessible in the public internet.")))),Object(o.b)("h3",{id:"deploy-a-database"},"Deploy a database"),Object(o.b)("p",null,"Create and deploy a new database."),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},"Name the new database **my-pql-db** to follow the guide flawlessly"),Object(o.b)("p",null,"To learn how to do it, you can ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"follow this guide"),"."),Object(o.b)("h3",{id:"connect-to-postgresql"},"Connect to PostgreSQL"),Object(o.b)("p",null,"Qovery add dynamically all required environment variables to connect to the database at the runtime of the container."),Object(o.b)("p",null,"You can list them all in ",Object(o.b)("strong",{parentName:"p"},"Environment Variables")," ",Object(o.b)("strong",{parentName:"p"},"Secrets")," section in your application overview, as described in ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/managing-environment-variables/"}),"envs guide"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/db-envs.png",alt:"DB Secrets"})),Object(o.b)("p",null,"To use them:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'fun initDatabase() {\n val config = HikariConfig().apply {\n jdbcUrl = "jdbc:${System.getenv("QOVERY_DATABASE_MY_PQL_DB_CONNECTION_URI_WITHOUT_CREDENTIALS")}"\n username = System.getenv("QOVERY_DATABASE_MY_PQL_DB_USERNAME")\n password = System.getenv("QOVERY_DATABASE_MY_PQL_DB_PASSWORD")\n driverClassName = "org.postgresql.Driver"\n }\n\n Database.connect(HikariDataSource(config))\n\n transaction {\n // create tables if they do not exist\n SchemaUtils.createMissingTablesAndColumns(RequestTable, ClickOverTimeTable)\n }\n}\n')),Object(o.b)("h3",{id:"deploy"},"Deploy"),Object(o.b)("p",null,"To deploy your application and database, click ",Object(o.b)("strong",{parentName:"p"},"Action")," and ",Object(o.b)("strong",{parentName:"p"},"Deploy")," button in your environments list view:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deploy-env.png",alt:"Kotlin URL Shortener"})),Object(o.b)("p",null,"To get public URL to the application, open application details and click on ",Object(o.b)("strong",{parentName:"p"},"Action")," ",Object(o.b)("strong",{parentName:"p"},"Open"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deploy-env-1.png",alt:"Kotlin URL Shortener"})),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/open-app.png",alt:"Kotlin URL Shortener"})),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"We have seen that creating an URL shortener API with Ktor and Kotlin is extremely simple. Connecting the application to PostgreSQL is very easy with the Exposed library. In just a few lines of code, the service is fully functional and can be deployed in production very quickly with the help of Qovery. In the next part, we will see how to create a web interface connecting to this API to convert our URLs without using the curl command."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Part 2"),": bind a web interface to the API - ","[link coming soon]"),Object(o.b)(l.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}g.isMDXComponent=!0},421:function(e,t,n){"use strict";n(423);var a=n(0),r=n.n(a),o=n(420),i=n.n(o);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,o=e.icon,l=e.type,s=null;switch(l){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return r.a.createElement("div",{className:i()(n,"alert","alert--"+l,{"alert--fill":a,"alert--icon":!1!==o}),role:"alert"},!1!==o&&r.a.createElement("i",{className:i()("feather","icon-"+(o||s))}),t)}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(430),s=n(20),c=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,b=n||s,u=Object(l.a)(b),p=Object(r.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var n,a;d&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:b})):o.a.createElement("a",Object(a.a)({},e,{href:b}))}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),i=n(420),l=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,s=e.rightIcon,c=e.size,b=e.target,u=e.to,p=l()("jump-to","jump-to--"+c,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return b?r.a.createElement("a",{href:u,target:b,className:p},d):r.a.createElement(o.a,{to:u,className:p},d)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},c="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),b=Object(a.useState)(null),u=b[0],p=b[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:c,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},434:function(e,t,n){"use strict";var a=n(1),r=(n(439),n(436),n(52),n(29),n(22),n(21),n(0)),o=n.n(r),i=n(446),l=n(420),s=n.n(l),c=n(428),b=n.n(c),u=n(445),p=37,d=39;function h(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,r=e.className,i=e.handleKeydown,l=e.style,c=e.values,b=e.selectedValue,u=e.tabRefs;return o.a.createElement("div",{className:n?"tabs--centered":null},o.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:s()("tabs",r,{"tabs--block":t}),style:l},c.map((function(e){var t=e.value,n=e.label;return o.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:s()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return i(u,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function m(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,r=e.size,l=e.values,s=l;if(s[0].group){var c=_.groupBy(s,"group");s=Object.keys(c).map((function(e){return{label:e,options:c[e]}}))}return o.a.createElement(i.a,{className:"react-select-container react-select--"+r,classNamePrefix:"react-select",options:s,isClearable:n,placeholder:t,value:l.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,i=e.groupId,l=e.label,s=e.placeholder,c=e.select,g=e.size,v=(e.style,e.values),j=e.urlKey,O=Object(u.a)(),f=O.tabGroupChoices,y=O.setTabGroupChoices,w=Object(r.useState)(n),N=w[0],k=w[1];if(null!=i){var T=f[i];null!=T&&T!==N&&k(T)}var R=function(e){k(e),null!=i&&y(i,e)},S=[],I=function(e,t,n){switch(n.keyCode){case d:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(r.useEffect)((function(){if("undefined"!=typeof window&&window.location&&j){var e=b.a.parse(window.location.search);e[j]&&k(e[j])}}),[]),o.a.createElement(o.a.Fragment,null,o.a.createElement("div",{className:"margin-bottom--"+(g||"md")},l&&o.a.createElement("div",{className:"margin-vert--sm"},l),v.length>1&&(c?o.a.createElement(m,Object(a.a)({changeSelectedValue:R,handleKeydown:I,placeholder:s,selectedValue:N,size:g,tabRefs:S},e)):o.a.createElement(h,Object(a.a)({changeSelectedValue:R,handleKeydown:I,selectedValue:N,tabRefs:S},e)))),r.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},441:function(e,t,n){"use strict";var a=n(0),r=n.n(a);t.a=function(e){return r.a.createElement(r.a.Fragment,null,e.children)}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[171],{323:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return p})),n.d(t,"metadata",(function(){return d})),n.d(t,"rightToc",(function(){return h})),n.d(t,"default",(function(){return g}));var a=n(1),r=n(9),o=(n(0),n(425)),i=n(424),l=n(431),s=n(434),c=n(437),b=n(444),u=n(429),p={last_modified_on:"2023-04-23",$schema:"/.meta/.schemas/guides.json",title:"URL Shortener API with Kotlin (Part 1/2)",description:"Create a URL shortener API with Kotlin, the micro-framework Ktor and PostgreSQL",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","language: kotlin","database: postgresql"],hide_pagination:!0},d={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"URL Shortener API with Kotlin (Part 1/2)",description:"Create a URL shortener API with Kotlin, the micro-framework Ktor and PostgreSQL",permalink:"/guides/tutorial/url-shortener-api-with-kotlin",readingTime:"14 min read",source:"@site/guides/tutorial/url-shortener-api-with-kotlin.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"language: kotlin",permalink:"/guides/tags/language-kotlin"},{label:"database: postgresql",permalink:"/guides/tags/database-postgresql"}],title:"URL Shortener API with Kotlin (Part 1/2)",truncated:!1,prevItem:{title:"Terraform",permalink:"/guides/advanced/terraform"},nextItem:{title:"Use an API gateway in front of multiple services",permalink:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services"}},h=[{value:"Introduction",id:"introduction",children:[]},{value:"What is a URL shortener?",id:"what-is-a-url-shortener",children:[]},{value:"Ktor principles",id:"ktor-principles",children:[{value:"Kotlin",id:"kotlin",children:[]},{value:"Functional programming",id:"functional-programming",children:[]},{value:"Asynchronous",id:"asynchronous",children:[]}]},{value:"HTTP Server",id:"http-server",children:[]},{value:"URL Encoder",id:"url-encoder",children:[{value:"Handle identifier collision",id:"handle-identifier-collision",children:[]}]},{value:"URL Decoder",id:"url-decoder",children:[]},{value:"Redirect",id:"redirect",children:[]},{value:"Stats: clicks over time",id:"stats-clicks-over-time",children:[]},{value:"Try the API",id:"try-the-api",children:[]},{value:"Connect to a PostgreSQL database with Exposed",id:"connect-to-a-postgresql-database-with-exposed",children:[]},{value:"Deploy in the Cloud with Qovery",id:"deploy-in-the-cloud-with-qovery",children:[{value:"Install Qovery CLI",id:"install-qovery-cli",children:[]},{value:"Sign up",id:"sign-up",children:[]},{value:"Create an application",id:"create-an-application",children:[]},{value:"Create a new project",id:"create-a-new-project",children:[]},{value:"Create a new environment",id:"create-a-new-environment",children:[]},{value:"Create a new application",id:"create-a-new-application",children:[]},{value:"Deploy a database",id:"deploy-a-database",children:[]},{value:"Connect to PostgreSQL",id:"connect-to-postgresql",children:[]},{value:"Deploy",id:"deploy",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],m={rightToc:h};function g(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},m,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"The source code for this post can be found on this ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/ktor-url-shortener"}),"github repo")),Object(o.b)("h2",{id:"introduction"},"Introduction"),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://ktor.io/"}),"Ktor")," is a brand new micro-framework created by the Jetbrains team, and running over the JVM. Jetbrains are the authors of ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://kotlinlang.org/"}),"Kotlin")," - which is now the official programming language for Android, and one of the most popular programming language on the JVM. Kotlin is gaining popularity on server-side and multi-platform application development."),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"Ktor is a framework for building asynchronous servers and clients in connected systems using the powerful Kotlin programming language.")),Object(o.b)("p",null,"In this article, you will learn:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"How to design a simple URL shortener."),Object(o.b)("li",{parentName:"ul"},"How to use the Ktor micro-framework with Kotlin"),Object(o.b)("li",{parentName:"ul"},"How to deploy a Ktor application")),Object(o.b)("p",null,"I have +4 years of experience using Spring, and I wanted to give a try to Ktor, which seems promising. Creating a URL shortener is an excellent way to start."),Object(o.b)("h2",{id:"what-is-a-url-shortener"},"What is a URL shortener?"),Object(o.b)("p",null,"A URL shortener is a simple tool that takes a long URL and turns it into a very short one"),Object(o.b)("p",null,Object(o.b)("img",Object(a.a)({parentName:"p"},{src:"https://uploads-ssl.webflow.com/5de176c0d41c9b4a1dbbb0aa/5e655859bc2ae5c7371efa36_urlshortener%20image.png",alt:"Flow of URL shortening - from original URL to short URL"}))),Object(o.b)("p",null,"It is commonly used for 3 reasons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Tracking clicks"),Object(o.b)("li",{parentName:"ul"},"Make URL much more concise."),Object(o.b)("li",{parentName:"ul"},"Hide original URL")),Object(o.b)("p",null,"One famous freemium provider is bit.ly (see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://uploads-ssl.webflow.com/5de176c0d41c9b4a1dbbb0aa/5e655a34bc2ae5452b1f124b_bitly.gif"}),"here"),")"),Object(o.b)("p",null,"In this article we will make a basic bit.ly like URL shortener. Let\u2019s go"),Object(o.b)("h2",{id:"ktor-principles"},"Ktor principles"),Object(o.b)("p",null,"Before starting I want to introduce the 3 main principles of Ktor."),Object(o.b)("h3",{id:"kotlin"},"Kotlin"),Object(o.b)("p",null,"Kotlin is the language used to develop on Ktor. It is an object-oriented and functional language. It is very stable and runs on the JVM. Kotlin is 100% interoperable with Java and allows you to benefit from its ecosystem (libraries, build system, etc.)."),Object(o.b)("h3",{id:"functional-programming"},"Functional programming"),Object(o.b)("p",null,"Ktor leverages the power of Kotlin and has a very functional approach. When writing code, everything seems obvious. It's very similar to what you can see on NodeJS. For me, coming from the Spring world, I find it very efficient to read and use."),Object(o.b)("h3",{id:"asynchronous"},"Asynchronous"),Object(o.b)("p",null,"Kotlin provides asynchronous code execution, thanks to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://kotlinlang.org/docs/reference/coroutines-overview.html"}),"coroutines"),". Ktor exploits this feature to its full potential, and even if you have the impression that you are writing code in a blocking manner, this is not the case. Ktor makes your life easier."),Object(o.b)("h2",{id:"http-server"},"HTTP Server"),Object(o.b)("p",null,"Here is a complete and simple example of how to expose an HTTP server (",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"http://localhost:8080"}),"http://localhost:8080"),") with Ktor."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'fun main(args: Array): Unit = io.ktor.server.netty.EngineMain.main(args)\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n routing {\n get("/") {\n call.respondText("Hello World", contentType = ContentType.Text.Plain)\n }\n }\n}\n')),Object(o.b)("h2",{id:"url-encoder"},"URL Encoder"),Object(o.b)("p",null,"The URL encoder will translate an incoming address into a smaller URL. The idea is to provide an ID that will identify the final URL. Using a hash function is perfect for this operation. However, the operation is non-reversible, meaning you can\u2019t retrieve the final URL by the generated identifier."),Object(o.b)("p",null,"Function to transform a long URL into a shorter URL"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// String extension\nfun String.encodeToID(): String {\n // hash String with MD5\n val hashBytes = MessageDigest.getInstance("MD5").digest(this.toByteArray(Charsets.UTF_8))\n // transform to human readable MD5 String\n val hashString = String.format("%032x", BigInteger(1, hashBytes))\n // truncate MD5 String\n val truncatedHashString = hashString.take(6)\n // return id\n return truncatedHashString\n}\n')),Object(o.b)("p",null,"We expose the function through the REST API"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// Request object\ndata class Request(val url: String) {\n fun toResponse(): Response = Response(url, url.encodeToID())\n}\n\n// Response object\ndata class Response(val originalURL: String, private val id: String) {\n val shortURL: String = "http://localhost:8080/$id"\n}\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n install(ContentNegotiation) {\n jackson {\n enable(SerializationFeature.INDENT_OUTPUT)\n propertyNamingStrategy = PropertyNamingStrategy.SNAKE_CASE\n }\n }\n\n // Hash Table Response object by ID\n val responseByID = mutableMapOf()\n\n routing {\n post("/api/v1/encode") {\n // Deserialize JSON body to Request object\n val request = call.receive()\n\n // find the Response object if it already exists\n val retrievedResponse = responseByID[request.url.encodeToID()]\n if (retrievedResponse != null) {\n // cache hit\n log.debug("cache hit $retrievedResponse")\n return@post call.respond(retrievedResponse)\n }\n\n // cache miss\n val response = request.toResponse()\n responseByID[request.url.encodeToID()] = response\n log.debug("cache miss $response")\n\n // Serialize Response object to JSON body\n call.respond(response)\n }\n }\n}\n')),Object(o.b)("h3",{id:"handle-identifier-collision"},"Handle identifier collision"),Object(o.b)("p",null,"Using a hash function makes no guarantee that it is not already being used. If it is in use, then you need to change it to another one. Note: even if the probability to have a collision is very low, you should handle this case."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// String extension (function signature has changed)\nfun String.encodeToID(truncateLength: Int = 6): String {\n // hash String with MD5\n val hashBytes = MessageDigest.getInstance("MD5").digest(this.toByteArray(Charsets.UTF_8))\n // transform to human readable MD5 String\n val hashString = String.format("%032x", BigInteger(1, hashBytes))\n // truncate MD5 String\n val truncatedHashString = hashString.take(truncateLength)\n // return id\n return truncatedHashString\n}\n\n//...\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n // ...\n // Hash Table Response object by id\n val responseByID = mutableMapOf()\n\n fun getIdentifier(url: String, truncateLength: Int = 6): String {\n val id = url.encodeToID()\n\n val retrievedResponse = responseByID[id]\n if (retrievedResponse?.originalURL != url) {\n // collision spotted !\n return getIdentifier(url, truncateLength + 1)\n }\n\n return id\n }\n\n routing {\n post("/api/v1/encode") {\n // Deserialize JSON body to Request object\n val request = call.receive()\n\n // find the Response object if it already exists\n val id = getID(request.url)\n val retrievedResponse = responseByID[id]\n if (retrievedResponse != null) {\n // cache hit\n log.debug("cache hit $retrievedResponse")\n return@post call.respond(retrievedResponse)\n }\n\n // cache miss\n val response = request.toResponse()\n responseByID[id] = response\n log.debug("cache miss $response")\n\n // Serialize Response object to JSON body\n call.respond(response)\n }\n }\n}\n')),Object(o.b)("h2",{id:"url-decoder"},"URL Decoder"),Object(o.b)("p",null,"Decoding the URL is the process of returning the original URL from the short URL. This is the reverse operation made by the URL Encoder"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),"val shortURL = getShortURL(request.url)\nval retrievedResponse = responseByID[shortURL]\nretrievedResponse?.originalURL // return original URL or null\n")),Object(o.b)("h2",{id:"redirect"},"Redirect"),Object(o.b)("p",null,"When a user clicks on a short URL, the user is redirected to the final URL. HTTP protocol allows to do this naturally by returning a 302 status code and a redirection URL."),Object(o.b)("p",null,"With Ktor the redirection is as simple as calling a method with the final URL as a parameter."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'call.respondRedirect("https://www.qovery.com")\n')),Object(o.b)("p",null,"What we expect is that when the user visits ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"http://localhost:8080/fbc951"}),"http://localhost:8080/fbc951")," he is redirected to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com"}),"https://www.qovery.com"),". If the URL is incorrect then redirect to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.google.com"}),"https://www.google.com")),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n // ...\n routing {\n get("/{id}") {\n val id = call.parameters["id"]\n val retrievedResponse = id?.let { responseByID[it] }\n\n if (id.isNullOrBlank() || retrievedResponse == null) {\n return@get call.respondRedirect("https://www.google.com")\n }\n\n log.debug("redirect to: $retrievedResponse")\n call.respondRedirect(retrievedResponse.originalURL)\n }\n // ...\n }\n}\n')),Object(o.b)("h2",{id:"stats-clicks-over-time"},"Stats: clicks over time"),Object(o.b)("p",null,"Something that is really useful on products like bit.ly is the stats provided (click over time, referrers, country of visitors). Here is how to store click over time and make them available through the API"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// added\ndata class Stat(val clicksOverTime: MutableList = mutableListOf())\n\n// Response object (modified with Stat)\ndata class Response(val originalURL: String, private val id: String, val stat: Stat = Stat()) {\n val shortURL: String = "http://localhost:8080/$id"\n}\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n install(ContentNegotiation) {\n jackson {\n // ...\n // add this line to return Date object as ISO8601 format\n disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)\n }\n }\n // ...\n routing {\n // ...\n get("/api/v1/url/{id}/stat") {\n val id = call.parameters["id"]\n val retrievedResponse = id?.let { responseByID[it] }\n\n if (id.isNullOrBlank() || retrievedResponse == null) {\n return@get call.respond(HttpStatusCode.NoContent)\n }\n\n call.respond(retrievedResponse.stat)\n }\n // ...\n }\n}\n')),Object(o.b)("h2",{id:"try-the-api"},"Try the API"),Object(o.b)("p",null,"Run the application"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ ./gradlew run\n//...\n2020-03-12 09:28:08.150 [main] INFO Application - No ktor.deployment.watch patterns specified, automatic reload is not active\n2020-03-12 09:28:08.606 [main] INFO Application - Responding at http://0.0.0.0:8080\n")),Object(o.b)("p",null,"Then execute the commands"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'# generate a short URL\n$ curl -X POST -d \'{"url": "https://www.qovery.com"}\' -H "Content-type: application/json" "http://localhost:8080/api/v1/encode"\n{\n "original_url": "https://www.qovery.com",\n "stat": {\n "clicks_over_time": []\n },\n "short_url": "http://localhost:8080/fbc951"\n}\n\n# generate 4 fake clicks\n$ curl -X GET \'http://localhost:8080/fbc951\'\n$ curl -X GET \'http://localhost:8080/fbc951\'\n$ curl -X GET \'http://localhost:8080/fbc951\'\n$ curl -X GET \'http://localhost:8080/fbc951\'\n\n# show stat\n$ curl -X GET \'http://localhost:8080/api/v1/url/fbc951/stat\'\n{\n "clicks_over_time": [\n "2020-03-11T21:10:52.354+0000",\n "2020-03-11T21:10:54.093+0000",\n "2020-03-11T21:12:34.987+0000",\n "2020-03-11T21:12:37.223+0000"\n ]\n}\n')),Object(o.b)("h2",{id:"connect-to-a-postgresql-database-with-exposed"},"Connect to a PostgreSQL database with Exposed"),Object(o.b)("p",null,"By storing the data in memory, we lose all the data every time the application restart. Which is problematic for running in production. To make the data persistent we will store it in a PostgreSQL database. We will have to add 1 new dependency - ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/JetBrains/Exposed"}),"Exposed"),". Exposed (with ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/brettwooldridge/HikariCP"}),"Hikari Connection Pool"),") is a lightweight SQL library on top of JDBC driver for Kotlin. With exposed it is possible to access databases in two flavours: typesafe SQL wrapping DSL and lightweight Data Access Objects (DAO)."),Object(o.b)("p",null,"Add the dependencies to your build.gradle (or POM.xml)"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'repositories {\n jcenter()\n}\n\ndependencies {\n // Connection Pool and PostgreSQL driver\n implementation("com.zaxxer:HikariCP:3.4.2")\n implementation("org.postgresql:postgresql:42.2.11")\n\n // Exposed\n implementation("org.jetbrains.exposed:exposed-core:0.22.1")\n implementation("org.jetbrains.exposed:exposed-dao:0.22.1")\n implementation("org.jetbrains.exposed:exposed-jdbc:0.22.1")\n implementation("org.jetbrains.exposed:exposed-java-time:0.22.1")\n}\n')),Object(o.b)("p",null,"We need to have 2 distincts tables, one containing all the final URLs with their correspond identifier"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'object ResponseTable : Table("response") {\n val id = varchar("id", 32)\n val originalURL = varchar("original_url", 2048)\n override val primaryKey: PrimaryKey = PrimaryKey(id)\n}\n')),Object(o.b)("p",null,"And a second one with all the clicking points"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'object ClickOverTimeTable : Table("click_over_time") {\n val id = integer("id").autoIncrement()\n val clickDate = datetime("click_date")\n val response = reference("response_id", onDelete = ReferenceOption.CASCADE, refColumn = ResponseTable.id)\n override val primaryKey: PrimaryKey = PrimaryKey(id)\n}\n')),Object(o.b)("p",null,"We need to create the tables as defined above programmatically"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'fun initDatabase() {\n val config = HikariConfig().apply {\n jdbcUrl = "jdbc:postgresql://127.0.0.1:5432/exposed"\n username = "exposed"\n password = "exposed"\n driverClassName = "org.postgresql.Driver"\n }\n\n Database.connect(HikariDataSource(config))\n\n transaction {\n // create tables if they do not exist\n SchemaUtils.createMissingTablesAndColumns(RequestTable, ClickOverTimeTable)\n }\n}\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n initDatabase()\n // ...\n}\n')),Object(o.b)("p",null,"We have to replace the Hash Table used to store the data by the PostgreSQL database (see the final code ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/ktor-url-shortener/blob/with_postgresql/src/Application.kt"}),"here"),")"),Object(o.b)("h2",{id:"deploy-in-the-cloud-with-qovery"},"Deploy in the Cloud with Qovery"),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com"}),"Qovery")," is going to help us to deploy the final application in the Cloud without the need to configure the CI/CD, network, security, load balancing, database and all the DevOps tasks"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"Qovery is a deployment platform that helps all developers to deploy their applications in the Cloud in just a few seconds")),Object(o.b)(u.a,{name:"tutorial",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Your code need to be hosted on Github/Gitlab/Bitbucket"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://ktor.io/quickstart/quickstart/docker.html"}),"Package your Ktor application to build and run it on Docker")))),Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"web",placeholder:"Select your interface",select:!1,size:null,values:[{group:"Interfaces",label:"Web",value:"web"},{group:"Interfaces",label:"CLI",value:"cli"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"web",mdxType:"TabItem"},Object(o.b)("li",null,Object(o.b)("p",null,"Sign in to the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web interface"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("a",{href:"https://onboarding.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.jpg",alt:"Qovery Sign-up page"}))))),Object(o.b)(b.a,{value:"cli",mdxType:"TabItem"},Object(o.b)("li",null,Object(o.b)("h3",{id:"install-qovery-cli"},"Install Qovery CLI"),Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"linux",placeholder:"Select your OS",select:!1,size:null,values:[{group:"Platforms",label:"Linux",value:"linux"},{group:"Platforms",label:"MacOS",value:"macos"},{group:"Platforms",label:"Windows",value:"windows"},{group:"Platforms",label:"Docker",value:"docker"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"universal",values:[{label:"*nix",value:"universal"},{label:"Arch Linux",value:"arch"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"universal",mdxType:"TabItem"},Object(o.b)("p",null,"To download and install Qovery CLI on any Linux distribution:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(b.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(b.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Linux manually by downloading the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(o.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(o.b)(b.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"homebrew",values:[{label:"Homebrew",value:"homebrew"},{label:"Script",value:"script"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"homebrew",mdxType:"TabItem"},Object(o.b)("p",null,"The common solution to install a command line binary on the MacOS is to use ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery brew repository\n$ brew tap Qovery/qovery-cli\n\n# Install the CLI\n$ brew install qovery-cli\n"))),Object(o.b)(b.a,{value:"script",mdxType:"TabItem"},Object(o.b)("p",null,"To download and install Qovery CLI from the command line:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(b.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Mac OS manually by downloading the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(o.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(o.b)(b.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"scoop",mdxType:"TabItem"},Object(o.b)("p",null,"The classic way to install binaries on Windows is to use ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery bucket\n$ scoop bucket add qovery https://github.com/Qovery/scoop-qovery-cli\n\n# Install the CLI\n$ scoop install qovery-cli\n"))),Object(o.b)(b.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Windows manually by downloading the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to\n",Object(o.b)("inlineCode",{parentName:"p"},"C:\\Windows"),".")))),Object(o.b)(b.a,{value:"docker",mdxType:"TabItem"},Object(o.b)("p",null,"Install Docker on your local machine and run the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Pull and Run the latest Qovery CLI\n$ docker run ghcr.io/qovery/qovery-cli:latest help\n")),Object(o.b)("p",null,"Change ",Object(o.b)("inlineCode",{parentName:"p"},"latest")," by the version you want to use. For example, to use the version 0.58.4, run:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ docker run ghcr.io/qovery/qovery-cli:0.58.4 help\n")),Object(o.b)("p",null,"Note: ",Object(o.b)("inlineCode",{parentName:"p"},"ghcr.io")," is the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/pkgs/container/qovery-cli"}),"GitHub Container Registry"),".")))),Object(o.b)("li",null,Object(o.b)("h3",{id:"sign-up"},"Sign up"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using an environment without access to GUI or a browser, you can use headless authentication instead:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth --headless\n"))),Object(o.b)("p",null,"Your browser window with sign-in options will open."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/qovery_signup.svg",alt:"Qovery Sign-up page"})),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/apps/qovery/installations/new"}),"Click here")," to authorize Qovery to clone and build your applications."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/github_signup.svg",alt:"Connect Github"})),Object(o.b)("p",null,"Congratulations, you are logged-in.")))),Object(o.b)("h3",{id:"create-an-application"},"Create an application"),Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h3",{id:"create-a-new-project"},"Create a new project"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/heroku/heroku-2.png",alt:"Migrate from Heroku"}))),Object(o.b)("li",null,Object(o.b)("h3",{id:"create-a-new-environment"},"Create a new environment"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/heroku/heroku-3.png",alt:"Migrate from Heroku"}))),Object(o.b)("li",null,Object(o.b)("h3",{id:"create-a-new-application"},"Create a new application"),Object(o.b)("p",null,"To follow the guide, ",Object(o.b)("a",{href:"https://github.com/evoxmusic/ktor-url-shortener.git"},"you can fork and use our repository")),Object(o.b)("p",null,"Use the forked repository (and branch ",Object(o.b)("strong",{parentName:"p"},"master"),") while creating the application in the repository field:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/rust/rust.png",alt:"Migrate from Heroku"}))),Object(o.b)("li",null,Object(o.b)("p",null,"After the application is created: "),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate application settings"),Object(o.b)("li",{parentName:"ul"},"Select ",Object(o.b)("strong",{parentName:"li"},"Port")),Object(o.b)("li",{parentName:"ul"},"Add port 8080")),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros-1.png",alt:"Microservices"})),Object(o.b)("p",null,"This will expose your application and make accessible in the public internet.")))),Object(o.b)("h3",{id:"deploy-a-database"},"Deploy a database"),Object(o.b)("p",null,"Create and deploy a new database."),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},"Name the new database **my-pql-db** to follow the guide flawlessly"),Object(o.b)("p",null,"To learn how to do it, you can ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"follow this guide"),"."),Object(o.b)("h3",{id:"connect-to-postgresql"},"Connect to PostgreSQL"),Object(o.b)("p",null,"Qovery add dynamically all required environment variables to connect to the database at the runtime of the container."),Object(o.b)("p",null,"You can list them all in ",Object(o.b)("strong",{parentName:"p"},"Environment Variables")," ",Object(o.b)("strong",{parentName:"p"},"Secrets")," section in your application overview, as described in ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/managing-environment-variables/"}),"envs guide"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/db-envs.png",alt:"DB Secrets"})),Object(o.b)("p",null,"To use them:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'fun initDatabase() {\n val config = HikariConfig().apply {\n jdbcUrl = "jdbc:${System.getenv("QOVERY_DATABASE_MY_PQL_DB_CONNECTION_URI_WITHOUT_CREDENTIALS")}"\n username = System.getenv("QOVERY_DATABASE_MY_PQL_DB_USERNAME")\n password = System.getenv("QOVERY_DATABASE_MY_PQL_DB_PASSWORD")\n driverClassName = "org.postgresql.Driver"\n }\n\n Database.connect(HikariDataSource(config))\n\n transaction {\n // create tables if they do not exist\n SchemaUtils.createMissingTablesAndColumns(RequestTable, ClickOverTimeTable)\n }\n}\n')),Object(o.b)("h3",{id:"deploy"},"Deploy"),Object(o.b)("p",null,"To deploy your application and database, click ",Object(o.b)("strong",{parentName:"p"},"Action")," and ",Object(o.b)("strong",{parentName:"p"},"Deploy")," button in your environments list view:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deploy-env.png",alt:"Kotlin URL Shortener"})),Object(o.b)("p",null,"To get public URL to the application, open application details and click on ",Object(o.b)("strong",{parentName:"p"},"Action")," ",Object(o.b)("strong",{parentName:"p"},"Open"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deploy-env-1.png",alt:"Kotlin URL Shortener"})),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/open-app.png",alt:"Kotlin URL Shortener"})),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"We have seen that creating an URL shortener API with Ktor and Kotlin is extremely simple. Connecting the application to PostgreSQL is very easy with the Exposed library. In just a few lines of code, the service is fully functional and can be deployed in production very quickly with the help of Qovery. In the next part, we will see how to create a web interface connecting to this API to convert our URLs without using the curl command."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Part 2"),": bind a web interface to the API - ","[link coming soon]"),Object(o.b)(l.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}g.isMDXComponent=!0},424:function(e,t,n){"use strict";n(426);var a=n(0),r=n.n(a),o=n(423),i=n.n(o);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,o=e.icon,l=e.type,s=null;switch(l){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return r.a.createElement("div",{className:i()(n,"alert","alert--"+l,{"alert--fill":a,"alert--icon":!1!==o}),role:"alert"},!1!==o&&r.a.createElement("i",{className:i()("feather","icon-"+(o||s))}),t)}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(432),s=n(20),c=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,b=n||s,u=Object(l.a)(b),p=Object(r.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var n,a;d&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:b})):o.a.createElement("a",Object(a.a)({},e,{href:b}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),i=n(423),l=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,s=e.rightIcon,c=e.size,b=e.target,u=e.to,p=l()("jump-to","jump-to--"+c,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return b?r.a.createElement("a",{href:u,target:b,className:p},d):r.a.createElement(o.a,{to:u,className:p},d)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},434:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},c="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),b=Object(a.useState)(null),u=b[0],p=b[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:c,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},437:function(e,t,n){"use strict";var a=n(1),r=(n(442),n(439),n(52),n(29),n(22),n(21),n(0)),o=n.n(r),i=n(449),l=n(423),s=n.n(l),c=n(433),b=n.n(c),u=n(448),p=37,d=39;function h(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,r=e.className,i=e.handleKeydown,l=e.style,c=e.values,b=e.selectedValue,u=e.tabRefs;return o.a.createElement("div",{className:n?"tabs--centered":null},o.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:s()("tabs",r,{"tabs--block":t}),style:l},c.map((function(e){var t=e.value,n=e.label;return o.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:s()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return i(u,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function m(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,r=e.size,l=e.values,s=l;if(s[0].group){var c=_.groupBy(s,"group");s=Object.keys(c).map((function(e){return{label:e,options:c[e]}}))}return o.a.createElement(i.a,{className:"react-select-container react-select--"+r,classNamePrefix:"react-select",options:s,isClearable:n,placeholder:t,value:l.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,i=e.groupId,l=e.label,s=e.placeholder,c=e.select,g=e.size,v=(e.style,e.values),j=e.urlKey,O=Object(u.a)(),f=O.tabGroupChoices,y=O.setTabGroupChoices,w=Object(r.useState)(n),N=w[0],k=w[1];if(null!=i){var T=f[i];null!=T&&T!==N&&k(T)}var R=function(e){k(e),null!=i&&y(i,e)},S=[],I=function(e,t,n){switch(n.keyCode){case d:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(r.useEffect)((function(){if("undefined"!=typeof window&&window.location&&j){var e=b.a.parse(window.location.search);e[j]&&k(e[j])}}),[]),o.a.createElement(o.a.Fragment,null,o.a.createElement("div",{className:"margin-bottom--"+(g||"md")},l&&o.a.createElement("div",{className:"margin-vert--sm"},l),v.length>1&&(c?o.a.createElement(m,Object(a.a)({changeSelectedValue:R,handleKeydown:I,placeholder:s,selectedValue:N,size:g,tabRefs:S},e)):o.a.createElement(h,Object(a.a)({changeSelectedValue:R,handleKeydown:I,selectedValue:N,tabRefs:S},e)))),r.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},444:function(e,t,n){"use strict";var a=n(0),r=n.n(a);t.a=function(e){return r.a.createElement(r.a.Fragment,null,e.children)}}}]); \ No newline at end of file diff --git a/ac2c90fd.02f5bb51.js b/ac2c90fd.4f99cc6a.js similarity index 96% rename from ac2c90fd.02f5bb51.js rename to ac2c90fd.4f99cc6a.js index 743c721436..32953a324d 100644 --- a/ac2c90fd.02f5bb51.js +++ b/ac2c90fd.4f99cc6a.js @@ -1,2 +1,2 @@ -/*! For license information please see ac2c90fd.02f5bb51.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[169],{321:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return d}));var a=n(1),r=n(9),o=(n(0),n(422)),s=n(421),i={last_modified_on:"2022-11-11",title:"Maintenance",description:"Maintainance and operation for your Qovery cluster and applications",sidebar_label:"hidden",hide_pagination:!0},c={id:"using-qovery/maintenance",title:"Maintenance",description:"Maintainance and operation for your Qovery cluster and applications",source:"@site/docs/using-qovery/maintenance.md",permalink:"/docs/using-qovery/maintenance",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Audit Logs",permalink:"/docs/using-qovery/audit-logs"},next:{title:"Security and Compliance",permalink:"/docs/security-and-compliance"}},l=[{value:"Kubernetes and components, patches, and upgrades",id:"kubernetes-and-components-patches-and-upgrades",children:[]},{value:"Managed services patches and upgrades",id:"managed-services-patches-and-upgrades",children:[]},{value:"Cloud providers' limits",id:"cloud-providers-limits",children:[]},{value:"Rotating system credentials",id:"rotating-system-credentials",children:[{value:"Manual rotation",id:"manual-rotation",children:[]},{value:"Automatic rotation",id:"automatic-rotation",children:[]}]}],u={rightToc:l};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"This guide will provide inputs about maintenance with Qovery. Qovery provides automatic and silent updates as much as possible. With and without cloud providers."),Object(o.b)("h2",{id:"kubernetes-and-components-patches-and-upgrades"},"Kubernetes and components, patches, and upgrades"),Object(o.b)("p",null,"Qovery manages Kubernetes updates through the Cloud provider update mechanism and ensures full compatibility with all deployed infrastructure components (Nginx ingress, cert-manager, CNI, CSI, etc.) inside the Kubernetes cluster."),Object(o.b)(s.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"To avoid as maximum as possible small downtimes, Qovery is using the rolling update strategy for the Kubernetes cluster and components. This strategy is the default strategy for Kubernetes and is the most reliable one.\nYou may need to adapt some liveness and readiness probes for some long-running applications to avoid downtimes.")),Object(o.b)("p",null,"Security patches and minor updates are applied automatically and silently by the cloud provider. Kubernetes major updates are applied automatically by Qovery to ensure compatibility between every deployed components inside the cluster."),Object(o.b)(s.a,{type:"danger",mdxType:"Alert"},Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"While Qovery allows customers to access Kubernetes cluster and manually deploy resources, Qovery is not responsible for any issues that may occur on those deployed resources."),Object(o.b)("li",{parentName:"ol"},"Qovery support can be canceled by Qovery, if the customer is manually updating or upgrading the Kubernetes cluster or components managed by Qovery."))),Object(o.b)("h2",{id:"managed-services-patches-and-upgrades"},"Managed services patches and upgrades"),Object(o.b)("p",null,"By default, every managed service deployed by Qovery is configured with automatic patches and upgrades proposed by the cloud provider."),Object(o.b)("p",null,"Major version upgrades are up to the end user to decide when it's the right time to upgrade."),Object(o.b)("h2",{id:"cloud-providers-limits"},"Cloud providers' limits"),Object(o.b)("p",null,"Cloud providers are using quotas for various reasons. Some of them are to prevent abuse, some others are to prevent overloading the infrastructure, and others are to prevent an excessive bill."),Object(o.b)("p",null,"It occurs that some customers are reaching the limits of their cloud provider. In this case, Qovery gives the information in the infrastructure or applications logs."),Object(o.b)("p",null,"It is up to the customer to contact the Cloud provider via ticketing support to increase the limits."),Object(o.b)("h2",{id:"rotating-system-credentials"},"Rotating system credentials"),Object(o.b)("p",null,"Some customers want to rotate their system credentials because on legal requests, security requirements, or other reasons. Qovery provides makes it simple to rotate credentials."),Object(o.b)("p",null,"Here is the way we recommend to avoid any downtime on your cluster and for your application deployments. Open your AWS console and open the ",Object(o.b)("inlineCode",{parentName:"p"},"Qovery")," user in the IAM service."),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/configuration/maintenance/aws_iam_user_select.png",alt:"User select"})),Object(o.b)("p",null,"Click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Security credentials")," tab, you will see one access key present:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/configuration/maintenance/aws_iam_access_key_list.png",alt:"User select"})),Object(o.b)("p",null,"For a single account, we can create up to two access keys. So we can create a new one, request a cluster deployment, wait for the deployment to be done, and then delete the old one."),Object(o.b)(s.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This key is also used to connect to the Kubernetes cluster and make deployments. You may encounter deployment failures if the key is deleted before the deployment is done.\nWe advise your to wait 1h or 2h before deleting the old key.")),Object(o.b)("p",null,"You can now 2 ways to rotate your credentials, select the one you prefer:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Manual"),": you update manually credentials from the Qovery interface"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Automatic"),": you update automatically credentials with a script")),Object(o.b)("h3",{id:"manual-rotation"},"Manual rotation"),Object(o.b)("p",null,"You can update or rotate manually credentials on your AWS account this way:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/configuration/maintenance/aws_iam_create_access_key.png",alt:"User select"})),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Click on the ",Object(o.b)("inlineCode",{parentName:"li"},"Create access key")," button"),Object(o.b)("li",{parentName:"ol"},"Save the ",Object(o.b)("inlineCode",{parentName:"li"},"access key")," and ",Object(o.b)("inlineCode",{parentName:"li"},"secret access Key")," in a safe place"),Object(o.b)("li",{parentName:"ol"},"Go to your Qovery dashboard to ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#credentials"}),"update the credentials on Qovery console"),"."),Object(o.b)("li",{parentName:"ol"},Object(o.b)("inlineCode",{parentName:"li"},"Deploy")," the cluster once again to apply changes"),Object(o.b)("li",{parentName:"ol"},"Once the cluster is fully updated, wait 2h (to ensure all ongoing deployments are done)"),Object(o.b)("li",{parentName:"ol"},"Delete the old access key from the AWS console:")),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/configuration/maintenance/aws_iam_delete_access_key.png",alt:"User select"})),Object(o.b)(s.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you have a doubt about the old credentials deletion, you can simply deactivate the old ",Object(o.b)("inlineCode",{parentName:"p"},"access key")," for a while and delete it later.")),Object(o.b)("h3",{id:"automatic-rotation"},"Automatic rotation"),Object(o.b)("p",null,"Another way to do it more programmatically. Here is a script to perform those actions, adapt it to your needs if you need and add it to your "),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'#!/bin/bash\n\n############## VARIABLES AND INSTRUCTIONS ##############\n\n# Ensure you have jq and awscli installed\n\n# 1. Ensure your AWS environment variables are set: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html\n# 2. AWS username to perform the rotation\naws_iam_username="Qovery"\n# 3. Use qovery CLI to generate a dedicated token\nqovery_token="xxx"\n# 4. Organization ID can be retrieved inside the Qovery console URL, where your cluster is located\norganization_id="xxx"\n# 5. Get your credentials: curl -s -X GET -H "Content-type: application/json\' -H \'Authorization: Token $qovery_token" "https://api.qovery.com/organization/$organization_id/aws/credentials"\ncredentials_id="xxx"\n# 6. Name of the credentials to update\ncredentials_name="My organization credentials"\n# 7. Cluster ID can be retrieved inside the Qovery console URL, where your cluster is located\ncluster_id="xxx"\n# 8. Set the delay to wait before deleting the old key in seconds (do not go below 7200)\ndelay_before_delete_old_key=7200\n\n############## DO NOT EDIT ##############\n\nset -e\n\necho "[+] Ensure there is only one Access Key"\nold_aws_access_key=$(aws iam list-access-keys --user-name $aws_iam_username | jq -r \'.AccessKeyMetadata[].AccessKeyId\')\nif [ $(echo $old_aws_access_key | grep -c \' \') -ne 0 ]; then\n echo "ERROR: more than one access key found, please delete the one not used by Qovery"\n exit 1\nfi\nif [ "$old_aws_access_key" == "" ] ; then\n echo "ERROR: no access key found, are you sure it\'s the correct user?"\n exit 1\nfi\necho " -> Current (future old) key detected: $old_aws_access_key"\n\ncurrent_time=$(date +"%s")\nmax_time=$((current_time + delay_before_delete_old_key))\ncluster_status=""\n\necho "[+] Create a new Access Key"\nnew_aws_access_key_json=$(aws iam create-access-key --user-name $aws_iam_username)\nnew_aws_access_key=$(echo $new_aws_access_key_json | jq -r \'.AccessKey.AccessKeyId\')\nnew_aws_secret_key=$(echo $new_aws_access_key_json | jq -r \'.AccessKey.SecretAccessKey\')\necho " -> Successfully created a new access key: $new_aws_access_key"\n\necho "[+] Update Qovery credentials"\ncurl -s -X PUT -H "Content-type: application/json" -H "Authorization: Token $qovery_token" -d "{\\"name\\": \\"$credentials_name\\", \\"access_key\\": \\"$new_aws_access_key\\", \\"secret_key\\": \\"$new_aws_secret_key\\"}" "https://api.qovery.com/organization/$organization_id/aws/credentials/$credentials_id" 1>/dev/null\n\necho "[+] Deploy the cluster with the new credentials"\ncurl -s -X POST -H "Content-type: application/json" -H "Authorization: Token $qovery_token" "https://api.qovery.com/organization/$organization_id/cluster/$cluster_id/deploy" 1>/dev/null\n\necho "[+] Wait for the cluster deployment to be done"\nsleep 15\nwhile [ "$cluster_status" != "RUNNING" ]; do\n sleep 60\n cluster_status=$(curl -s -X GET -H "Content-type: application/json" -H "Authorization: Token $qovery_token" "https://api.qovery.com/organization/$organization_id/cluster/$cluster_id/status" | jq -r \'.status\')\n echo " -> $(date "+%H:%M") Waiting for the cluster deployment to be done. Current status: $cluster_status..."\n # Ensure the cluster is in a valid state\n if [ "$cluster_status" != "DEPLOYMENT_QUEUED" ] && [ "$cluster_status" != "DEPLOYING" ] && [ "$cluster_status" != "DEPLOYED" ] && [ "$cluster_status" != "RUNNING" ]; then\n echo "ERROR: the cluster does not have a correct status, please check cluster logs and fix the issue. Then delete the key $old_aws_access_key and retry"\n exit 1\n fi\n if [ $(date +"%s") -gt $max_time ]; then\n echo "ERROR: timeout reached, the cluster is not deployed yet, please check cluster logs and fix the cluster issue. Then delete the key $new_aws_access_key and retry"\n exit 1\n fi\ndone\n\necho "[+] Waiting up to 2h to ensure all ongoing deployments are done ($(date -d @$max_time))"\nwhile [ $(date +"%s") -lt $max_time ]; do\n sleep 10\ndone\n\necho "[+] Delete the old Access Key"\naws iam delete-access-key --access-key-id $old_aws_access_key --user-name $aws_iam_username\n\necho "[+] Done"\n')),Object(o.b)("p",null,"You will see the following output:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"[+] Ensure there is only one Access Key\n -> Current (future old) key detected: xxx\n[+] Create a new Access Key\n -> Successfully created a new access key: yyy\n[+] Update Qovery credentials\n[+] Deploy the cluster with the new credentials\n[+] Wait for the cluster deployment to be done\n -> 15:04 Waiting for the cluster deployment to be done. Current status: DEPLOYING...\n -> 15:05 Waiting for the cluster deployment to be done. Current status: DEPLOYING...\n -> 15:06 Waiting for the cluster deployment to be done. Current status: DEPLOYING...\n -> 15:07 Waiting for the cluster deployment to be done. Current status: RUNNING...\n[+] Waiting up to 2h to ensure all ongoing deployments are done (Fri Nov 11 03:22:57 PM CET 2022)\n[+] Delete the old Access Key\n[+] Done\n")))}d.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),u=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},d=function(e){var t=u(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},y=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),d=u(n),y=a,m=d["".concat(s,".").concat(y)]||d[y]||p[y]||o;return n?r.a.createElement(m,i({ref:t},l,{components:n})):r.a.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=y;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i.mdxType="string"==typeof e?e:a,s[1]=i;for(var l=2;l1?arguments[1]:void 0,n),c=s>2?arguments[2]:void 0,l=void 0===c?n:r(c,n);l>i;)t[i++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see ac2c90fd.4f99cc6a.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[172],{324:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return d}));var a=n(1),r=n(9),o=(n(0),n(425)),s=n(424),i={last_modified_on:"2022-11-11",title:"Maintenance",description:"Maintainance and operation for your Qovery cluster and applications",sidebar_label:"hidden",hide_pagination:!0},c={id:"using-qovery/maintenance",title:"Maintenance",description:"Maintainance and operation for your Qovery cluster and applications",source:"@site/docs/using-qovery/maintenance.md",permalink:"/docs/using-qovery/maintenance",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Audit Logs",permalink:"/docs/using-qovery/audit-logs"},next:{title:"Security and Compliance",permalink:"/docs/security-and-compliance"}},l=[{value:"Kubernetes and components, patches, and upgrades",id:"kubernetes-and-components-patches-and-upgrades",children:[]},{value:"Managed services patches and upgrades",id:"managed-services-patches-and-upgrades",children:[]},{value:"Cloud providers' limits",id:"cloud-providers-limits",children:[]},{value:"Rotating system credentials",id:"rotating-system-credentials",children:[{value:"Manual rotation",id:"manual-rotation",children:[]},{value:"Automatic rotation",id:"automatic-rotation",children:[]}]}],u={rightToc:l};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"This guide will provide inputs about maintenance with Qovery. Qovery provides automatic and silent updates as much as possible. With and without cloud providers."),Object(o.b)("h2",{id:"kubernetes-and-components-patches-and-upgrades"},"Kubernetes and components, patches, and upgrades"),Object(o.b)("p",null,"Qovery manages Kubernetes updates through the Cloud provider update mechanism and ensures full compatibility with all deployed infrastructure components (Nginx ingress, cert-manager, CNI, CSI, etc.) inside the Kubernetes cluster."),Object(o.b)(s.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"To avoid as maximum as possible small downtimes, Qovery is using the rolling update strategy for the Kubernetes cluster and components. This strategy is the default strategy for Kubernetes and is the most reliable one.\nYou may need to adapt some liveness and readiness probes for some long-running applications to avoid downtimes.")),Object(o.b)("p",null,"Security patches and minor updates are applied automatically and silently by the cloud provider. Kubernetes major updates are applied automatically by Qovery to ensure compatibility between every deployed components inside the cluster."),Object(o.b)(s.a,{type:"danger",mdxType:"Alert"},Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"While Qovery allows customers to access Kubernetes cluster and manually deploy resources, Qovery is not responsible for any issues that may occur on those deployed resources."),Object(o.b)("li",{parentName:"ol"},"Qovery support can be canceled by Qovery, if the customer is manually updating or upgrading the Kubernetes cluster or components managed by Qovery."))),Object(o.b)("h2",{id:"managed-services-patches-and-upgrades"},"Managed services patches and upgrades"),Object(o.b)("p",null,"By default, every managed service deployed by Qovery is configured with automatic patches and upgrades proposed by the cloud provider."),Object(o.b)("p",null,"Major version upgrades are up to the end user to decide when it's the right time to upgrade."),Object(o.b)("h2",{id:"cloud-providers-limits"},"Cloud providers' limits"),Object(o.b)("p",null,"Cloud providers are using quotas for various reasons. Some of them are to prevent abuse, some others are to prevent overloading the infrastructure, and others are to prevent an excessive bill."),Object(o.b)("p",null,"It occurs that some customers are reaching the limits of their cloud provider. In this case, Qovery gives the information in the infrastructure or applications logs."),Object(o.b)("p",null,"It is up to the customer to contact the Cloud provider via ticketing support to increase the limits."),Object(o.b)("h2",{id:"rotating-system-credentials"},"Rotating system credentials"),Object(o.b)("p",null,"Some customers want to rotate their system credentials because on legal requests, security requirements, or other reasons. Qovery provides makes it simple to rotate credentials."),Object(o.b)("p",null,"Here is the way we recommend to avoid any downtime on your cluster and for your application deployments. Open your AWS console and open the ",Object(o.b)("inlineCode",{parentName:"p"},"Qovery")," user in the IAM service."),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/configuration/maintenance/aws_iam_user_select.png",alt:"User select"})),Object(o.b)("p",null,"Click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Security credentials")," tab, you will see one access key present:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/configuration/maintenance/aws_iam_access_key_list.png",alt:"User select"})),Object(o.b)("p",null,"For a single account, we can create up to two access keys. So we can create a new one, request a cluster deployment, wait for the deployment to be done, and then delete the old one."),Object(o.b)(s.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This key is also used to connect to the Kubernetes cluster and make deployments. You may encounter deployment failures if the key is deleted before the deployment is done.\nWe advise your to wait 1h or 2h before deleting the old key.")),Object(o.b)("p",null,"You can now 2 ways to rotate your credentials, select the one you prefer:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Manual"),": you update manually credentials from the Qovery interface"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Automatic"),": you update automatically credentials with a script")),Object(o.b)("h3",{id:"manual-rotation"},"Manual rotation"),Object(o.b)("p",null,"You can update or rotate manually credentials on your AWS account this way:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/configuration/maintenance/aws_iam_create_access_key.png",alt:"User select"})),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Click on the ",Object(o.b)("inlineCode",{parentName:"li"},"Create access key")," button"),Object(o.b)("li",{parentName:"ol"},"Save the ",Object(o.b)("inlineCode",{parentName:"li"},"access key")," and ",Object(o.b)("inlineCode",{parentName:"li"},"secret access Key")," in a safe place"),Object(o.b)("li",{parentName:"ol"},"Go to your Qovery dashboard to ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#credentials"}),"update the credentials on Qovery console"),"."),Object(o.b)("li",{parentName:"ol"},Object(o.b)("inlineCode",{parentName:"li"},"Deploy")," the cluster once again to apply changes"),Object(o.b)("li",{parentName:"ol"},"Once the cluster is fully updated, wait 2h (to ensure all ongoing deployments are done)"),Object(o.b)("li",{parentName:"ol"},"Delete the old access key from the AWS console:")),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/configuration/maintenance/aws_iam_delete_access_key.png",alt:"User select"})),Object(o.b)(s.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you have a doubt about the old credentials deletion, you can simply deactivate the old ",Object(o.b)("inlineCode",{parentName:"p"},"access key")," for a while and delete it later.")),Object(o.b)("h3",{id:"automatic-rotation"},"Automatic rotation"),Object(o.b)("p",null,"Another way to do it more programmatically. Here is a script to perform those actions, adapt it to your needs if you need and add it to your "),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'#!/bin/bash\n\n############## VARIABLES AND INSTRUCTIONS ##############\n\n# Ensure you have jq and awscli installed\n\n# 1. Ensure your AWS environment variables are set: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html\n# 2. AWS username to perform the rotation\naws_iam_username="Qovery"\n# 3. Use qovery CLI to generate a dedicated token\nqovery_token="xxx"\n# 4. Organization ID can be retrieved inside the Qovery console URL, where your cluster is located\norganization_id="xxx"\n# 5. Get your credentials: curl -s -X GET -H "Content-type: application/json\' -H \'Authorization: Token $qovery_token" "https://api.qovery.com/organization/$organization_id/aws/credentials"\ncredentials_id="xxx"\n# 6. Name of the credentials to update\ncredentials_name="My organization credentials"\n# 7. Cluster ID can be retrieved inside the Qovery console URL, where your cluster is located\ncluster_id="xxx"\n# 8. Set the delay to wait before deleting the old key in seconds (do not go below 7200)\ndelay_before_delete_old_key=7200\n\n############## DO NOT EDIT ##############\n\nset -e\n\necho "[+] Ensure there is only one Access Key"\nold_aws_access_key=$(aws iam list-access-keys --user-name $aws_iam_username | jq -r \'.AccessKeyMetadata[].AccessKeyId\')\nif [ $(echo $old_aws_access_key | grep -c \' \') -ne 0 ]; then\n echo "ERROR: more than one access key found, please delete the one not used by Qovery"\n exit 1\nfi\nif [ "$old_aws_access_key" == "" ] ; then\n echo "ERROR: no access key found, are you sure it\'s the correct user?"\n exit 1\nfi\necho " -> Current (future old) key detected: $old_aws_access_key"\n\ncurrent_time=$(date +"%s")\nmax_time=$((current_time + delay_before_delete_old_key))\ncluster_status=""\n\necho "[+] Create a new Access Key"\nnew_aws_access_key_json=$(aws iam create-access-key --user-name $aws_iam_username)\nnew_aws_access_key=$(echo $new_aws_access_key_json | jq -r \'.AccessKey.AccessKeyId\')\nnew_aws_secret_key=$(echo $new_aws_access_key_json | jq -r \'.AccessKey.SecretAccessKey\')\necho " -> Successfully created a new access key: $new_aws_access_key"\n\necho "[+] Update Qovery credentials"\ncurl -s -X PUT -H "Content-type: application/json" -H "Authorization: Token $qovery_token" -d "{\\"name\\": \\"$credentials_name\\", \\"access_key\\": \\"$new_aws_access_key\\", \\"secret_key\\": \\"$new_aws_secret_key\\"}" "https://api.qovery.com/organization/$organization_id/aws/credentials/$credentials_id" 1>/dev/null\n\necho "[+] Deploy the cluster with the new credentials"\ncurl -s -X POST -H "Content-type: application/json" -H "Authorization: Token $qovery_token" "https://api.qovery.com/organization/$organization_id/cluster/$cluster_id/deploy" 1>/dev/null\n\necho "[+] Wait for the cluster deployment to be done"\nsleep 15\nwhile [ "$cluster_status" != "RUNNING" ]; do\n sleep 60\n cluster_status=$(curl -s -X GET -H "Content-type: application/json" -H "Authorization: Token $qovery_token" "https://api.qovery.com/organization/$organization_id/cluster/$cluster_id/status" | jq -r \'.status\')\n echo " -> $(date "+%H:%M") Waiting for the cluster deployment to be done. Current status: $cluster_status..."\n # Ensure the cluster is in a valid state\n if [ "$cluster_status" != "DEPLOYMENT_QUEUED" ] && [ "$cluster_status" != "DEPLOYING" ] && [ "$cluster_status" != "DEPLOYED" ] && [ "$cluster_status" != "RUNNING" ]; then\n echo "ERROR: the cluster does not have a correct status, please check cluster logs and fix the issue. Then delete the key $old_aws_access_key and retry"\n exit 1\n fi\n if [ $(date +"%s") -gt $max_time ]; then\n echo "ERROR: timeout reached, the cluster is not deployed yet, please check cluster logs and fix the cluster issue. Then delete the key $new_aws_access_key and retry"\n exit 1\n fi\ndone\n\necho "[+] Waiting up to 2h to ensure all ongoing deployments are done ($(date -d @$max_time))"\nwhile [ $(date +"%s") -lt $max_time ]; do\n sleep 10\ndone\n\necho "[+] Delete the old Access Key"\naws iam delete-access-key --access-key-id $old_aws_access_key --user-name $aws_iam_username\n\necho "[+] Done"\n')),Object(o.b)("p",null,"You will see the following output:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"[+] Ensure there is only one Access Key\n -> Current (future old) key detected: xxx\n[+] Create a new Access Key\n -> Successfully created a new access key: yyy\n[+] Update Qovery credentials\n[+] Deploy the cluster with the new credentials\n[+] Wait for the cluster deployment to be done\n -> 15:04 Waiting for the cluster deployment to be done. Current status: DEPLOYING...\n -> 15:05 Waiting for the cluster deployment to be done. Current status: DEPLOYING...\n -> 15:06 Waiting for the cluster deployment to be done. Current status: DEPLOYING...\n -> 15:07 Waiting for the cluster deployment to be done. Current status: RUNNING...\n[+] Waiting up to 2h to ensure all ongoing deployments are done (Fri Nov 11 03:22:57 PM CET 2022)\n[+] Delete the old Access Key\n[+] Done\n")))}d.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),u=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},d=function(e){var t=u(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},y=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),d=u(n),y=a,m=d["".concat(s,".").concat(y)]||d[y]||p[y]||o;return n?r.a.createElement(m,i({ref:t},l,{components:n})):r.a.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=y;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i.mdxType="string"==typeof e?e:a,s[1]=i;for(var l=2;l1?arguments[1]:void 0,n),c=s>2?arguments[2]:void 0,l=void 0===c?n:r(c,n);l>i;)t[i++]=e;return t}}}]); \ No newline at end of file diff --git a/b2880863.f32a0387.js.LICENSE.txt b/ac2c90fd.4f99cc6a.js.LICENSE.txt similarity index 100% rename from b2880863.f32a0387.js.LICENSE.txt rename to ac2c90fd.4f99cc6a.js.LICENSE.txt diff --git a/a4c8ecc0.d76b8560.js b/acaf40e9.fd86f35e.js similarity index 95% rename from a4c8ecc0.d76b8560.js rename to acaf40e9.fd86f35e.js index 8b2faf03f6..3083d97a32 100644 --- a/a4c8ecc0.d76b8560.js +++ b/acaf40e9.fd86f35e.js @@ -1,2 +1,2 @@ -/*! For license information please see a4c8ecc0.d76b8560.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[163],{315:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return c})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),o=(n(0),n(422)),i=(n(421),n(426),n(429),{last_modified_on:"2022-03-09",$schema:"/.meta/.schemas/guides.json",title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2",readingTime:"8 min read",source:"@site/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",truncated:!1,prevItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1"},nextItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3"}},c=[{value:"Architecture",id:"architecture",children:[]},{value:"Hosting AppWrite Cloud",id:"hosting-appwrite-cloud",children:[]},{value:"Deploying AppWrite Cloud on Qovery",id:"deploying-appwrite-cloud-on-qovery",children:[{value:"Postgres",id:"postgres",children:[]},{value:"Hasura",id:"hasura",children:[]},{value:"Functions",id:"functions",children:[]},{value:"Deploy the environment",id:"deploy-the-environment",children:[]}]},{value:"Database Structure",id:"database-structure",children:[]},{value:"AppWrite Cloud API",id:"appwrite-cloud-api",children:[]},{value:"Testing AppWrite Cloud Backend",id:"testing-appwrite-cloud-backend",children:[{value:"Signup",id:"signup",children:[]},{value:"Create Project",id:"create-project",children:[]},{value:"Start / Stop Project",id:"start--stop-project",children:[]}]},{value:"AppWrite Cloud API domain",id:"appwrite-cloud-api-domain",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],s={rightToc:c};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"In the second part of the\xa0",Object(o.b)("em",{parentName:"p"},"Case Study with AppWrite"),", we will create the backend part of our AppWrite Cloud. The backend will communicate with Qovery API to request the infrastructure (",Object(o.b)("inlineCode",{parentName:"p"},"AppWrite")," instances and their dependencies, i.e. ",Object(o.b)("inlineCode",{parentName:"p"},"MariaDB")," and ",Object(o.b)("inlineCode",{parentName:"p"},"Redis"),") for AppWrite Cloud users. Qovery will take care of provisioning, managing, and running AppWrite instances and databases, while AppWrite Cloud will take care of providing a nice UI and other utilities for the users wanting to deploy AppWrite on a cloud-managed solution."),Object(o.b)("h2",{id:"architecture"},"Architecture"),Object(o.b)("p",null,"The backend of AppWrite Cloud will make use of a low-code tool ",Object(o.b)("inlineCode",{parentName:"p"},"Hasura"),". Hasura is an open-source project that allows building backend apps with minimal effort while still providing fast performance. It also allows executing custom business logic using cloud functions. Our Hasura backend will use ",Object(o.b)("inlineCode",{parentName:"p"},"PostgreSQL")," as its data store. In the first stage, the AppWrite Cloud backend will contain information about users and their projects. For all tasks related to running and managing the underlying infrastructure, it will call Qovery API and delegate those tasks to Qovery so that AppWrite Cloud can stay focused on delivering to their users what they really want - an excellent experience AppWrite, instead of wasting time on reinventing the wheel of managing the infrastructure."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-1.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"For all business logic, we will use the ",Object(o.b)("inlineCode",{parentName:"p"},"Async Actions")," feature of Hasura. In this approach, the Hasura backend calls external functions over the network and lets them perform any business logic required. The async functions can be hosted anywhere, as long as they conform to the contract required by Hasura."),Object(o.b)("h2",{id:"hosting-appwrite-cloud"},"Hosting AppWrite Cloud"),Object(o.b)("p",null,"Besides, hosting all the managed AppWrite projects of AppWrite Cloud users, Qovery can also host the whole AppWrite Cloud backend itself. Indeed, in this case study, we'll go through all the steps required to deploy AppWrite Cloud on Qovery."),Object(o.b)("h2",{id:"deploying-appwrite-cloud-on-qovery"},"Deploying AppWrite Cloud on Qovery"),Object(o.b)("p",null,"To deploy the AppWrite Cloud, we need to deploy a Hasura backend, a PostgreSQL database for Hasura, and our Go server for handling the custom business logic."),Object(o.b)("h3",{id:"postgres"},"Postgres"),Object(o.b)("p",null,"First, let's deploy our database. To do so, use Qovery Console to create a new project and environment, then click ",Object(o.b)("inlineCode",{parentName:"p"},"Add Database")," button and choose PostgreSQL ",Object(o.b)("inlineCode",{parentName:"p"},"v12"),"."),Object(o.b)("h3",{id:"hasura"},"Hasura"),Object(o.b)("p",null,"To deploy Hasura, fork this repository\xa0",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/hasura"}),"https://github.com/Qovery/hasura"),". Use ",Object(o.b)("inlineCode",{parentName:"p"},"DOCKER")," build mode and Port ",Object(o.b)("inlineCode",{parentName:"p"},"8080"),". Then, in the Environment Variables section, add the following variables:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_ENABLE_CONSOLE")," - true"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_ADMIN_SECRET")," - your Hasura admin secret (value up to you)"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_JWT_SECRET"))),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "type": "HS256",\n "key": "$KEY"\n}\n')),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"where ",Object(o.b)("inlineCode",{parentName:"li"},"$KEY")," is a minimum 32 character long string"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_DATABASE_URL")," - an alias to your previously created PostgreSQL URL")),Object(o.b)("h3",{id:"functions"},"Functions"),Object(o.b)("p",null,"Now, let's deploy our Go server. To do so, you can fork this repository\xa0",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/appwrite-functions"}),"https://github.com/pjeziorowski/appwrite-functions"),"."),Object(o.b)("p",null,"Create a new app using ",Object(o.b)("inlineCode",{parentName:"p"},"DOCKER")," build mode and Port ",Object(o.b)("inlineCode",{parentName:"p"},"3000"),"."),Object(o.b)("p",null,"Now, we need to set up a few environment variables:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"ORGANIZATION_ID_QOVERY")," - organization ID used as your AppWrite Cloud on Qovery"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"API_TOKEN_QOVERY")," - API token to use to interact with Qovery API"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_API_URL")," - location of your Hasura backend instance"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"SECRET")," - key to sign tokens, use the same value as in ",Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_JWT_SECRET")," key section"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_API_TOKEN")," - admin secret token of your Hasura instance")),Object(o.b)("h3",{id:"deploy-the-environment"},"Deploy the environment"),Object(o.b)("p",null,"After your project is set up as described above, deploy the whole environment, and your AppWrite Cloud backend will be ready to play and test."),Object(o.b)("h2",{id:"database-structure"},"Database Structure"),Object(o.b)("p",null,"All we need to store in the AppWrite Cloud database at the moment is users and their projects. For this, we will create a user table and project table that will contain AppWrite URLs and project names."),Object(o.b)("p",null,"To import the structure of the tables into the Hasura backend, you can use the metadata file located here ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/hasura/blob/main/appwrite-cloud-metadata.json"}),"hasura/appwrite-cloud-metadata.json at main \xb7 Qovery/hasura")),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"user")," table contains sign-in information (email and hashed password):"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-2.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"whereas the ",Object(o.b)("inlineCode",{parentName:"p"},"project")," table contains basic information about the project in AppWrite Cloud, URL to AppWrite instance as well as its mapping to a project in Qovery:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-3.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h2",{id:"appwrite-cloud-api"},"AppWrite Cloud API"),Object(o.b)("p",null,"The initial version of the API will allow to:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Signup")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Signin")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Create/Start/Stop/Delete AppWrite Instances"))),Object(o.b)("p",null,"The API will be exposed using Hasura Actions. Actions delegate the custom logic to handler functions we deployed in our Go server. Hasura will delegate the work of contacting the Qovery API to those functions."),Object(o.b)("p",null,"All the Actions were already imported into Hasura using the same metadata file as we used to import the structure of the tables."),Object(o.b)("p",null,"When you navigate to ",Object(o.b)("inlineCode",{parentName:"p"},"Actions")," section in Hasura, you'll see actions definition similar to this one:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-4.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"The functions serving those actions in our Golang app look more or less like this:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-go"}),'func stopProject(args StopProjectArgs, userId string) (response StopProjectOutput, err error) {\n log.Printf("received stop project request %v", args)\n\n response = StopProjectOutput{\n Ok: false,\n }\n\n // try to stop a project using Qovery API\n err = callQoveryApi(args.Input.Id)\n if err != nil {\n return response, err\n }\n\n response.Ok = true\n\n return response, nil\n}\n')),Object(o.b)("p",null,"You can see the whole code in your forked repository on ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/appwrite-functions"}),"Github"),"."),Object(o.b)("h2",{id:"testing-appwrite-cloud-backend"},"Testing AppWrite Cloud Backend"),Object(o.b)("h3",{id:"signup"},"Signup"),Object(o.b)("p",null,"After a few minutes of deployment, the first version of our managed cloud solution should be ready. Let's use the Hasura GraphQL API to create a new user."),Object(o.b)("p",null,"To do so, open your Hasura by clicking the Open button in your Hasura application. Then, run the following mutation in the GraphQL explorer:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'mutation {\n Signup(input: {email: "pjeziorowski@qovery.com", password: "mysecret"}) {\n accessToken\n }\n}\n')),Object(o.b)("p",null,"You'll end up with a response like this:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "data": {\n "Signup": {\n "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLXVzZXItaWQiOiIyIiwieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoiYWRtaW4iLCJ4LWhhc3VyYS1hbGxvd2VkLXJvbGVzIjpbImFkbWluIl19LCJleHAiOjE2Mzc0ODAxNDR9.aNv72YwjWXkKItDPxQOe5bB7LPo8ZCZ0Gqb3mR6_KQI"\n }\n }\n}\n')),Object(o.b)("p",null,"Great! We have just created our first user and received a token to interact with AppWrite Cloud API."),Object(o.b)("h3",{id:"create-project"},"Create Project"),Object(o.b)("p",null,"Now, let's create our first managed AppWrite instance. In headers, include ",Object(o.b)("inlineCode",{parentName:"p"},"Authorization")," header with the ",Object(o.b)("inlineCode",{parentName:"p"},"Bearer token")," received when signing up:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'mutation {\n CreateProject(input: {name: "myproject"}) {\n id\n name\n url\n }\n}\n')),Object(o.b)("p",null,"You should see a response similar to this one:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "data": {\n "CreateProject": {\n "id": 10,\n "name": "myproject",\n "url": ""\n }\n }\n}\n')),Object(o.b)("p",null,"Great! In the response, we have received the URL we can use to access our managed AppWrite instance."),Object(o.b)("p",null,"When we peek into Qovery UI, we see the created project for our managed AppWrite:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-5.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h3",{id:"start--stop-project"},"Start / Stop Project"),Object(o.b)("p",null,"It's the time to start our project. To do so, run the following mutation:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),"mutation {\n StartProject(input: {id: 10}) {\n ok\n }\n}\n")),Object(o.b)("p",null,"We should get this response:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "data": {\n "StartProject": {\n "ok": true\n }\n }\n}\n')),Object(o.b)("p",null,"And looking into Qovery, we'll see our environment is starting:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-6.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"After a few minutes, our AppWrite instance should be available up and running using the URL from the previous response. We can also list our projects to get all projects' URLs:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),"{\n project(where: {user: {id: {_eq: 1}}}) {\n id\n name\n url\n }\n}\n")),Object(o.b)("p",null,"Response:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "data": {\n "project": [\n {\n "id": 9,\n "name": "appwrite1",\n "url": "https://zd3da7904-z24aae066-gtw.oom.sh"\n },\n {\n "id": 10,\n "name": "myproject",\n "url": "https://zf3f05b5a-zab0fb2f8-gtw.oom.sh"\n }\n ]\n }\n}\n')),Object(o.b)("h2",{id:"appwrite-cloud-api-domain"},"AppWrite Cloud API domain"),Object(o.b)("p",null,"Now, as the last step of this part of tutorial, let's set up a custom domain for our AppWrite Cloud."),Object(o.b)("p",null,"To do so, all we need to do is to follow a few simple steps:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Navigate to the Hasura GraphQL API application in Qovery Console"),Object(o.b)("li",{parentName:"ol"},"Click ",Object(o.b)("inlineCode",{parentName:"li"},"Add")," button and select ",Object(o.b)("inlineCode",{parentName:"li"},"Custom Domain"))),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-7.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("ol",{start:3},Object(o.b)("li",{parentName:"ol"},"Type the name of desired domain, click ",Object(o.b)("inlineCode",{parentName:"li"},"Add")," and copy the ",Object(o.b)("inlineCode",{parentName:"li"},"Value")," displayed in the box below")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-8.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("ol",{start:4},Object(o.b)("li",{parentName:"ol"},"Add a ",Object(o.b)("inlineCode",{parentName:"li"},"CNAME")," record with value copied in the previous step in your domain provider DNS management settings")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-9.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("ol",{start:5},Object(o.b)("li",{parentName:"ol"},"Restart ",Object(o.b)("inlineCode",{parentName:"li"},"Hasura")," application")),Object(o.b)("p",null,"Congratulations, your AppWrite Cloud API will be exposed using your custom domain shortly."),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"In this tutorial, we have managed to bootstrap the backend for our AppWrite Cloud solution. Users can register, log in, create and deploy managed AppWrite projects. In the following steps, we will add more functionalities to our AppWrite Cloud offering, set up a nice to use web User Interface and continue adding new features to AppWrite Cloud on top of Qovery."))}p.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),p=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},u=function(e){var t=p(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),u=p(n),d=a,m=u["".concat(i,".").concat(d)]||u[d]||b[d]||o;return n?r.a.createElement(m,l({ref:t},s,{components:n})):r.a.createElement(m,l({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,i[1]=l;for(var s=2;s1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,s=void 0===c?n:r(c,n);s>l;)t[l++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(430),c=n(20),s=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,p=n||c,u=Object(l.a)(p),b=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&t&&t.disconnect()}}),[p,d,u]),p&&u?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(p),b.current=!0)},innerRef:function(e){var n,a;d&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:p})):o.a.createElement("a",Object(a.a)({},e,{href:p}))}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),i=n(420),l=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,s=e.size,p=e.target,u=e.to,b=l()("jump-to","jump-to--"+s,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:u,target:p,className:b},d):r.a.createElement(o.a,{to:u,className:b},d)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see acaf40e9.fd86f35e.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[173],{325:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return c})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),o=(n(0),n(425)),i=(n(424),n(429),n(431),{last_modified_on:"2022-03-09",$schema:"/.meta/.schemas/guides.json",title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2",readingTime:"8 min read",source:"@site/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",truncated:!1,prevItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1"},nextItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3"}},c=[{value:"Architecture",id:"architecture",children:[]},{value:"Hosting AppWrite Cloud",id:"hosting-appwrite-cloud",children:[]},{value:"Deploying AppWrite Cloud on Qovery",id:"deploying-appwrite-cloud-on-qovery",children:[{value:"Postgres",id:"postgres",children:[]},{value:"Hasura",id:"hasura",children:[]},{value:"Functions",id:"functions",children:[]},{value:"Deploy the environment",id:"deploy-the-environment",children:[]}]},{value:"Database Structure",id:"database-structure",children:[]},{value:"AppWrite Cloud API",id:"appwrite-cloud-api",children:[]},{value:"Testing AppWrite Cloud Backend",id:"testing-appwrite-cloud-backend",children:[{value:"Signup",id:"signup",children:[]},{value:"Create Project",id:"create-project",children:[]},{value:"Start / Stop Project",id:"start--stop-project",children:[]}]},{value:"AppWrite Cloud API domain",id:"appwrite-cloud-api-domain",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],s={rightToc:c};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"In the second part of the\xa0",Object(o.b)("em",{parentName:"p"},"Case Study with AppWrite"),", we will create the backend part of our AppWrite Cloud. The backend will communicate with Qovery API to request the infrastructure (",Object(o.b)("inlineCode",{parentName:"p"},"AppWrite")," instances and their dependencies, i.e. ",Object(o.b)("inlineCode",{parentName:"p"},"MariaDB")," and ",Object(o.b)("inlineCode",{parentName:"p"},"Redis"),") for AppWrite Cloud users. Qovery will take care of provisioning, managing, and running AppWrite instances and databases, while AppWrite Cloud will take care of providing a nice UI and other utilities for the users wanting to deploy AppWrite on a cloud-managed solution."),Object(o.b)("h2",{id:"architecture"},"Architecture"),Object(o.b)("p",null,"The backend of AppWrite Cloud will make use of a low-code tool ",Object(o.b)("inlineCode",{parentName:"p"},"Hasura"),". Hasura is an open-source project that allows building backend apps with minimal effort while still providing fast performance. It also allows executing custom business logic using cloud functions. Our Hasura backend will use ",Object(o.b)("inlineCode",{parentName:"p"},"PostgreSQL")," as its data store. In the first stage, the AppWrite Cloud backend will contain information about users and their projects. For all tasks related to running and managing the underlying infrastructure, it will call Qovery API and delegate those tasks to Qovery so that AppWrite Cloud can stay focused on delivering to their users what they really want - an excellent experience AppWrite, instead of wasting time on reinventing the wheel of managing the infrastructure."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-1.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"For all business logic, we will use the ",Object(o.b)("inlineCode",{parentName:"p"},"Async Actions")," feature of Hasura. In this approach, the Hasura backend calls external functions over the network and lets them perform any business logic required. The async functions can be hosted anywhere, as long as they conform to the contract required by Hasura."),Object(o.b)("h2",{id:"hosting-appwrite-cloud"},"Hosting AppWrite Cloud"),Object(o.b)("p",null,"Besides, hosting all the managed AppWrite projects of AppWrite Cloud users, Qovery can also host the whole AppWrite Cloud backend itself. Indeed, in this case study, we'll go through all the steps required to deploy AppWrite Cloud on Qovery."),Object(o.b)("h2",{id:"deploying-appwrite-cloud-on-qovery"},"Deploying AppWrite Cloud on Qovery"),Object(o.b)("p",null,"To deploy the AppWrite Cloud, we need to deploy a Hasura backend, a PostgreSQL database for Hasura, and our Go server for handling the custom business logic."),Object(o.b)("h3",{id:"postgres"},"Postgres"),Object(o.b)("p",null,"First, let's deploy our database. To do so, use Qovery Console to create a new project and environment, then click ",Object(o.b)("inlineCode",{parentName:"p"},"Add Database")," button and choose PostgreSQL ",Object(o.b)("inlineCode",{parentName:"p"},"v12"),"."),Object(o.b)("h3",{id:"hasura"},"Hasura"),Object(o.b)("p",null,"To deploy Hasura, fork this repository\xa0",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/hasura"}),"https://github.com/Qovery/hasura"),". Use ",Object(o.b)("inlineCode",{parentName:"p"},"DOCKER")," build mode and Port ",Object(o.b)("inlineCode",{parentName:"p"},"8080"),". Then, in the Environment Variables section, add the following variables:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_ENABLE_CONSOLE")," - true"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_ADMIN_SECRET")," - your Hasura admin secret (value up to you)"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_JWT_SECRET"))),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "type": "HS256",\n "key": "$KEY"\n}\n')),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"where ",Object(o.b)("inlineCode",{parentName:"li"},"$KEY")," is a minimum 32 character long string"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_DATABASE_URL")," - an alias to your previously created PostgreSQL URL")),Object(o.b)("h3",{id:"functions"},"Functions"),Object(o.b)("p",null,"Now, let's deploy our Go server. To do so, you can fork this repository\xa0",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/appwrite-functions"}),"https://github.com/pjeziorowski/appwrite-functions"),"."),Object(o.b)("p",null,"Create a new app using ",Object(o.b)("inlineCode",{parentName:"p"},"DOCKER")," build mode and Port ",Object(o.b)("inlineCode",{parentName:"p"},"3000"),"."),Object(o.b)("p",null,"Now, we need to set up a few environment variables:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"ORGANIZATION_ID_QOVERY")," - organization ID used as your AppWrite Cloud on Qovery"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"API_TOKEN_QOVERY")," - API token to use to interact with Qovery API"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_API_URL")," - location of your Hasura backend instance"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"SECRET")," - key to sign tokens, use the same value as in ",Object(o.b)("inlineCode",{parentName:"li"},"HASURA_GRAPHQL_JWT_SECRET")," key section"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"HASURA_API_TOKEN")," - admin secret token of your Hasura instance")),Object(o.b)("h3",{id:"deploy-the-environment"},"Deploy the environment"),Object(o.b)("p",null,"After your project is set up as described above, deploy the whole environment, and your AppWrite Cloud backend will be ready to play and test."),Object(o.b)("h2",{id:"database-structure"},"Database Structure"),Object(o.b)("p",null,"All we need to store in the AppWrite Cloud database at the moment is users and their projects. For this, we will create a user table and project table that will contain AppWrite URLs and project names."),Object(o.b)("p",null,"To import the structure of the tables into the Hasura backend, you can use the metadata file located here ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/hasura/blob/main/appwrite-cloud-metadata.json"}),"hasura/appwrite-cloud-metadata.json at main \xb7 Qovery/hasura")),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"user")," table contains sign-in information (email and hashed password):"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-2.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"whereas the ",Object(o.b)("inlineCode",{parentName:"p"},"project")," table contains basic information about the project in AppWrite Cloud, URL to AppWrite instance as well as its mapping to a project in Qovery:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-3.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h2",{id:"appwrite-cloud-api"},"AppWrite Cloud API"),Object(o.b)("p",null,"The initial version of the API will allow to:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Signup")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Signin")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Create/Start/Stop/Delete AppWrite Instances"))),Object(o.b)("p",null,"The API will be exposed using Hasura Actions. Actions delegate the custom logic to handler functions we deployed in our Go server. Hasura will delegate the work of contacting the Qovery API to those functions."),Object(o.b)("p",null,"All the Actions were already imported into Hasura using the same metadata file as we used to import the structure of the tables."),Object(o.b)("p",null,"When you navigate to ",Object(o.b)("inlineCode",{parentName:"p"},"Actions")," section in Hasura, you'll see actions definition similar to this one:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-4.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"The functions serving those actions in our Golang app look more or less like this:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-go"}),'func stopProject(args StopProjectArgs, userId string) (response StopProjectOutput, err error) {\n log.Printf("received stop project request %v", args)\n\n response = StopProjectOutput{\n Ok: false,\n }\n\n // try to stop a project using Qovery API\n err = callQoveryApi(args.Input.Id)\n if err != nil {\n return response, err\n }\n\n response.Ok = true\n\n return response, nil\n}\n')),Object(o.b)("p",null,"You can see the whole code in your forked repository on ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/appwrite-functions"}),"Github"),"."),Object(o.b)("h2",{id:"testing-appwrite-cloud-backend"},"Testing AppWrite Cloud Backend"),Object(o.b)("h3",{id:"signup"},"Signup"),Object(o.b)("p",null,"After a few minutes of deployment, the first version of our managed cloud solution should be ready. Let's use the Hasura GraphQL API to create a new user."),Object(o.b)("p",null,"To do so, open your Hasura by clicking the Open button in your Hasura application. Then, run the following mutation in the GraphQL explorer:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'mutation {\n Signup(input: {email: "pjeziorowski@qovery.com", password: "mysecret"}) {\n accessToken\n }\n}\n')),Object(o.b)("p",null,"You'll end up with a response like this:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "data": {\n "Signup": {\n "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLXVzZXItaWQiOiIyIiwieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoiYWRtaW4iLCJ4LWhhc3VyYS1hbGxvd2VkLXJvbGVzIjpbImFkbWluIl19LCJleHAiOjE2Mzc0ODAxNDR9.aNv72YwjWXkKItDPxQOe5bB7LPo8ZCZ0Gqb3mR6_KQI"\n }\n }\n}\n')),Object(o.b)("p",null,"Great! We have just created our first user and received a token to interact with AppWrite Cloud API."),Object(o.b)("h3",{id:"create-project"},"Create Project"),Object(o.b)("p",null,"Now, let's create our first managed AppWrite instance. In headers, include ",Object(o.b)("inlineCode",{parentName:"p"},"Authorization")," header with the ",Object(o.b)("inlineCode",{parentName:"p"},"Bearer token")," received when signing up:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'mutation {\n CreateProject(input: {name: "myproject"}) {\n id\n name\n url\n }\n}\n')),Object(o.b)("p",null,"You should see a response similar to this one:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "data": {\n "CreateProject": {\n "id": 10,\n "name": "myproject",\n "url": ""\n }\n }\n}\n')),Object(o.b)("p",null,"Great! In the response, we have received the URL we can use to access our managed AppWrite instance."),Object(o.b)("p",null,"When we peek into Qovery UI, we see the created project for our managed AppWrite:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-5.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h3",{id:"start--stop-project"},"Start / Stop Project"),Object(o.b)("p",null,"It's the time to start our project. To do so, run the following mutation:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),"mutation {\n StartProject(input: {id: 10}) {\n ok\n }\n}\n")),Object(o.b)("p",null,"We should get this response:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "data": {\n "StartProject": {\n "ok": true\n }\n }\n}\n')),Object(o.b)("p",null,"And looking into Qovery, we'll see our environment is starting:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-6.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"After a few minutes, our AppWrite instance should be available up and running using the URL from the previous response. We can also list our projects to get all projects' URLs:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),"{\n project(where: {user: {id: {_eq: 1}}}) {\n id\n name\n url\n }\n}\n")),Object(o.b)("p",null,"Response:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-graphql"}),'{\n "data": {\n "project": [\n {\n "id": 9,\n "name": "appwrite1",\n "url": "https://zd3da7904-z24aae066-gtw.oom.sh"\n },\n {\n "id": 10,\n "name": "myproject",\n "url": "https://zf3f05b5a-zab0fb2f8-gtw.oom.sh"\n }\n ]\n }\n}\n')),Object(o.b)("h2",{id:"appwrite-cloud-api-domain"},"AppWrite Cloud API domain"),Object(o.b)("p",null,"Now, as the last step of this part of tutorial, let's set up a custom domain for our AppWrite Cloud."),Object(o.b)("p",null,"To do so, all we need to do is to follow a few simple steps:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Navigate to the Hasura GraphQL API application in Qovery Console"),Object(o.b)("li",{parentName:"ol"},"Click ",Object(o.b)("inlineCode",{parentName:"li"},"Add")," button and select ",Object(o.b)("inlineCode",{parentName:"li"},"Custom Domain"))),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-7.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("ol",{start:3},Object(o.b)("li",{parentName:"ol"},"Type the name of desired domain, click ",Object(o.b)("inlineCode",{parentName:"li"},"Add")," and copy the ",Object(o.b)("inlineCode",{parentName:"li"},"Value")," displayed in the box below")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-8.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("ol",{start:4},Object(o.b)("li",{parentName:"ol"},"Add a ",Object(o.b)("inlineCode",{parentName:"li"},"CNAME")," record with value copied in the previous step in your domain provider DNS management settings")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-2-9.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("ol",{start:5},Object(o.b)("li",{parentName:"ol"},"Restart ",Object(o.b)("inlineCode",{parentName:"li"},"Hasura")," application")),Object(o.b)("p",null,"Congratulations, your AppWrite Cloud API will be exposed using your custom domain shortly."),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"In this tutorial, we have managed to bootstrap the backend for our AppWrite Cloud solution. Users can register, log in, create and deploy managed AppWrite projects. In the following steps, we will add more functionalities to our AppWrite Cloud offering, set up a nice to use web User Interface and continue adding new features to AppWrite Cloud on top of Qovery."))}p.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),p=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},u=function(e){var t=p(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),u=p(n),d=a,m=u["".concat(i,".").concat(d)]||u[d]||b[d]||o;return n?r.a.createElement(m,l({ref:t},s,{components:n})):r.a.createElement(m,l({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,i[1]=l;for(var s=2;s1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,s=void 0===c?n:r(c,n);s>l;)t[l++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(432),c=n(20),s=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,p=n||c,u=Object(l.a)(p),b=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&t&&t.disconnect()}}),[p,d,u]),p&&u?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(p),b.current=!0)},innerRef:function(e){var n,a;d&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(p)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:p})):o.a.createElement("a",Object(a.a)({},e,{href:p}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),i=n(423),l=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,s=e.size,p=e.target,u=e.to,b=l()("jump-to","jump-to--"+s,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return p?r.a.createElement("a",{href:u,target:p,className:b},d):r.a.createElement(o.a,{to:u,className:b},d)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/b479fc9a.f934788d.js.LICENSE.txt b/acaf40e9.fd86f35e.js.LICENSE.txt similarity index 100% rename from b479fc9a.f934788d.js.LICENSE.txt rename to acaf40e9.fd86f35e.js.LICENSE.txt diff --git a/accdb2b4.03c0f294.js b/accdb2b4.dd09ffc6.js similarity index 96% rename from accdb2b4.03c0f294.js rename to accdb2b4.dd09ffc6.js index 6d7f4044cf..05a455a42a 100644 --- a/accdb2b4.03c0f294.js +++ b/accdb2b4.dd09ffc6.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[171],{323:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return c})),r.d(t,"metadata",(function(){return i})),r.d(t,"rightToc",(function(){return l})),r.d(t,"default",(function(){return s}));var n=r(1),a=r(9),o=(r(0),r(422)),c={last_modified_on:"2023-04-04",title:"MySQL",description:"How to set up and use a MySQL database"},i={id:"using-qovery/configuration/database/mysql",title:"MySQL",description:"How to set up and use a MySQL database",source:"@site/docs/using-qovery/configuration/database/mysql.md",permalink:"/docs/using-qovery/configuration/database/mysql",sidebar:"docs",previous:{title:"PostgreSQL",permalink:"/docs/using-qovery/configuration/database/postgresql"},next:{title:"MongoDB",permalink:"/docs/using-qovery/configuration/database/mongodb"}},l=[{value:"Supported Versions and Cloud Providers",id:"supported-versions-and-cloud-providers",children:[]}],p={rightToc:l};function s(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},p,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"MySQL is the world's most popular open source database. Whether you are a fast growing web property, technology ISV or large enterprise, MySQL can cost-effectively help you deliver high performance, scalable database applications."),Object(o.b)("h2",{id:"supported-versions-and-cloud-providers"},"Supported Versions and Cloud Providers"),Object(o.b)("p",null,"You can find the supported versions directly within the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),"."),Object(o.b)("p",null,"Availability of the Container version or Cloud Provider Managed versions depends on the chosen Cloud Provider "),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Cloud provider"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Container supported"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Managed supported"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"AWS"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Yes"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Yes (RDS)")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Scaleway"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Yes"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"No")))),Object(o.b)("p",null,"Have a look at the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/"}),"Database page")," to know more about the database creation and setup."))}s.isMDXComponent=!0},422:function(e,t,r){"use strict";r.d(t,"a",(function(){return u})),r.d(t,"b",(function(){return f}));var n=r(0),a=r.n(n);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function c(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=a.a.createContext({}),s=function(e){var t=a.a.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},u=function(e){var t=s(e.components);return a.a.createElement(p.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(r),d=n,f=u["".concat(c,".").concat(d)]||u[d]||b[d]||o;return r?a.a.createElement(f,i({ref:t},p,{components:r})):a.a.createElement(f,i({ref:t},p))}));function f(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,c=new Array(o);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var p=2;p=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=a.a.createContext({}),s=function(e){var t=a.a.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},u=function(e){var t=s(e.components);return a.a.createElement(p.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(r),d=n,f=u["".concat(c,".").concat(d)]||u[d]||b[d]||o;return r?a.a.createElement(f,i({ref:t},p,{components:r})):a.a.createElement(f,i({ref:t},p))}));function f(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,c=new Array(o);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var p=2;p=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var o=r.a.createContext({}),s=function(e){var t=r.a.useContext(o),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},u=function(e){var t=s(e.components);return r.a.createElement(o.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},p=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,c=e.parentName,o=b(e,["components","mdxType","originalType","parentName"]),u=s(n),p=a,O=u["".concat(c,".").concat(p)]||u[p]||m[p]||l;return n?r.a.createElement(O,i({ref:t},o,{components:n})):r.a.createElement(O,i({ref:t},o))}));function O(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,c=new Array(l);c[0]=p;var i={};for(var b in t)hasOwnProperty.call(t,b)&&(i[b]=t[b]);i.originalType=e,i.mdxType="string"==typeof e?e:a,c[1]=i;for(var o=2;o1?arguments[1]:void 0,n),b=c>2?arguments[2]:void 0,o=void 0===b?n:r(b,n);o>i;)t[i++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,l=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(l)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),l=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(l.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),l=n.n(r),c=n(39),i=n(430),b=n(20),o=n.n(b);t.a=function(e){var t,n=e.to,b=e.href,s=n||b,u=Object(i.a)(s),m=Object(r.useRef)(!1),p=o.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&u&&window.docusaurus.prefetch(s),function(){p&&t&&t.disconnect()}}),[s,p,u]),s&&u?l.a.createElement(c.b,Object(a.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(s),m.current=!0)},innerRef:function(e){var n,a;p&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:s})):l.a.createElement("a",Object(a.a)({},e,{href:s}))}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),l=n(427),c=n(420),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,c=e.leftIcon,b=e.rightIcon,o=e.size,s=e.target,u=e.to,m=i()("jump-to","jump-to--"+o,n),p=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(b||"chevron-right")+" arrow"}))));return s?r.a.createElement("a",{href:u,target:s,className:m},p):r.a.createElement(l.a,{to:u,className:m},p)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see b2880863.d480f702.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[177],{328:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return o})),n.d(t,"default",(function(){return u}));var a=n(1),r=n(9),l=(n(0),n(425)),c=n(424),i=(n(431),n(429),{last_modified_on:"2023-11-24",title:"Members and RBAC",description:"Learn how to manage the RBAC via Qovery"}),b={id:"using-qovery/configuration/organization/members-rbac",title:"Members and RBAC",description:"Learn how to manage the RBAC via Qovery",source:"@site/docs/using-qovery/configuration/organization/members-rbac.md",permalink:"/docs/using-qovery/configuration/organization/members-rbac",sidebar:"docs",previous:{title:"Organization",permalink:"/docs/using-qovery/configuration/organization"},next:{title:"Git Repository access",permalink:"/docs/using-qovery/configuration/organization/git-repository-access"}},o=[{value:"Organization members",id:"organization-members",children:[]},{value:"Roles-Based access control (RBAC)",id:"roles-based-access-control-rbac",children:[{value:"Custom roles",id:"custom-roles",children:[]}]},{value:"Cluster Level Permissions",id:"cluster-level-permissions",children:[{value:"Examples",id:"examples",children:[]},{value:"Example 2, advanced setup",id:"example-2-advanced-setup",children:[]}]}],s={rightToc:o};function u(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(l.b)("wrapper",Object(a.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(l.b)("p",null,"You can manage from the organization settings the members capable to access your organization and as well their permission via an RBAC system."),Object(l.b)("p",null,"You can access the organization settings using the ",Object(l.b)("inlineCode",{parentName:"p"},"Wheel")," button on the left nav bar"),Object(l.b)("p",{align:"center"},Object(l.b)("img",{src:"/img/configuration/organization/access_settings.png",alt:"How to access your organization settings"})),Object(l.b)("h2",{id:"organization-members"},"Organization members"),Object(l.b)("p",null,"This section allows you to manage the members of your organization (add / remove) and as well assign a role to each of them."),Object(l.b)("p",null,"You can invite someone to join your organization by email. Then he will get access to your projects and will be able to contribute."),Object(l.b)("p",{align:"center"},Object(l.b)("img",{src:"/img/configuration/organization/members.png",alt:"Qovery - List all members within an organization"})),Object(l.b)(c.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,"Changing the role of a member requires the user to logout/login to make the changes effective or wait a few minutes (max 1 hour)")),Object(l.b)("h2",{id:"roles-based-access-control-rbac"},"Roles-Based access control (RBAC)"),Object(l.b)("p",null,"Qovery allows you to control the access to your cluster and environment resources by defining and assigning roles to your users."),Object(l.b)("p",null,"By default, five roles are created within your organization (Basic Roles):"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"Owner: the user has full access on the organization"),Object(l.b)("li",{parentName:"ul"},"Admin: same as the owner, the has full access to the organization but he cannot delete it"),Object(l.b)("li",{parentName:"ul"},"DevOps: the user can manage the organization infrastructure (clusters/registry/webhook setup) and manage the deployments of any environment within the organization."),Object(l.b)("li",{parentName:"ul"},"Billing Manager: the user can only manage the billing of the organization"),Object(l.b)("li",{parentName:"ul"},"Viewer: the user has read-only access to any section of the organization")),Object(l.b)("p",null,"More in detail, you can find the associated permissions below:"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Action"),Object(l.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Owner"),Object(l.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Admin"),Object(l.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"DevOps"),Object(l.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Billing Manager"),Object(l.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Viewer"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Read organization"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Edit organization"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Delete organization"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Manage billing"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Manage members & roles"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Manage cluster & container registry"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Manage organization setup (webhooks, Git and API tokens etc..)"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Read ANY project"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Edit/Delete ANY project"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Create project"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Read ANY environment"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Edit/Delete ANY environment or service"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Create environment or service"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Add/Edit/Delete environment variables and secrets"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Deploy/Stop ANY environment or service"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Connect via shell to ANY application"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"yes"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"no")))),Object(l.b)(c.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,"Only one user can be Owner of an organization. You can transfer the ownership to another member via the menu available on the target member")),Object(l.b)("h3",{id:"custom-roles"},"Custom roles"),Object(l.b)("p",null,"If the basic roles are not enough given your internal organization, Qovery allows you to customize the accesses to your clusters, projets and environments by defining ",Object(l.b)("inlineCode",{parentName:"p"},"Custom Roles"),"."),Object(l.b)("p",null,"A ",Object(l.b)("inlineCode",{parentName:"p"},"Custom role")," allows you to customize:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"Cluster Level Permissions: you can specify the access to the existing computing resources (manage cluster X, create environments on cluster Y, read-only access on cluster K)"),Object(l.b)("li",{parentName:"ul"},"Project Level Permissions: you can specify the access to the projects and their environments by environment type (deploy type X, create type K etc..)")),Object(l.b)(c.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,"Users with a custom role cannot create clusters or manage any of the organization settings (members, webhook, API token etc..)")),Object(l.b)("p",null,'To create a custom role, go in the Roles & Permissions section press "Add new Role"'),Object(l.b)("p",null,"For the new role, you will be able to specify:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"The name of the role"),Object(l.b)("li",{parentName:"ul"},"A description"),Object(l.b)("li",{parentName:"ul"},"Cluster Level permissions"),Object(l.b)("li",{parentName:"ul"},"Project Level Permissions")),Object(l.b)("h2",{id:"cluster-level-permissions"},"Cluster Level Permissions"),Object(l.b)("p",null,"This section allows you to fine tune the access to the computing resources. For each cluster of your organization, you will be able to specify an access permission (ordered by permission level):"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Name"),Object(l.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Permission Type"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Read-Only"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"The user can access the cluster information (name, region etc..). Minimum permission level.")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Create Environment"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),'The user can create environments on this cluster. Only users with this role could allocate resources for their environments on this cluster. Further environment level permissions (like deployment rights) are managed via the "Project Permissions", see below')),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Full Access"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"The user can create create environments on this cluster and as well manage the cluster's settings (start/stop, change number and type of nodes etc..). This permission allows a group of users to manage by themselves a specific cluster")))),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},'Project Level Permissions\nThis section allows you to fine tune the access to the projects and their environments. The environment access is managed by "Environment Type" to simplify the configuration (Production, Staging, Development, Preview). For each project of your organization and by environment type, you will be able to specify an access permission (ordered by permission level):')),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Name"),Object(l.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Permission Type"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"No Access"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),'The user has no access to this environment type. If the user has "No Access" on all the environment types, he will not have access to the project')),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Read-Only"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Access in read-only to this environment type. Useful to restrict access on sensitive environments")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Deploy"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Manage the deployments of this environment type, access the logs, connect via SSH to the application and manage its environment variables")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Manage"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Manage the deployments and the settings of this environment type (including adding or removing services)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Full Access"),Object(l.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"The user is admin of the project and can do everything he wants on it (no matter the environment type)")))),Object(l.b)("p",{align:"center"},Object(l.b)("img",{src:"/img/configuration/organization/custom_role_creation.png",alt:"Qovery - custom role"})),Object(l.b)("p",null,'Once the role is created, you can assign it to a member of your organization within the "Members" section. You can also update the permissions by editing the role from the Roles&Permissions screen'),Object(l.b)("h3",{id:"examples"},"Examples"),Object(l.b)("p",null,"Within this section, we will try to provide you some example of roles & permission setup"),Object(l.b)("h4",{id:"example-1-simple-setup"},"Example 1, simple setup"),Object(l.b)("p",null,'An organization has 3 clusters ("prod cluster", \u201cstaging cluster\u201d, \u201cdev cluster\u201d) and 1 project P1. The organization has a CTO, a devops and some developers.\nThe roles & permissions could be configured in this way:'),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"CTO = Owner"),Object(l.b)("li",{parentName:"ul"},"Devops = Devops or Admin"),Object(l.b)("li",{parentName:"ul"},"Developers: we want these users capable of accessing the project, having read access to the prod clusters/env, managing deployments on the staging cluster (but not creating new environments on it) and doing whatever they want for the development environments on the dev cluster. So the configuration will look like:",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Create a new Role \u201cdeveloper\u201d with the following permissions:",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Cluster Level Permissions:",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Prod cluster \u2192 Read-Only"),Object(l.b)("li",{parentName:"ul"},"Staging cluster \u2192 Read-Only"),Object(l.b)("li",{parentName:"ul"},"Dev cluster \u2192 Create Environment (they can create environments on this cluster)"))),Object(l.b)("li",{parentName:"ul"},'Project Level Permissions for the project "P1":',Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Environment access (by env type)",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"prod = Read-Only"),Object(l.b)("li",{parentName:"ul"},"staging = deploye (i.e. they can deploy env of type \u201cstaging\u201d)"),Object(l.b)("li",{parentName:"ul"},"development = Full Access (i.e. they can manage and create env of type \u201cdev\u201d)")))))))))),Object(l.b)("h3",{id:"example-2-advanced-setup"},"Example 2, advanced setup"),Object(l.b)("p",null,'An organization with 4 dev clusters (\u201cprod cluster\u201d, \u201cstaging clyster\u201d, 2 Dev clusters called \u201cdev cluster team 1\u201d and "dev cluster team 2\u201d) and 2 projects P1 and P2. The organization has a CTO, a devops, 2 dev teams with an \u201cacting dev-ops\u201d in it who manages the dev cluster on behalf of the devops.\nThe roles & permissions could be configured in this way:'),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"CTO = Owner"),Object(l.b)("li",{parentName:"ul"},"Devops = Devops or Admin"),Object(l.b)("li",{parentName:"ul"},'Dev team 1: we want these users capable of accessing the project P1, having no access to the prod env and managing their deployments only on the "dev cluster Dev team 1" for their development environments.So the config will look like:',Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Create a new Role \u201cDev Team 1\u201d",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Cluster Level Permissions:",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Prod cluster \u2192 Read-Only"),Object(l.b)("li",{parentName:"ul"},"Staging cluster \u2192 Read-Only"),Object(l.b)("li",{parentName:"ul"},"Dev cluster team 1 \u2192 Create Environment (they can create envs only on their dev cluster)"),Object(l.b)("li",{parentName:"ul"},"Dev cluster team 2 \u2192 Read-Only"))),Object(l.b)("li",{parentName:"ul"},"Project Level Permissions:",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Config on the project \u201cP1\u201d",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Environment access (by env type)",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"prod = no-access"),Object(l.b)("li",{parentName:"ul"},"staging = deploy"),Object(l.b)("li",{parentName:"ul"},"dev = Full Access (i.e. they can do whatever they want on env of type \u201cdev\u201d)"))))),Object(l.b)("li",{parentName:"ul"},"Config on the project \u201cP2\u201d (i.e. they can't access P2)",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Environment access (by env type)",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"prod = no-access"),Object(l.b)("li",{parentName:"ul"},"staging = no-access"),Object(l.b)("li",{parentName:"ul"},"dev = no-access"))))))))))),Object(l.b)("li",{parentName:"ul"},'Dev team 2: we want these users capable of accessing the project P2, having no access to the prod env and managing their deployments only on the "dev cluster team 2" for their development environments. So the config will look like:',Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Create a new Role \u201cDev Team 2\u201d",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Cluster Level Permissions:",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Prod cluster \u2192 Read-Only"),Object(l.b)("li",{parentName:"ul"},"Staging cluster \u2192 Read-Only"),Object(l.b)("li",{parentName:"ul"},"Dev cluster team 1 \u2192 Read-Only"),Object(l.b)("li",{parentName:"ul"},"Dev cluster team 2 \u2192 Create Environment (they can create envs only on their dev cluster)"))),Object(l.b)("li",{parentName:"ul"},"Project Level Permissions:",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Config on the project \u201cP1\u201d (i.e. they can't access P1)",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Environment access (by env type)",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"prod = no-access"),Object(l.b)("li",{parentName:"ul"},"staging = no-access"),Object(l.b)("li",{parentName:"ul"},"dev = no-access"))))),Object(l.b)("li",{parentName:"ul"},"Config on the project \u201cP2\u201d",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Environment access (by env type)",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"prod = no-access"),Object(l.b)("li",{parentName:"ul"},"staging = deploy"),Object(l.b)("li",{parentName:"ul"},"dev = Full Access (i.e. they can do whatever they want on env of type \u201cdev\u201d)"))))))))))),Object(l.b)("li",{parentName:"ul"},"Acting DevOps user: we want this user capable of accessing the project, having read access to the prod env, managing the dev clusters and all the environments on it. So the config will look like this:",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Create a new Group \u201cActing DevOps\u201d",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Cluster Level Permissions:",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Prod cluster \u2192 Read-Only"),Object(l.b)("li",{parentName:"ul"},"Staging cluster \u2192 Create Environment"),Object(l.b)("li",{parentName:"ul"},"Dev1 cluster \u2192 Full Access"),Object(l.b)("li",{parentName:"ul"},"Dev2 cluster \u2192 Full Access"))),Object(l.b)("li",{parentName:"ul"},"Project permissions settings",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Config on the project \u201cP1\u201d",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Admin (i.e.: full access to the project)"))),Object(l.b)("li",{parentName:"ul"},"Config on the project \u201cP2\u201d",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"Admin (i.e.: full access to the project)")))))))))))}u.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var o=r.a.createContext({}),s=function(e){var t=r.a.useContext(o),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},u=function(e){var t=s(e.components);return r.a.createElement(o.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},p=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,c=e.parentName,o=b(e,["components","mdxType","originalType","parentName"]),u=s(n),p=a,O=u["".concat(c,".").concat(p)]||u[p]||m[p]||l;return n?r.a.createElement(O,i({ref:t},o,{components:n})):r.a.createElement(O,i({ref:t},o))}));function O(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,c=new Array(l);c[0]=p;var i={};for(var b in t)hasOwnProperty.call(t,b)&&(i[b]=t[b]);i.originalType=e,i.mdxType="string"==typeof e?e:a,c[1]=i;for(var o=2;o1?arguments[1]:void 0,n),b=c>2?arguments[2]:void 0,o=void 0===b?n:r(b,n);o>i;)t[i++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,l=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(l)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),l=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(l.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),l=n.n(r),c=n(39),i=n(432),b=n(20),o=n.n(b);t.a=function(e){var t,n=e.to,b=e.href,s=n||b,u=Object(i.a)(s),m=Object(r.useRef)(!1),p=o.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&u&&window.docusaurus.prefetch(s),function(){p&&t&&t.disconnect()}}),[s,p,u]),s&&u?l.a.createElement(c.b,Object(a.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(s),m.current=!0)},innerRef:function(e){var n,a;p&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:s})):l.a.createElement("a",Object(a.a)({},e,{href:s}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),l=n(430),c=n(423),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,c=e.leftIcon,b=e.rightIcon,o=e.size,s=e.target,u=e.to,m=i()("jump-to","jump-to--"+o,n),p=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(b||"chevron-right")+" arrow"}))));return s?r.a.createElement("a",{href:u,target:s,className:m},p):r.a.createElement(l.a,{to:u,className:m},p)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/b4dda200.cfc0de7b.js.LICENSE.txt b/b2880863.d480f702.js.LICENSE.txt similarity index 100% rename from b4dda200.cfc0de7b.js.LICENSE.txt rename to b2880863.d480f702.js.LICENSE.txt diff --git a/b5eab6bb.f6b65c65.js b/b479fc9a.c07c748d.js similarity index 78% rename from b5eab6bb.f6b65c65.js rename to b479fc9a.c07c748d.js index 85621f0da6..6cbd9c78fe 100644 --- a/b5eab6bb.f6b65c65.js +++ b/b479fc9a.c07c748d.js @@ -1,2 +1,2 @@ -/*! For license information please see b5eab6bb.f6b65c65.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[178],{329:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return b}));var a=n(1),r=n(9),o=(n(0),n(422)),i=n(431),c=(n(421),n(426)),l=(n(429),{last_modified_on:"2022-09-23",$schema:"/.meta/.schemas/guides.json",title:"Kubernetes observability and monitoring with Datadog",description:"How to integrate Datadog with Kubernetes on Qovery.",author_github:"https://github.com/l0ck3",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Kubernetes observability and monitoring with Datadog",description:"How to integrate Datadog with Kubernetes on Qovery.",permalink:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog",readingTime:"4 min read",source:"@site/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Kubernetes observability and monitoring with Datadog",truncated:!1,prevItem:{title:"Integrate your application logs to Cloudwatch",permalink:"/guides/tutorial/cloudwatch-integration"},nextItem:{title:"Managing Environment Variables in React (create-react-app)",permalink:"/guides/tutorial/managing-env-variables-in-create-react-app"}},u=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],d={rightToc:u};function b(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"While Qovery will soon provide basic metrics on apps resources usage, you might need a more advanced view on what happens on your infrastructure. There are many solutions on the market, one of them being Datadog.\nDatadog is one of the leading platforms for monitoring and observability, and it's pretty easy to integrate it with Qovery."),Object(o.b)(c.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Qovery cluster running"),Object(o.b)("li",{parentName:"ul"},"You have access to your Kubernetes cluster through kubectl: ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"see how here")),Object(o.b)("li",{parentName:"ul"},"Helm v3 is installed on your machine: ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://helm.sh/docs/intro/install/"}),"https://helm.sh/docs/intro/install/")))),Object(o.b)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"In this tutorial, we will install the Datadog agent on a Qovery cluster to gather metrics about infrastructure and applications."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-datadog-account"},"Create a Datadog Account"),Object(o.b)("p",null," The first step is to create an account on Datadog: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.datadoghq.com"}),"https://www.datadoghq.com"),"."),Object(o.b)("p",null," You will be prompted to enter some information. An important decision you have to make is which site to use. It will determine where your data get stored."),Object(o.b)("p",null," Warning: You can't migrate your data between regions, so chose carefully. More information here: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.datadoghq.com/fr/getting_started/site/"}),"https://docs.datadoghq.com/fr/getting_started/site/")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/0.png",alt:"Datadog - Console"})),Object(o.b)("p",null,"After signup, you will be redirected to a wizard. Fill-in the information until you get to step 3.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"prepare-the-agent-helm-chart-values"},"Prepare the agent Helm chart values"),Object(o.b)("p",null,"When you get to step 3, ",Object(o.b)("inlineCode",{parentName:"p"},"Agent Setup"),", select ",Object(o.b)("inlineCode",{parentName:"p"},"Kubernetes")," in the list."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/1.png",alt:"Datadog - Console"})),Object(o.b)("p",null,"This screen shows you all the information you need to install the agent."),Object(o.b)("p",null,"Create a ",Object(o.b)("inlineCode",{parentName:"p"},"datadog-values.yaml")," file with the following content:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'datadog:\n clusterName: qovery-dx-cluster\n\n # datadog.site -- The site of the Datadog intake to send Agent data to\n ## Set to \'datadoghq.eu\' to send data to the EU site.\n site: datadoghq.eu\n\n # Export custom Kubernetes labels as tags\n podLabelsAsTags:\n "qovery.com/*": "%%label%%"\n\n logs:\n enabled: true\n containerCollectAll: true\n\n # Set to false if you are not using APM.\n apm:\n enabled: true\n \n containerExcludeLogs: "kube_namespace:kube-system kube_namespace:qovery kube_namespace:cert-manager kube_namespace:nginx-ingress kube_namespace:logging kube_namespace:prometheus"\n\n# You can remove this part if you are not using APM.\n# Note that it it will be enabled for all your applications.\nclusterAgent:\n admissionController:\n enabled: true\n mutateUnlabelled: true\n')),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Replace ",Object(o.b)("inlineCode",{parentName:"li"},"")," with a meaningful name to identify your cluster."),Object(o.b)("li",{parentName:"ul"},"Set the ",Object(o.b)("inlineCode",{parentName:"li"},"site")," value corresponding to the one you selected upon account creation (you can find the information under ",Object(o.b)("inlineCode",{parentName:"li"},"1 > With Helm V3 > --set datadog.site="),")")),Object(o.b)("p",null,"There are many other values you can set. For advanced usage, check: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Datadog/helm-charts/blob/main/charts/datadog/values.yaml"}),"https://github.com/Datadog/helm-charts/blob/main/charts/datadog/values.yaml"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"install-datadog-agent-in-your-cluster"},"Install Datadog agent in your cluster"),Object(o.b)("p",null,"The Datadog agent is a program that will collect data from your cluster and forward it to Datadog.\nWe'll install it uning ",Object(o.b)("inlineCode",{parentName:"p"},"Helm"),"."),Object(o.b)("p",null,"First add the ",Object(o.b)("inlineCode",{parentName:"p"},"datadog")," Helm repository and update your local list:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add datadog https://helm.datadoghq.com\nhelm repo update\n")),Object(o.b)("p",null,"Then we will install the agent in the ",Object(o.b)("inlineCode",{parentName:"p"},"datadog")," namespace:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"helm install datadog-agent \\ \n -n datadog --create-namespace \\\n -f \\\n --set datadog.apiKey='' \\\n datadog/datadog\n")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Edit the path to the ",Object(o.b)("inlineCode",{parentName:"li"},"datadog-values.yaml")," file you created"),Object(o.b)("li",{parentName:"ul"},"Replace ",Object(o.b)("inlineCode",{parentName:"li"},"")," with your actual API KEY. You can find it under ",Object(o.b)("inlineCode",{parentName:"li"},"1 > With Helm V3 > --set datadog.apiKey=")))),Object(o.b)("li",null,Object(o.b)("h4",{id:"check-the-agent-is-running-properly"},"Check the agent is running properly"),Object(o.b)("p",null,"Wait for a minute then run the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get pods -n datadog\n")),Object(o.b)("p",null,"If the installation was successful, you should see an output similar to this one: "),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"NAME READY STATUS RESTARTS AGE\ndatadog-agent-2xhsv 3/3 Running 0 1m\ndatadog-agent-cluster-agent-7f8bddd44-pwjnl 1/1 Running 0 1m\ndatadog-agent-kube-state-metrics-577fcf6778-kc2gk 1/1 Running 0 1m\ndatadog-agent-qfsl2 3/3 Running 0 1m\ndatadog-agent-s5r5r 3/3 Running 0 1m\n"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"finish-setup"},"Finish Setup"),Object(o.b)("p",null,"Once Datadog receives your data, you should be able to click ",Object(o.b)("inlineCode",{parentName:"p"},"Next")," on the wizard. You might need to refresh the page in some cases. It can take a couple minutes before your data is ready."),Object(o.b)("p",null,"You will then arrive on ",Object(o.b)("inlineCode",{parentName:"p"},"Step 4")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/2.png",alt:"Datadog - Console"})),Object(o.b)("p",null,"You can skip this part if you're not interested in monitoring your cloud account."),Object(o.b)("p",null,"Finally, restart your applications if you are using APM.")))),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"You now have Datadog agent running on your Qovery cluster. You can check their ",Object(o.b)("inlineCode",{parentName:"p"},"Getting Started")," guide to familiarize yourself with the product: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.datadoghq.com/fr/getting_started"}),"https://docs.datadoghq.com/fr/getting_started"),"."))}b.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},d=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},p=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=u(n),p=a,m=d["".concat(i,".").concat(p)]||d[p]||b[p]||o;return n?r.a.createElement(m,c({ref:t},s,{components:n})):r.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=p;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(430),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,d=Object(c.a)(u),b=Object(r.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&d&&window.docusaurus.prefetch(u),function(){p&&t&&t.disconnect()}}),[u,p,d]),u&&d?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,a;p&&e&&d&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},428:function(e,t,n){"use strict";var a=n(432),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(n(a,e,i.length))})),i.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,d=e.to,b=c()("jump-to","jump-to--"+s,n),p=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:d,target:u,className:b},p):r.a.createElement(o.a,{to:d,className:b},p)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(a.useState)(null),d=u[0],b=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!d&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==d&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see b479fc9a.c07c748d.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[178],{329:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return b}));var a=n(1),r=n(9),o=(n(0),n(425)),i=n(434),c=(n(424),n(429)),l=(n(431),{last_modified_on:"2022-09-23",$schema:"/.meta/.schemas/guides.json",title:"Kubernetes observability and monitoring with Datadog",description:"How to integrate Datadog with Kubernetes on Qovery.",author_github:"https://github.com/l0ck3",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Kubernetes observability and monitoring with Datadog",description:"How to integrate Datadog with Kubernetes on Qovery.",permalink:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog",readingTime:"4 min read",source:"@site/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Kubernetes observability and monitoring with Datadog",truncated:!1,prevItem:{title:"Integrate your application logs to Cloudwatch",permalink:"/guides/tutorial/cloudwatch-integration"},nextItem:{title:"Managing Environment Variables in React (create-react-app)",permalink:"/guides/tutorial/managing-env-variables-in-create-react-app"}},u=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],d={rightToc:u};function b(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"While Qovery will soon provide basic metrics on apps resources usage, you might need a more advanced view on what happens on your infrastructure. There are many solutions on the market, one of them being Datadog.\nDatadog is one of the leading platforms for monitoring and observability, and it's pretty easy to integrate it with Qovery."),Object(o.b)(c.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Qovery cluster running"),Object(o.b)("li",{parentName:"ul"},"You have access to your Kubernetes cluster through kubectl: ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"see how here")),Object(o.b)("li",{parentName:"ul"},"Helm v3 is installed on your machine: ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://helm.sh/docs/intro/install/"}),"https://helm.sh/docs/intro/install/")))),Object(o.b)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"In this tutorial, we will install the Datadog agent on a Qovery cluster to gather metrics about infrastructure and applications."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-datadog-account"},"Create a Datadog Account"),Object(o.b)("p",null," The first step is to create an account on Datadog: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.datadoghq.com"}),"https://www.datadoghq.com"),"."),Object(o.b)("p",null," You will be prompted to enter some information. An important decision you have to make is which site to use. It will determine where your data get stored."),Object(o.b)("p",null," Warning: You can't migrate your data between regions, so chose carefully. More information here: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.datadoghq.com/fr/getting_started/site/"}),"https://docs.datadoghq.com/fr/getting_started/site/")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/0.png",alt:"Datadog - Console"})),Object(o.b)("p",null,"After signup, you will be redirected to a wizard. Fill-in the information until you get to step 3.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"prepare-the-agent-helm-chart-values"},"Prepare the agent Helm chart values"),Object(o.b)("p",null,"When you get to step 3, ",Object(o.b)("inlineCode",{parentName:"p"},"Agent Setup"),", select ",Object(o.b)("inlineCode",{parentName:"p"},"Kubernetes")," in the list."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/1.png",alt:"Datadog - Console"})),Object(o.b)("p",null,"This screen shows you all the information you need to install the agent."),Object(o.b)("p",null,"Create a ",Object(o.b)("inlineCode",{parentName:"p"},"datadog-values.yaml")," file with the following content:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'datadog:\n clusterName: qovery-dx-cluster\n\n # datadog.site -- The site of the Datadog intake to send Agent data to\n ## Set to \'datadoghq.eu\' to send data to the EU site.\n site: datadoghq.eu\n\n # Export custom Kubernetes labels as tags\n podLabelsAsTags:\n "qovery.com/*": "%%label%%"\n\n logs:\n enabled: true\n containerCollectAll: true\n\n # Set to false if you are not using APM.\n apm:\n enabled: true\n \n containerExcludeLogs: "kube_namespace:kube-system kube_namespace:qovery kube_namespace:cert-manager kube_namespace:nginx-ingress kube_namespace:logging kube_namespace:prometheus"\n\n# You can remove this part if you are not using APM.\n# Note that it it will be enabled for all your applications.\nclusterAgent:\n admissionController:\n enabled: true\n mutateUnlabelled: true\n')),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Replace ",Object(o.b)("inlineCode",{parentName:"li"},"")," with a meaningful name to identify your cluster."),Object(o.b)("li",{parentName:"ul"},"Set the ",Object(o.b)("inlineCode",{parentName:"li"},"site")," value corresponding to the one you selected upon account creation (you can find the information under ",Object(o.b)("inlineCode",{parentName:"li"},"1 > With Helm V3 > --set datadog.site="),")")),Object(o.b)("p",null,"There are many other values you can set. For advanced usage, check: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Datadog/helm-charts/blob/main/charts/datadog/values.yaml"}),"https://github.com/Datadog/helm-charts/blob/main/charts/datadog/values.yaml"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"install-datadog-agent-in-your-cluster"},"Install Datadog agent in your cluster"),Object(o.b)("p",null,"The Datadog agent is a program that will collect data from your cluster and forward it to Datadog.\nWe'll install it uning ",Object(o.b)("inlineCode",{parentName:"p"},"Helm"),"."),Object(o.b)("p",null,"First add the ",Object(o.b)("inlineCode",{parentName:"p"},"datadog")," Helm repository and update your local list:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add datadog https://helm.datadoghq.com\nhelm repo update\n")),Object(o.b)("p",null,"Then we will install the agent in the ",Object(o.b)("inlineCode",{parentName:"p"},"datadog")," namespace:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"helm install datadog-agent \\ \n -n datadog --create-namespace \\\n -f \\\n --set datadog.apiKey='' \\\n datadog/datadog\n")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Edit the path to the ",Object(o.b)("inlineCode",{parentName:"li"},"datadog-values.yaml")," file you created"),Object(o.b)("li",{parentName:"ul"},"Replace ",Object(o.b)("inlineCode",{parentName:"li"},"")," with your actual API KEY. You can find it under ",Object(o.b)("inlineCode",{parentName:"li"},"1 > With Helm V3 > --set datadog.apiKey=")))),Object(o.b)("li",null,Object(o.b)("h4",{id:"check-the-agent-is-running-properly"},"Check the agent is running properly"),Object(o.b)("p",null,"Wait for a minute then run the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get pods -n datadog\n")),Object(o.b)("p",null,"If the installation was successful, you should see an output similar to this one: "),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"NAME READY STATUS RESTARTS AGE\ndatadog-agent-2xhsv 3/3 Running 0 1m\ndatadog-agent-cluster-agent-7f8bddd44-pwjnl 1/1 Running 0 1m\ndatadog-agent-kube-state-metrics-577fcf6778-kc2gk 1/1 Running 0 1m\ndatadog-agent-qfsl2 3/3 Running 0 1m\ndatadog-agent-s5r5r 3/3 Running 0 1m\n"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"finish-setup"},"Finish Setup"),Object(o.b)("p",null,"Once Datadog receives your data, you should be able to click ",Object(o.b)("inlineCode",{parentName:"p"},"Next")," on the wizard. You might need to refresh the page in some cases. It can take a couple minutes before your data is ready."),Object(o.b)("p",null,"You will then arrive on ",Object(o.b)("inlineCode",{parentName:"p"},"Step 4")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/2.png",alt:"Datadog - Console"})),Object(o.b)("p",null,"You can skip this part if you're not interested in monitoring your cloud account."),Object(o.b)("p",null,"Finally, restart your applications if you are using APM.")))),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"You now have Datadog agent running on your Qovery cluster. You can check their ",Object(o.b)("inlineCode",{parentName:"p"},"Getting Started")," guide to familiarize yourself with the product: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.datadoghq.com/fr/getting_started"}),"https://docs.datadoghq.com/fr/getting_started"),"."))}b.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},d=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},p=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=u(n),p=a,m=d["".concat(i,".").concat(p)]||d[p]||b[p]||o;return n?r.a.createElement(m,c({ref:t},s,{components:n})):r.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=p;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(432),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,d=Object(c.a)(u),b=Object(r.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&d&&window.docusaurus.prefetch(u),function(){p&&t&&t.disconnect()}}),[u,p,d]),u&&d?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,a;p&&e&&d&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,d=e.to,b=c()("jump-to","jump-to--"+s,n),p=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:d,target:u,className:b},p):r.a.createElement(o.a,{to:d,className:b},p)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},433:function(e,t,n){"use strict";var a=n(435),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(n(a,e,i.length))})),i.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(a.useState)(null),d=u[0],b=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!d&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==d&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/b5eab6bb.f6b65c65.js.LICENSE.txt b/b479fc9a.c07c748d.js.LICENSE.txt similarity index 100% rename from b5eab6bb.f6b65c65.js.LICENSE.txt rename to b479fc9a.c07c748d.js.LICENSE.txt diff --git a/b4dda200.cfc0de7b.js b/b4dda200.9bd97e60.js similarity index 87% rename from b4dda200.cfc0de7b.js rename to b4dda200.9bd97e60.js index 64fc83ed1a..a318788c8f 100644 --- a/b4dda200.cfc0de7b.js +++ b/b4dda200.9bd97e60.js @@ -1,2 +1,2 @@ -/*! For license information please see b4dda200.cfc0de7b.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[176],{327:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return s})),r.d(t,"metadata",(function(){return u})),r.d(t,"rightToc",(function(){return l})),r.d(t,"default",(function(){return f}));var n=r(1),o=r(9),a=(r(0),r(422)),i=r(421),c=r(429),s={last_modified_on:"2023-11-02",title:"Troubleshoot",description:"Everything you need to troubleshoot your application with Qovery",sidebar_label:"hidden",hide_pagination:!0},u={id:"using-qovery/troubleshoot",title:"Troubleshoot",description:"Everything you need to troubleshoot your application with Qovery",source:"@site/docs/using-qovery/troubleshoot.md",permalink:"/docs/using-qovery/troubleshoot",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Image Mirroring",permalink:"/docs/using-qovery/deployment/image-mirroring"},next:{title:"Application Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/application-troubleshoot"}},l=[],p={rightToc:l};function f(e){var t=e.components,r=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},p,r,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"In this guide, you'll find common mistakes, and how to resolve them. If you don't find what you need here, ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"please use the forum"),".")),Object(a.b)("p",null,"This guide is divided into three sections that will guide you through your troubleshooting depending on the issue you face"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Deployment issues: guide through to fix the deployment "),Object(a.b)("li",{parentName:"ul"},"Run issues : App in error -> provide Pod errors, performance issues (?), dropped request(nginx investigations)"),Object(a.b)("li",{parentName:"ul"},"Cluster issues: ")),Object(a.b)(c.a,{to:"/docs/using-qovery/troubleshoot/application-troubleshoot/",mdxType:"Jump"},"Application troubleshoot"),Object(a.b)(c.a,{to:"/docs/using-qovery/troubleshoot/cluster-troubleshoot/",mdxType:"Jump"},"Cluster troubleshoot"),Object(a.b)(c.a,{to:"/docs/using-qovery/troubleshoot/database-troubleshoot/",mdxType:"Jump"},"Database troubleshoot"),Object(a.b)(c.a,{to:"/docs/using-qovery/troubleshoot/lifecycle-troubleshoot/",mdxType:"Jump"},"Lifecycle troubleshoot"))}f.isMDXComponent=!0},420:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=o.a.createContext({}),l=function(e){var t=o.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=l(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,b=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return r?o.a.createElement(b,c({ref:t},u,{components:r})):o.a.createElement(b,c({ref:t},u))}));function b(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var u=2;u1?arguments[1]:void 0,r),s=i>2?arguments[2]:void 0,u=void 0===s?r:o(s,r);u>c;)t[c++]=e;return t}},427:function(e,t,r){"use strict";var n=r(1),o=r(0),a=r.n(o),i=r(39),c=r(430),s=r(20),u=r.n(s);t.a=function(e){var t,r=e.to,s=e.href,l=r||s,p=Object(c.a)(l),f=Object(o.useRef)(!1),d=u.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(l),function(){d&&t&&t.disconnect()}}),[l,d,p]),l&&p?a.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){f.current||(window.docusaurus.preload(l),f.current=!0)},innerRef:function(e){var r,n;d&&e&&p&&(r=e,n=function(){window.docusaurus.prefetch(l)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){r===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):a.a.createElement("a",Object(n.a)({},e,{href:l}))}},429:function(e,t,r){"use strict";var n=r(0),o=r.n(n),a=r(427),i=r(420),c=r.n(i);r(133);t.a=function(e){var t=e.children,r=e.className,n=e.badge,i=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,f=c()("jump-to","jump-to--"+u,r),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},n?o.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return l?o.a.createElement("a",{href:p,target:l,className:f},d):o.a.createElement(a.a,{to:p,className:f},d)}},430:function(e,t,r){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}r.d(t,"a",(function(){return n}))}}]); \ No newline at end of file +/*! For license information please see b4dda200.9bd97e60.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[179],{330:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return s})),r.d(t,"metadata",(function(){return u})),r.d(t,"rightToc",(function(){return l})),r.d(t,"default",(function(){return f}));var n=r(1),o=r(9),a=(r(0),r(425)),i=r(424),c=r(431),s={last_modified_on:"2023-11-02",title:"Troubleshoot",description:"Everything you need to troubleshoot your application with Qovery",sidebar_label:"hidden",hide_pagination:!0},u={id:"using-qovery/troubleshoot",title:"Troubleshoot",description:"Everything you need to troubleshoot your application with Qovery",source:"@site/docs/using-qovery/troubleshoot.md",permalink:"/docs/using-qovery/troubleshoot",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Image Mirroring",permalink:"/docs/using-qovery/deployment/image-mirroring"},next:{title:"Application Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/application-troubleshoot"}},l=[],p={rightToc:l};function f(e){var t=e.components,r=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},p,r,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"In this guide, you'll find common mistakes, and how to resolve them. If you don't find what you need here, ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"please use the forum"),".")),Object(a.b)("p",null,"This guide is divided into three sections that will guide you through your troubleshooting depending on the issue you face"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Deployment issues: guide through to fix the deployment "),Object(a.b)("li",{parentName:"ul"},"Run issues : App in error -> provide Pod errors, performance issues (?), dropped request(nginx investigations)"),Object(a.b)("li",{parentName:"ul"},"Cluster issues: ")),Object(a.b)(c.a,{to:"/docs/using-qovery/troubleshoot/application-troubleshoot/",mdxType:"Jump"},"Application troubleshoot"),Object(a.b)(c.a,{to:"/docs/using-qovery/troubleshoot/cluster-troubleshoot/",mdxType:"Jump"},"Cluster troubleshoot"),Object(a.b)(c.a,{to:"/docs/using-qovery/troubleshoot/database-troubleshoot/",mdxType:"Jump"},"Database troubleshoot"),Object(a.b)(c.a,{to:"/docs/using-qovery/troubleshoot/lifecycle-troubleshoot/",mdxType:"Jump"},"Lifecycle troubleshoot"))}f.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=o.a.createContext({}),l=function(e){var t=o.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=l(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,b=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return r?o.a.createElement(b,c({ref:t},u,{components:r})):o.a.createElement(b,c({ref:t},u))}));function b(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var u=2;u1?arguments[1]:void 0,r),s=i>2?arguments[2]:void 0,u=void 0===s?r:o(s,r);u>c;)t[c++]=e;return t}},430:function(e,t,r){"use strict";var n=r(1),o=r(0),a=r.n(o),i=r(39),c=r(432),s=r(20),u=r.n(s);t.a=function(e){var t,r=e.to,s=e.href,l=r||s,p=Object(c.a)(l),f=Object(o.useRef)(!1),d=u.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(l),function(){d&&t&&t.disconnect()}}),[l,d,p]),l&&p?a.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){f.current||(window.docusaurus.preload(l),f.current=!0)},innerRef:function(e){var r,n;d&&e&&p&&(r=e,n=function(){window.docusaurus.prefetch(l)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){r===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):a.a.createElement("a",Object(n.a)({},e,{href:l}))}},431:function(e,t,r){"use strict";var n=r(0),o=r.n(n),a=r(430),i=r(423),c=r.n(i);r(133);t.a=function(e){var t=e.children,r=e.className,n=e.badge,i=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,f=c()("jump-to","jump-to--"+u,r),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},n?o.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return l?o.a.createElement("a",{href:p,target:l,className:f},d):o.a.createElement(a.a,{to:p,className:f},d)}},432:function(e,t,r){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}r.d(t,"a",(function(){return n}))}}]); \ No newline at end of file diff --git a/b7280cb5.8ba4c5aa.js.LICENSE.txt b/b4dda200.9bd97e60.js.LICENSE.txt similarity index 100% rename from b7280cb5.8ba4c5aa.js.LICENSE.txt rename to b4dda200.9bd97e60.js.LICENSE.txt diff --git a/b565c464.75f931df.js b/b565c464.b03ae35c.js similarity index 95% rename from b565c464.75f931df.js rename to b565c464.b03ae35c.js index 1318b91dc0..03fd9c0072 100644 --- a/b565c464.75f931df.js +++ b/b565c464.b03ae35c.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[177],{328:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return b})),a.d(t,"metadata",(function(){return p})),a.d(t,"rightToc",(function(){return m})),a.d(t,"default",(function(){return g}));var n=a(1),r=a(9),o=(a(0),a(422)),l=a(434),i=a(441),c=a(421),s=a(426),u=a(429),b={last_modified_on:"2023-04-23",$schema:"/.meta/.schemas/guides.json",title:"How to deploy a Rust REST API application on AWS with ease",description:"In this article, you will learn how to deploy a Rust REST API application on AWS with ease",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","language: rust"],hide_pagination:!0},p={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to deploy a Rust REST API application on AWS with ease",description:"In this article, you will learn how to deploy a Rust REST API application on AWS with ease",permalink:"/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease",readingTime:"8 min read",source:"@site/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"language: rust",permalink:"/guides/tags/language-rust"}],title:"How to deploy a Rust REST API application on AWS with ease",truncated:!1,prevItem:{title:"How to create an RDS instance through the AWS console",permalink:"/guides/tutorial/how-to-create-an-rds-instance-through-aws-console"},nextItem:{title:"How to deploy Helm charts",permalink:"/guides/tutorial/how-to-deploy-helm-charts"}},m=[{value:"Create a Rust REST API app",id:"create-a-rust-rest-api-app",children:[]},{value:"Dockerized our Rust REST API app",id:"dockerized-our-rust-rest-api-app",children:[]},{value:"Deploy our Rust REST API app on AWS",id:"deploy-our-rust-rest-api-app-on-aws",children:[{value:"Sign up into Qovery",id:"sign-up-into-qovery",children:[]},{value:"Install Qovery CLI",id:"install-qovery-cli",children:[]},{value:"Sign up",id:"sign-up",children:[]},{value:"Connect your AWS account",id:"connect-your-aws-account",children:[]},{value:"Deploy our Rust REST API app",id:"deploy-our-rust-rest-api-app",children:[]}]},{value:"Wrapping up",id:"wrapping-up",children:[]},{value:"Useful resources",id:"useful-resources",children:[]}],d={rightToc:m};function g(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},d,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/rust-lang/www.rust-lang.org/issues/419#issuecomment-443418587"}),"Fast, reliable, productive - Pick three")," | Rust's slogan")),Object(o.b)("p",null,"Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety."),Object(o.b)("p",null,"In this article, you will learn how to deploy a Rust API easily in a few steps. This article is separate into two parts:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Create a Rust REST API app"),Object(o.b)("li",{parentName:"ul"},"Dockerized our Rust REST API app"),Object(o.b)("li",{parentName:"ul"},"Deploy our Rust REST API app on AWS")),Object(o.b)(s.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Rust installed on your system (instructions ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.rust-lang.org/learn/get-started"}),"here"),")"),Object(o.b)("li",{parentName:"ul"},"You have an AWS account"),Object(o.b)("li",{parentName:"ul"},"You have a GitHub account"))),Object(o.b)("p",null,"Let's go!"),Object(o.b)("h2",{id:"create-a-rust-rest-api-app"},"Create a Rust REST API app"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Check out the Rust REST API repo ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/rust-prime-number-api"}),"here"),". You can fork it!")),Object(o.b)("p",null,"To illustrate the deployment of our Rust API application, we are going to create an API to know if a number is prime number. Let's create our Rust project using cargo"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="create our rust project"',title:'"create',our:!0,rust:!0,'project"':!0}),"cargo new --bin rust-prime-number-api\n")),Object(o.b)("p",null,"Now you must have a ",Object(o.b)("inlineCode",{parentName:"p"},"rust-prime-number-api")," folder with 2 files:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Cargo.toml")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"src/main.rs"))),Object(o.b)("p",null,"To build our Rust REST API we are going to use Rocket - a web framework for Rust that makes it simple to write fast web application."),Object(o.b)("p",null,"Add the ",Object(o.b)("inlineCode",{parentName:"p"},"rocket")," and ",Object(o.b)("inlineCode",{parentName:"p"},"serde")," (JSON serializer/deserializer) dependencies to your ",Object(o.b)("inlineCode",{parentName:"p"},"Cargo.toml"),", then run ",Object(o.b)("inlineCode",{parentName:"p"},"cargo fetch")," (optional) to update your local dependencies."),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-toml",metastring:'title="Cargo.toml" {9-12}',title:'"Cargo.toml"',"{9-12}":!0}),'[package]\nname = "rust-prime-number-api"\nversion = "0.1.0"\nauthors = ["Romaric Philogene "]\nedition = "2018"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrocket = { version = "0.5.0-rc.1", features = ["json"] }\nserde = { version = "1.0.130", features = ["derive"] }\nserde_json = "1.0.68"\n')),Object(o.b)("p",null,"Put inside your ",Object(o.b)("inlineCode",{parentName:"p"},"src/main.rs")," the following Rust code"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="src/main.rs"',title:'"src/main.rs"'}),'#[macro_use]\nextern crate rocket;\n\nuse rocket::serde::json::Json;\nuse serde::Serialize;\nuse std::time::SystemTime;\nuse std::net::{IpAddr, Ipv4Addr};\n\n#[derive(Serialize)]\nstruct NumberResponse {\n number: u64,\n is_prime_number: bool,\n execution_time_in_micros: u128\n}\n\n#[get("/")]\nfn index() -> &\'static str {\n "This is my Rust prime number REST API"\n}\n\n#[get("/isPrime?")]\nfn get_is_prime(number: u64) -> Json {\n let now = SystemTime::now();\n\n Json(NumberResponse {\n number,\n is_prime_number: is_prime(number),\n execution_time_in_micros: now.elapsed().unwrap().as_micros(),\n })\n}\n\nfn is_prime(n: u64) -> bool {\n if n <= 1 {\n return false;\n }\n\n for a in 2..n {\n if n % a == 0 {\n return false;\n }\n }\n\n true\n}\n\n#[rocket::main]\nasync fn main() {\n let mut config = rocket::config::Config::default();\n config.address = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0));\n\n let _ = rocket::build()\n .configure(config)\n .mount("/", routes![index, get_is_prime])\n .launch()\n .await;\n}\n')),Object(o.b)("p",null,"Run ",Object(o.b)("inlineCode",{parentName:"p"},"cargo run")," and you are supposed to get the following output"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"\ud83d\udd27 Configured for debug.\n >> address: 0.0.0.0\n >> port: 8000\n >> workers: 16\n >> ident: Rocket\n >> keep-alive: 5s\n >> limits: bytes = 8KiB, data-form = 2MiB, file = 1MiB, form = 32KiB, json = 1MiB, msgpack = 1MiB, string = 8KiB\n >> tls: disabled\n >> temp dir: /var/folders/td/bjr48yg96gd2xgd3s44fg40c0000gn/T/\n >> log level: normal\n >> cli colors: true\n >> shutdown: ctrlc = true, force = true, signals = [SIGTERM], grace = 2s, mercy = 3s\n\ud83d\udef0 Routes:\n >> (index) GET /\n >> (get_is_prime) GET /isPrime?\n\ud83d\udce1 Fairings:\n >> Shield (liftoff, response, singleton)\n\ud83d\udee1\ufe0f Shield:\n >> X-Frame-Options: SAMEORIGIN\n >> Permissions-Policy: interest-cohort=()\n >> X-Content-Type-Options: nosniff\n\ud83d\ude80 Rocket has launched from http://127.0.0.1:8000\n")),Object(o.b)("p",null,"You can try your Rust REST API by opening ",Object(o.b)("inlineCode",{parentName:"p"},"http://127.0.0.1:8000/isPrime?number=9293029022983991")," in your browser."),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-json"}),'{\n "number": 9293029022983992,\n "is_prime_number": false,\n "execution_time_in_micros": 942894\n}\n')),Object(o.b)("p",null,"Let's now containerized our app with Docker to deploy it on our AWS account."),Object(o.b)("h2",{id:"dockerized-our-rust-rest-api-app"},"Dockerized our Rust REST API app"),Object(o.b)("p",null,"To run our Rust app we need to provide a valid Dockerfile. If you are not familiar with Docker, you can take a look to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/how-to-write-a-dockerfile/"}),"this article"),". Here is the content of our Dockerfile."),Object(o.b)(c.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"Our Dockerfile contains a multi-stage build. That is why we have two ",Object(o.b)("inlineCode",{parentName:"p"},"FROM")," instructions.\nOur final container image is optimized to be as light as possible.")),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-Dockerfile",metastring:'title="Dockerfile"',title:'"Dockerfile"'}),'####################################################################################################\n## Builder\n####################################################################################################\nFROM rust:latest AS builder\n\nRUN rustup target add x86_64-unknown-linux-musl\nRUN apt update && apt install -y musl-tools musl-dev\nRUN update-ca-certificates\n\n# Create appuser\nENV USER=app\nENV UID=10001\n\nRUN adduser \\\n --disabled-password \\\n --gecos "" \\\n --home "/nonexistent" \\\n --shell "/sbin/nologin" \\\n --no-create-home \\\n --uid "${UID}" \\\n "${USER}"\n\nWORKDIR /app\n\nCOPY ./ .\n\nRUN cargo build --target x86_64-unknown-linux-musl --release\n\n####################################################################################################\n## Final image\n####################################################################################################\nFROM scratch\n\n# Import from builder.\nCOPY --from=builder /etc/passwd /etc/passwd\nCOPY --from=builder /etc/group /etc/group\n\nWORKDIR /app\n\n# Copy our build\nCOPY --from=builder /app/target/x86_64-unknown-linux-musl/release/rust-prime-number-api ./\n\n# Use an unprivileged user.\nUSER app:app\n\nCMD ["/app/rust-prime-number-api"]\n')),Object(o.b)("h2",{id:"deploy-our-rust-rest-api-app-on-aws"},"Deploy our Rust REST API app on AWS"),Object(o.b)("p",null,"To deploy our Rust app on AWS we are going to use Qovery. Qovery is the simplest way to deploy any app on AWS. It is the perfect candidate to deploy our Rust REST API in a few steps."),Object(o.b)("h3",{id:"sign-up-into-qovery"},"Sign up into Qovery"),Object(o.b)("p",null,"First, you need to sign up or sign in on Qovery."),Object(o.b)(l.a,{centered:!0,className:"rounded",defaultValue:"web",placeholder:"Select your interface",select:!1,size:null,values:[{group:"Interfaces",label:"Web",value:"web"},{group:"Interfaces",label:"CLI",value:"cli"}],mdxType:"Tabs"},Object(o.b)(i.a,{value:"web",mdxType:"TabItem"},Object(o.b)("li",null,Object(o.b)("p",null,"Sign in to the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web interface"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("a",{href:"https://onboarding.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.jpg",alt:"Qovery Sign-up page"}))))),Object(o.b)(i.a,{value:"cli",mdxType:"TabItem"},Object(o.b)("li",null,Object(o.b)("h3",{id:"install-qovery-cli"},"Install Qovery CLI"),Object(o.b)(l.a,{centered:!0,className:"rounded",defaultValue:"linux",placeholder:"Select your OS",select:!1,size:null,values:[{group:"Platforms",label:"Linux",value:"linux"},{group:"Platforms",label:"MacOS",value:"macos"},{group:"Platforms",label:"Windows",value:"windows"},{group:"Platforms",label:"Docker",value:"docker"}],mdxType:"Tabs"},Object(o.b)(i.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(l.a,{centered:!0,className:"rounded",defaultValue:"universal",values:[{label:"*nix",value:"universal"},{label:"Arch Linux",value:"arch"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(i.a,{value:"universal",mdxType:"TabItem"},Object(o.b)("p",null,"To download and install Qovery CLI on any Linux distribution:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(i.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(i.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Linux manually by downloading the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(o.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(o.b)(i.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(l.a,{centered:!0,className:"rounded",defaultValue:"homebrew",values:[{label:"Homebrew",value:"homebrew"},{label:"Script",value:"script"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(i.a,{value:"homebrew",mdxType:"TabItem"},Object(o.b)("p",null,"The common solution to install a command line binary on the MacOS is to use ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery brew repository\n$ brew tap Qovery/qovery-cli\n\n# Install the CLI\n$ brew install qovery-cli\n"))),Object(o.b)(i.a,{value:"script",mdxType:"TabItem"},Object(o.b)("p",null,"To download and install Qovery CLI from the command line:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(i.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Mac OS manually by downloading the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(o.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(o.b)(i.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(l.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(i.a,{value:"scoop",mdxType:"TabItem"},Object(o.b)("p",null,"The classic way to install binaries on Windows is to use ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery bucket\n$ scoop bucket add qovery https://github.com/Qovery/scoop-qovery-cli\n\n# Install the CLI\n$ scoop install qovery-cli\n"))),Object(o.b)(i.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Windows manually by downloading the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to\n",Object(o.b)("inlineCode",{parentName:"p"},"C:\\Windows"),".")))),Object(o.b)(i.a,{value:"docker",mdxType:"TabItem"},Object(o.b)("p",null,"Install Docker on your local machine and run the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Pull and Run the latest Qovery CLI\n$ docker run ghcr.io/qovery/qovery-cli:latest help\n")),Object(o.b)("p",null,"Change ",Object(o.b)("inlineCode",{parentName:"p"},"latest")," by the version you want to use. For example, to use the version 0.58.4, run:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ docker run ghcr.io/qovery/qovery-cli:0.58.4 help\n")),Object(o.b)("p",null,"Note: ",Object(o.b)("inlineCode",{parentName:"p"},"ghcr.io")," is the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/pkgs/container/qovery-cli"}),"GitHub Container Registry"),".")))),Object(o.b)("li",null,Object(o.b)("h3",{id:"sign-up"},"Sign up"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using an environment without access to GUI or a browser, you can use headless authentication instead:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth --headless\n"))),Object(o.b)("p",null,"Your browser window with sign-in options will open."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/qovery_signup.svg",alt:"Qovery Sign-up page"})),Object(o.b)("p",null,Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/apps/qovery/installations/new"}),"Click here")," to authorize Qovery to clone and build your applications."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/github_signup.svg",alt:"Connect Github"})),Object(o.b)("p",null,"Congratulations, you are logged-in.")))),Object(o.b)("h3",{id:"connect-your-aws-account"},"Connect your AWS account"),Object(o.b)("p",null,"To connect your AWS account check out ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes/"}),"this guide"),"."),Object(o.b)(c.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"Qovery installation on your AWS account takes up to 30 minutes. You will be notified by email when it is over.")),Object(o.b)("h3",{id:"deploy-our-rust-rest-api-app"},"Deploy our Rust REST API app"),Object(o.b)("p",null,"Once your AWS account is set-up, you can deploy your Rust app by.."),Object(o.b)("p",null,"Creating a project ",Object(o.b)("inlineCode",{parentName:"p"},"prime number"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/rust_prime_number_project.png",alt:"Create a project"})),Object(o.b)("p",null,"Creating an environment ",Object(o.b)("inlineCode",{parentName:"p"},"prod"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/rust_prime_number_environment.png",alt:"Create an environment"})),Object(o.b)("p",null,"Creating an app by selecting your Rust app repository, build mode > ",Object(o.b)("strong",{parentName:"p"},"Dockerfile"),", and the port ",Object(o.b)("strong",{parentName:"p"},"8000"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/rust_prime_number_app.png",alt:"Create an app"})),Object(o.b)("p",null,"And deploy! That's it \ud83d\udd25... nothing more. Our Rust REST API app is ready"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/rust_prime_number_app_deployed.png",alt:"Our app is deployed"})),Object(o.b)("p",null,"Check out this video to see how I quickly deploy my Rust REST API with Qovery."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/7ae48d3383da40159d8aa97c23aadb3e",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("p",null,"Watch this video showing the final result \ud83d\udc47"),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/30cc34ef166a4fdaaeb0a9e864bf7836",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(o.b)("p",null,"Rust combined to Rocket web framework turns building REST API super easy. Deploying your Rust app on AWS with Qovery is as simple as selecting your GitHub repository. Nothing more. Hope you liked it."),Object(o.b)("h2",{id:"useful-resources"},"Useful resources"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/evoxmusic/rust-prime-number-api"}),"Source code")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://rocket.rs"}),"Rocket framework")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://doc.rust-lang.org/book/"}),"The Rust programming language book")," (Free)"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://circleci.com/blog/rust-cd/"}),"Rust Circle CI"))),Object(o.b)(u.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}g.isMDXComponent=!0},421:function(e,t,a){"use strict";a(423);var n=a(0),r=a.n(n),o=a(420),l=a.n(o);a(132);t.a=function(e){var t=e.children,a=e.classNames,n=e.fill,o=e.icon,i=e.type,c=null;switch(i){case"danger":c="alert-triangle";break;case"success":c="check-circle";break;case"warning":c="alert-triangle";break;default:c="info"}return r.a.createElement("div",{className:l()(a,"alert","alert--"+i,{"alert--fill":n,"alert--icon":!1!==o}),role:"alert"},!1!==o&&r.a.createElement("i",{className:l()("feather","icon-"+(o||c))}),t)}},425:function(e,t,a){var n=a(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var n=a(0),r=a.n(n),o=a(421);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},427:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),l=a(39),i=a(430),c=a(20),s=a.n(c);t.a=function(e){var t,a=e.to,c=e.href,u=a||c,b=Object(i.a)(u),p=Object(r.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&b&&window.docusaurus.prefetch(u),function(){m&&t&&t.disconnect()}}),[u,m,b]),u&&b?o.a.createElement(l.b,Object(n.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var a,n;m&&e&&b&&(a=e,n=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:u})):o.a.createElement("a",Object(n.a)({},e,{href:u}))}},429:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(427),l=a(420),i=a.n(l);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,l=e.leftIcon,c=e.rightIcon,s=e.size,u=e.target,b=e.to,p=i()("jump-to","jump-to--"+s,a),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},l&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+l})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:b,target:u,className:p},m):r.a.createElement(o.a,{to:b,className:p},m)}},430:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},434:function(e,t,a){"use strict";var n=a(1),r=(a(439),a(436),a(52),a(29),a(22),a(21),a(0)),o=a.n(r),l=a(446),i=a(420),c=a.n(i),s=a(428),u=a.n(s),b=a(445),p=37,m=39;function d(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,r=e.className,l=e.handleKeydown,i=e.style,s=e.values,u=e.selectedValue,b=e.tabRefs;return o.a.createElement("div",{className:a?"tabs--centered":null},o.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:c()("tabs",r,{"tabs--block":t}),style:i},s.map((function(e){var t=e.value,a=e.label;return o.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":u===t,className:c()("tab-item",{"tab-item--active":u===t}),key:t,ref:function(e){return b.push(e)},onKeyDown:function(e){return l(b,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function g(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,r=e.size,i=e.values,c=i;if(c[0].group){var s=_.groupBy(c,"group");c=Object.keys(s).map((function(e){return{label:e,options:s[e]}}))}return o.a.createElement(l.a,{className:"react-select-container react-select--"+r,classNamePrefix:"react-select",options:c,isClearable:a,placeholder:t,value:i.find((function(e){return e.value==a})),onChange:function(e){return n(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,a=e.defaultValue,l=e.groupId,i=e.label,c=e.placeholder,s=e.select,h=e.size,O=(e.style,e.values),j=e.urlKey,y=Object(b.a)(),f=y.tabGroupChoices,v=y.setTabGroupChoices,w=Object(r.useState)(a),N=w[0],R=w[1];if(null!=l){var T=f[l];null!=T&&T!==N&&R(T)}var I=function(e){R(e),null!=l&&v(l,e)},k=[],S=function(e,t,a){switch(a.keyCode){case m:!function(e,t){var a=e.indexOf(t)+1;e[a]?e[a].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var a=e.indexOf(t)-1;e[a]?e[a].focus():e[e.length-1].focus()}(e,t)}};return Object(r.useEffect)((function(){if("undefined"!=typeof window&&window.location&&j){var e=u.a.parse(window.location.search);e[j]&&R(e[j])}}),[]),o.a.createElement(o.a.Fragment,null,o.a.createElement("div",{className:"margin-bottom--"+(h||"md")},i&&o.a.createElement("div",{className:"margin-vert--sm"},i),O.length>1&&(s?o.a.createElement(g,Object(n.a)({changeSelectedValue:I,handleKeydown:S,placeholder:c,selectedValue:N,size:h,tabRefs:k},e)):o.a.createElement(d,Object(n.a)({changeSelectedValue:I,handleKeydown:S,selectedValue:N,tabRefs:k},e)))),r.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},441:function(e,t,a){"use strict";var n=a(0),r=a.n(n);t.a=function(e){return r.a.createElement(r.a.Fragment,null,e.children)}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[180],{331:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return b})),a.d(t,"metadata",(function(){return p})),a.d(t,"rightToc",(function(){return m})),a.d(t,"default",(function(){return g}));var n=a(1),r=a(9),o=(a(0),a(425)),l=a(437),i=a(444),c=a(424),s=a(429),u=a(431),b={last_modified_on:"2023-04-23",$schema:"/.meta/.schemas/guides.json",title:"How to deploy a Rust REST API application on AWS with ease",description:"In this article, you will learn how to deploy a Rust REST API application on AWS with ease",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","language: rust"],hide_pagination:!0},p={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to deploy a Rust REST API application on AWS with ease",description:"In this article, you will learn how to deploy a Rust REST API application on AWS with ease",permalink:"/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease",readingTime:"8 min read",source:"@site/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"language: rust",permalink:"/guides/tags/language-rust"}],title:"How to deploy a Rust REST API application on AWS with ease",truncated:!1,prevItem:{title:"How to create an RDS instance through the AWS console",permalink:"/guides/tutorial/how-to-create-an-rds-instance-through-aws-console"},nextItem:{title:"How to deploy Helm charts",permalink:"/guides/tutorial/how-to-deploy-helm-charts"}},m=[{value:"Create a Rust REST API app",id:"create-a-rust-rest-api-app",children:[]},{value:"Dockerized our Rust REST API app",id:"dockerized-our-rust-rest-api-app",children:[]},{value:"Deploy our Rust REST API app on AWS",id:"deploy-our-rust-rest-api-app-on-aws",children:[{value:"Sign up into Qovery",id:"sign-up-into-qovery",children:[]},{value:"Install Qovery CLI",id:"install-qovery-cli",children:[]},{value:"Sign up",id:"sign-up",children:[]},{value:"Connect your AWS account",id:"connect-your-aws-account",children:[]},{value:"Deploy our Rust REST API app",id:"deploy-our-rust-rest-api-app",children:[]}]},{value:"Wrapping up",id:"wrapping-up",children:[]},{value:"Useful resources",id:"useful-resources",children:[]}],d={rightToc:m};function g(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},d,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/rust-lang/www.rust-lang.org/issues/419#issuecomment-443418587"}),"Fast, reliable, productive - Pick three")," | Rust's slogan")),Object(o.b)("p",null,"Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety."),Object(o.b)("p",null,"In this article, you will learn how to deploy a Rust API easily in a few steps. This article is separate into two parts:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Create a Rust REST API app"),Object(o.b)("li",{parentName:"ul"},"Dockerized our Rust REST API app"),Object(o.b)("li",{parentName:"ul"},"Deploy our Rust REST API app on AWS")),Object(o.b)(s.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Rust installed on your system (instructions ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.rust-lang.org/learn/get-started"}),"here"),")"),Object(o.b)("li",{parentName:"ul"},"You have an AWS account"),Object(o.b)("li",{parentName:"ul"},"You have a GitHub account"))),Object(o.b)("p",null,"Let's go!"),Object(o.b)("h2",{id:"create-a-rust-rest-api-app"},"Create a Rust REST API app"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Check out the Rust REST API repo ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/rust-prime-number-api"}),"here"),". You can fork it!")),Object(o.b)("p",null,"To illustrate the deployment of our Rust API application, we are going to create an API to know if a number is prime number. Let's create our Rust project using cargo"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="create our rust project"',title:'"create',our:!0,rust:!0,'project"':!0}),"cargo new --bin rust-prime-number-api\n")),Object(o.b)("p",null,"Now you must have a ",Object(o.b)("inlineCode",{parentName:"p"},"rust-prime-number-api")," folder with 2 files:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Cargo.toml")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"src/main.rs"))),Object(o.b)("p",null,"To build our Rust REST API we are going to use Rocket - a web framework for Rust that makes it simple to write fast web application."),Object(o.b)("p",null,"Add the ",Object(o.b)("inlineCode",{parentName:"p"},"rocket")," and ",Object(o.b)("inlineCode",{parentName:"p"},"serde")," (JSON serializer/deserializer) dependencies to your ",Object(o.b)("inlineCode",{parentName:"p"},"Cargo.toml"),", then run ",Object(o.b)("inlineCode",{parentName:"p"},"cargo fetch")," (optional) to update your local dependencies."),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-toml",metastring:'title="Cargo.toml" {9-12}',title:'"Cargo.toml"',"{9-12}":!0}),'[package]\nname = "rust-prime-number-api"\nversion = "0.1.0"\nauthors = ["Romaric Philogene "]\nedition = "2018"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrocket = { version = "0.5.0-rc.1", features = ["json"] }\nserde = { version = "1.0.130", features = ["derive"] }\nserde_json = "1.0.68"\n')),Object(o.b)("p",null,"Put inside your ",Object(o.b)("inlineCode",{parentName:"p"},"src/main.rs")," the following Rust code"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="src/main.rs"',title:'"src/main.rs"'}),'#[macro_use]\nextern crate rocket;\n\nuse rocket::serde::json::Json;\nuse serde::Serialize;\nuse std::time::SystemTime;\nuse std::net::{IpAddr, Ipv4Addr};\n\n#[derive(Serialize)]\nstruct NumberResponse {\n number: u64,\n is_prime_number: bool,\n execution_time_in_micros: u128\n}\n\n#[get("/")]\nfn index() -> &\'static str {\n "This is my Rust prime number REST API"\n}\n\n#[get("/isPrime?")]\nfn get_is_prime(number: u64) -> Json {\n let now = SystemTime::now();\n\n Json(NumberResponse {\n number,\n is_prime_number: is_prime(number),\n execution_time_in_micros: now.elapsed().unwrap().as_micros(),\n })\n}\n\nfn is_prime(n: u64) -> bool {\n if n <= 1 {\n return false;\n }\n\n for a in 2..n {\n if n % a == 0 {\n return false;\n }\n }\n\n true\n}\n\n#[rocket::main]\nasync fn main() {\n let mut config = rocket::config::Config::default();\n config.address = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0));\n\n let _ = rocket::build()\n .configure(config)\n .mount("/", routes![index, get_is_prime])\n .launch()\n .await;\n}\n')),Object(o.b)("p",null,"Run ",Object(o.b)("inlineCode",{parentName:"p"},"cargo run")," and you are supposed to get the following output"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"\ud83d\udd27 Configured for debug.\n >> address: 0.0.0.0\n >> port: 8000\n >> workers: 16\n >> ident: Rocket\n >> keep-alive: 5s\n >> limits: bytes = 8KiB, data-form = 2MiB, file = 1MiB, form = 32KiB, json = 1MiB, msgpack = 1MiB, string = 8KiB\n >> tls: disabled\n >> temp dir: /var/folders/td/bjr48yg96gd2xgd3s44fg40c0000gn/T/\n >> log level: normal\n >> cli colors: true\n >> shutdown: ctrlc = true, force = true, signals = [SIGTERM], grace = 2s, mercy = 3s\n\ud83d\udef0 Routes:\n >> (index) GET /\n >> (get_is_prime) GET /isPrime?\n\ud83d\udce1 Fairings:\n >> Shield (liftoff, response, singleton)\n\ud83d\udee1\ufe0f Shield:\n >> X-Frame-Options: SAMEORIGIN\n >> Permissions-Policy: interest-cohort=()\n >> X-Content-Type-Options: nosniff\n\ud83d\ude80 Rocket has launched from http://127.0.0.1:8000\n")),Object(o.b)("p",null,"You can try your Rust REST API by opening ",Object(o.b)("inlineCode",{parentName:"p"},"http://127.0.0.1:8000/isPrime?number=9293029022983991")," in your browser."),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-json"}),'{\n "number": 9293029022983992,\n "is_prime_number": false,\n "execution_time_in_micros": 942894\n}\n')),Object(o.b)("p",null,"Let's now containerized our app with Docker to deploy it on our AWS account."),Object(o.b)("h2",{id:"dockerized-our-rust-rest-api-app"},"Dockerized our Rust REST API app"),Object(o.b)("p",null,"To run our Rust app we need to provide a valid Dockerfile. If you are not familiar with Docker, you can take a look to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/how-to-write-a-dockerfile/"}),"this article"),". Here is the content of our Dockerfile."),Object(o.b)(c.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"Our Dockerfile contains a multi-stage build. That is why we have two ",Object(o.b)("inlineCode",{parentName:"p"},"FROM")," instructions.\nOur final container image is optimized to be as light as possible.")),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-Dockerfile",metastring:'title="Dockerfile"',title:'"Dockerfile"'}),'####################################################################################################\n## Builder\n####################################################################################################\nFROM rust:latest AS builder\n\nRUN rustup target add x86_64-unknown-linux-musl\nRUN apt update && apt install -y musl-tools musl-dev\nRUN update-ca-certificates\n\n# Create appuser\nENV USER=app\nENV UID=10001\n\nRUN adduser \\\n --disabled-password \\\n --gecos "" \\\n --home "/nonexistent" \\\n --shell "/sbin/nologin" \\\n --no-create-home \\\n --uid "${UID}" \\\n "${USER}"\n\nWORKDIR /app\n\nCOPY ./ .\n\nRUN cargo build --target x86_64-unknown-linux-musl --release\n\n####################################################################################################\n## Final image\n####################################################################################################\nFROM scratch\n\n# Import from builder.\nCOPY --from=builder /etc/passwd /etc/passwd\nCOPY --from=builder /etc/group /etc/group\n\nWORKDIR /app\n\n# Copy our build\nCOPY --from=builder /app/target/x86_64-unknown-linux-musl/release/rust-prime-number-api ./\n\n# Use an unprivileged user.\nUSER app:app\n\nCMD ["/app/rust-prime-number-api"]\n')),Object(o.b)("h2",{id:"deploy-our-rust-rest-api-app-on-aws"},"Deploy our Rust REST API app on AWS"),Object(o.b)("p",null,"To deploy our Rust app on AWS we are going to use Qovery. Qovery is the simplest way to deploy any app on AWS. It is the perfect candidate to deploy our Rust REST API in a few steps."),Object(o.b)("h3",{id:"sign-up-into-qovery"},"Sign up into Qovery"),Object(o.b)("p",null,"First, you need to sign up or sign in on Qovery."),Object(o.b)(l.a,{centered:!0,className:"rounded",defaultValue:"web",placeholder:"Select your interface",select:!1,size:null,values:[{group:"Interfaces",label:"Web",value:"web"},{group:"Interfaces",label:"CLI",value:"cli"}],mdxType:"Tabs"},Object(o.b)(i.a,{value:"web",mdxType:"TabItem"},Object(o.b)("li",null,Object(o.b)("p",null,"Sign in to the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web interface"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("a",{href:"https://onboarding.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.jpg",alt:"Qovery Sign-up page"}))))),Object(o.b)(i.a,{value:"cli",mdxType:"TabItem"},Object(o.b)("li",null,Object(o.b)("h3",{id:"install-qovery-cli"},"Install Qovery CLI"),Object(o.b)(l.a,{centered:!0,className:"rounded",defaultValue:"linux",placeholder:"Select your OS",select:!1,size:null,values:[{group:"Platforms",label:"Linux",value:"linux"},{group:"Platforms",label:"MacOS",value:"macos"},{group:"Platforms",label:"Windows",value:"windows"},{group:"Platforms",label:"Docker",value:"docker"}],mdxType:"Tabs"},Object(o.b)(i.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(l.a,{centered:!0,className:"rounded",defaultValue:"universal",values:[{label:"*nix",value:"universal"},{label:"Arch Linux",value:"arch"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(i.a,{value:"universal",mdxType:"TabItem"},Object(o.b)("p",null,"To download and install Qovery CLI on any Linux distribution:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(i.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(i.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Linux manually by downloading the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(o.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(o.b)(i.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(l.a,{centered:!0,className:"rounded",defaultValue:"homebrew",values:[{label:"Homebrew",value:"homebrew"},{label:"Script",value:"script"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(i.a,{value:"homebrew",mdxType:"TabItem"},Object(o.b)("p",null,"The common solution to install a command line binary on the MacOS is to use ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery brew repository\n$ brew tap Qovery/qovery-cli\n\n# Install the CLI\n$ brew install qovery-cli\n"))),Object(o.b)(i.a,{value:"script",mdxType:"TabItem"},Object(o.b)("p",null,"To download and install Qovery CLI from the command line:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(i.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Mac OS manually by downloading the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(o.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(o.b)(i.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(l.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(i.a,{value:"scoop",mdxType:"TabItem"},Object(o.b)("p",null,"The classic way to install binaries on Windows is to use ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery bucket\n$ scoop bucket add qovery https://github.com/Qovery/scoop-qovery-cli\n\n# Install the CLI\n$ scoop install qovery-cli\n"))),Object(o.b)(i.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Windows manually by downloading the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to\n",Object(o.b)("inlineCode",{parentName:"p"},"C:\\Windows"),".")))),Object(o.b)(i.a,{value:"docker",mdxType:"TabItem"},Object(o.b)("p",null,"Install Docker on your local machine and run the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Pull and Run the latest Qovery CLI\n$ docker run ghcr.io/qovery/qovery-cli:latest help\n")),Object(o.b)("p",null,"Change ",Object(o.b)("inlineCode",{parentName:"p"},"latest")," by the version you want to use. For example, to use the version 0.58.4, run:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ docker run ghcr.io/qovery/qovery-cli:0.58.4 help\n")),Object(o.b)("p",null,"Note: ",Object(o.b)("inlineCode",{parentName:"p"},"ghcr.io")," is the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/pkgs/container/qovery-cli"}),"GitHub Container Registry"),".")))),Object(o.b)("li",null,Object(o.b)("h3",{id:"sign-up"},"Sign up"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using an environment without access to GUI or a browser, you can use headless authentication instead:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth --headless\n"))),Object(o.b)("p",null,"Your browser window with sign-in options will open."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/qovery_signup.svg",alt:"Qovery Sign-up page"})),Object(o.b)("p",null,Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/apps/qovery/installations/new"}),"Click here")," to authorize Qovery to clone and build your applications."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/github_signup.svg",alt:"Connect Github"})),Object(o.b)("p",null,"Congratulations, you are logged-in.")))),Object(o.b)("h3",{id:"connect-your-aws-account"},"Connect your AWS account"),Object(o.b)("p",null,"To connect your AWS account check out ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes/"}),"this guide"),"."),Object(o.b)(c.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"Qovery installation on your AWS account takes up to 30 minutes. You will be notified by email when it is over.")),Object(o.b)("h3",{id:"deploy-our-rust-rest-api-app"},"Deploy our Rust REST API app"),Object(o.b)("p",null,"Once your AWS account is set-up, you can deploy your Rust app by.."),Object(o.b)("p",null,"Creating a project ",Object(o.b)("inlineCode",{parentName:"p"},"prime number"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/rust_prime_number_project.png",alt:"Create a project"})),Object(o.b)("p",null,"Creating an environment ",Object(o.b)("inlineCode",{parentName:"p"},"prod"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/rust_prime_number_environment.png",alt:"Create an environment"})),Object(o.b)("p",null,"Creating an app by selecting your Rust app repository, build mode > ",Object(o.b)("strong",{parentName:"p"},"Dockerfile"),", and the port ",Object(o.b)("strong",{parentName:"p"},"8000"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/rust_prime_number_app.png",alt:"Create an app"})),Object(o.b)("p",null,"And deploy! That's it \ud83d\udd25... nothing more. Our Rust REST API app is ready"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/rust_prime_number_app_deployed.png",alt:"Our app is deployed"})),Object(o.b)("p",null,"Check out this video to see how I quickly deploy my Rust REST API with Qovery."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/7ae48d3383da40159d8aa97c23aadb3e",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("p",null,"Watch this video showing the final result \ud83d\udc47"),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/30cc34ef166a4fdaaeb0a9e864bf7836",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(o.b)("p",null,"Rust combined to Rocket web framework turns building REST API super easy. Deploying your Rust app on AWS with Qovery is as simple as selecting your GitHub repository. Nothing more. Hope you liked it."),Object(o.b)("h2",{id:"useful-resources"},"Useful resources"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/evoxmusic/rust-prime-number-api"}),"Source code")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://rocket.rs"}),"Rocket framework")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://doc.rust-lang.org/book/"}),"The Rust programming language book")," (Free)"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://circleci.com/blog/rust-cd/"}),"Rust Circle CI"))),Object(o.b)(u.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}g.isMDXComponent=!0},424:function(e,t,a){"use strict";a(426);var n=a(0),r=a.n(n),o=a(423),l=a.n(o);a(132);t.a=function(e){var t=e.children,a=e.classNames,n=e.fill,o=e.icon,i=e.type,c=null;switch(i){case"danger":c="alert-triangle";break;case"success":c="check-circle";break;case"warning":c="alert-triangle";break;default:c="info"}return r.a.createElement("div",{className:l()(a,"alert","alert--"+i,{"alert--fill":n,"alert--icon":!1!==o}),role:"alert"},!1!==o&&r.a.createElement("i",{className:l()("feather","icon-"+(o||c))}),t)}},428:function(e,t,a){var n=a(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var n=a(0),r=a.n(n),o=a(424);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},430:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),l=a(39),i=a(432),c=a(20),s=a.n(c);t.a=function(e){var t,a=e.to,c=e.href,u=a||c,b=Object(i.a)(u),p=Object(r.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&b&&window.docusaurus.prefetch(u),function(){m&&t&&t.disconnect()}}),[u,m,b]),u&&b?o.a.createElement(l.b,Object(n.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var a,n;m&&e&&b&&(a=e,n=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:u})):o.a.createElement("a",Object(n.a)({},e,{href:u}))}},431:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(430),l=a(423),i=a.n(l);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,l=e.leftIcon,c=e.rightIcon,s=e.size,u=e.target,b=e.to,p=i()("jump-to","jump-to--"+s,a),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},l&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+l})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:b,target:u,className:p},m):r.a.createElement(o.a,{to:b,className:p},m)}},432:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},437:function(e,t,a){"use strict";var n=a(1),r=(a(442),a(439),a(52),a(29),a(22),a(21),a(0)),o=a.n(r),l=a(449),i=a(423),c=a.n(i),s=a(433),u=a.n(s),b=a(448),p=37,m=39;function d(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,r=e.className,l=e.handleKeydown,i=e.style,s=e.values,u=e.selectedValue,b=e.tabRefs;return o.a.createElement("div",{className:a?"tabs--centered":null},o.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:c()("tabs",r,{"tabs--block":t}),style:i},s.map((function(e){var t=e.value,a=e.label;return o.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":u===t,className:c()("tab-item",{"tab-item--active":u===t}),key:t,ref:function(e){return b.push(e)},onKeyDown:function(e){return l(b,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function g(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,r=e.size,i=e.values,c=i;if(c[0].group){var s=_.groupBy(c,"group");c=Object.keys(s).map((function(e){return{label:e,options:s[e]}}))}return o.a.createElement(l.a,{className:"react-select-container react-select--"+r,classNamePrefix:"react-select",options:c,isClearable:a,placeholder:t,value:i.find((function(e){return e.value==a})),onChange:function(e){return n(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,a=e.defaultValue,l=e.groupId,i=e.label,c=e.placeholder,s=e.select,h=e.size,O=(e.style,e.values),j=e.urlKey,y=Object(b.a)(),f=y.tabGroupChoices,v=y.setTabGroupChoices,w=Object(r.useState)(a),N=w[0],R=w[1];if(null!=l){var T=f[l];null!=T&&T!==N&&R(T)}var I=function(e){R(e),null!=l&&v(l,e)},k=[],S=function(e,t,a){switch(a.keyCode){case m:!function(e,t){var a=e.indexOf(t)+1;e[a]?e[a].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var a=e.indexOf(t)-1;e[a]?e[a].focus():e[e.length-1].focus()}(e,t)}};return Object(r.useEffect)((function(){if("undefined"!=typeof window&&window.location&&j){var e=u.a.parse(window.location.search);e[j]&&R(e[j])}}),[]),o.a.createElement(o.a.Fragment,null,o.a.createElement("div",{className:"margin-bottom--"+(h||"md")},i&&o.a.createElement("div",{className:"margin-vert--sm"},i),O.length>1&&(s?o.a.createElement(g,Object(n.a)({changeSelectedValue:I,handleKeydown:S,placeholder:c,selectedValue:N,size:h,tabRefs:k},e)):o.a.createElement(d,Object(n.a)({changeSelectedValue:I,handleKeydown:S,selectedValue:N,tabRefs:k},e)))),r.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},444:function(e,t,a){"use strict";var n=a(0),r=a.n(n);t.a=function(e){return r.a.createElement(r.a.Fragment,null,e.children)}}}]); \ No newline at end of file diff --git a/b479fc9a.f934788d.js b/b5eab6bb.4643d690.js similarity index 78% rename from b479fc9a.f934788d.js rename to b5eab6bb.4643d690.js index 96dc0bbc7c..70d134f1ac 100644 --- a/b479fc9a.f934788d.js +++ b/b5eab6bb.4643d690.js @@ -1,2 +1,2 @@ -/*! For license information please see b479fc9a.f934788d.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[175],{326:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return b}));var a=n(1),r=n(9),o=(n(0),n(422)),i=n(431),c=(n(421),n(426)),l=(n(429),{last_modified_on:"2022-09-23",$schema:"/.meta/.schemas/guides.json",title:"Kubernetes observability and monitoring with Datadog",description:"How to integrate Datadog with Kubernetes on Qovery.",author_github:"https://github.com/l0ck3",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Kubernetes observability and monitoring with Datadog",description:"How to integrate Datadog with Kubernetes on Qovery.",permalink:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog",readingTime:"4 min read",source:"@site/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Kubernetes observability and monitoring with Datadog",truncated:!1,prevItem:{title:"Integrate your application logs to Cloudwatch",permalink:"/guides/tutorial/cloudwatch-integration"},nextItem:{title:"Managing Environment Variables in React (create-react-app)",permalink:"/guides/tutorial/managing-env-variables-in-create-react-app"}},u=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],d={rightToc:u};function b(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"While Qovery will soon provide basic metrics on apps resources usage, you might need a more advanced view on what happens on your infrastructure. There are many solutions on the market, one of them being Datadog.\nDatadog is one of the leading platforms for monitoring and observability, and it's pretty easy to integrate it with Qovery."),Object(o.b)(c.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Qovery cluster running"),Object(o.b)("li",{parentName:"ul"},"You have access to your Kubernetes cluster through kubectl: ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"see how here")),Object(o.b)("li",{parentName:"ul"},"Helm v3 is installed on your machine: ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://helm.sh/docs/intro/install/"}),"https://helm.sh/docs/intro/install/")))),Object(o.b)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"In this tutorial, we will install the Datadog agent on a Qovery cluster to gather metrics about infrastructure and applications."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-datadog-account"},"Create a Datadog Account"),Object(o.b)("p",null," The first step is to create an account on Datadog: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.datadoghq.com"}),"https://www.datadoghq.com"),"."),Object(o.b)("p",null," You will be prompted to enter some information. An important decision you have to make is which site to use. It will determine where your data get stored."),Object(o.b)("p",null," Warning: You can't migrate your data between regions, so chose carefully. More information here: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.datadoghq.com/fr/getting_started/site/"}),"https://docs.datadoghq.com/fr/getting_started/site/")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/0.png",alt:"Datadog - Console"})),Object(o.b)("p",null,"After signup, you will be redirected to a wizard. Fill-in the information until you get to step 3.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"prepare-the-agent-helm-chart-values"},"Prepare the agent Helm chart values"),Object(o.b)("p",null,"When you get to step 3, ",Object(o.b)("inlineCode",{parentName:"p"},"Agent Setup"),", select ",Object(o.b)("inlineCode",{parentName:"p"},"Kubernetes")," in the list."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/1.png",alt:"Datadog - Console"})),Object(o.b)("p",null,"This screen shows you all the information you need to install the agent."),Object(o.b)("p",null,"Create a ",Object(o.b)("inlineCode",{parentName:"p"},"datadog-values.yaml")," file with the following content:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'datadog:\n clusterName: qovery-dx-cluster\n\n # datadog.site -- The site of the Datadog intake to send Agent data to\n ## Set to \'datadoghq.eu\' to send data to the EU site.\n site: datadoghq.eu\n\n # Export custom Kubernetes labels as tags\n podLabelsAsTags:\n "qovery.com/*": "%%label%%"\n\n logs:\n enabled: true\n containerCollectAll: true\n\n # Set to false if you are not using APM.\n apm:\n enabled: true\n \n containerExcludeLogs: "kube_namespace:kube-system kube_namespace:qovery kube_namespace:cert-manager kube_namespace:nginx-ingress kube_namespace:logging kube_namespace:prometheus"\n\n# You can remove this part if you are not using APM.\n# Note that it it will be enabled for all your applications.\nclusterAgent:\n admissionController:\n enabled: true\n mutateUnlabelled: true\n')),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Replace ",Object(o.b)("inlineCode",{parentName:"li"},"")," with a meaningful name to identify your cluster."),Object(o.b)("li",{parentName:"ul"},"Set the ",Object(o.b)("inlineCode",{parentName:"li"},"site")," value corresponding to the one you selected upon account creation (you can find the information under ",Object(o.b)("inlineCode",{parentName:"li"},"1 > With Helm V3 > --set datadog.site="),")")),Object(o.b)("p",null,"There are many other values you can set. For advanced usage, check: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Datadog/helm-charts/blob/main/charts/datadog/values.yaml"}),"https://github.com/Datadog/helm-charts/blob/main/charts/datadog/values.yaml"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"install-datadog-agent-in-your-cluster"},"Install Datadog agent in your cluster"),Object(o.b)("p",null,"The Datadog agent is a program that will collect data from your cluster and forward it to Datadog.\nWe'll install it uning ",Object(o.b)("inlineCode",{parentName:"p"},"Helm"),"."),Object(o.b)("p",null,"First add the ",Object(o.b)("inlineCode",{parentName:"p"},"datadog")," Helm repository and update your local list:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add datadog https://helm.datadoghq.com\nhelm repo update\n")),Object(o.b)("p",null,"Then we will install the agent in the ",Object(o.b)("inlineCode",{parentName:"p"},"datadog")," namespace:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"helm install datadog-agent \\ \n -n datadog --create-namespace \\\n -f \\\n --set datadog.apiKey='' \\\n datadog/datadog\n")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Edit the path to the ",Object(o.b)("inlineCode",{parentName:"li"},"datadog-values.yaml")," file you created"),Object(o.b)("li",{parentName:"ul"},"Replace ",Object(o.b)("inlineCode",{parentName:"li"},"")," with your actual API KEY. You can find it under ",Object(o.b)("inlineCode",{parentName:"li"},"1 > With Helm V3 > --set datadog.apiKey=")))),Object(o.b)("li",null,Object(o.b)("h4",{id:"check-the-agent-is-running-properly"},"Check the agent is running properly"),Object(o.b)("p",null,"Wait for a minute then run the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get pods -n datadog\n")),Object(o.b)("p",null,"If the installation was successful, you should see an output similar to this one: "),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"NAME READY STATUS RESTARTS AGE\ndatadog-agent-2xhsv 3/3 Running 0 1m\ndatadog-agent-cluster-agent-7f8bddd44-pwjnl 1/1 Running 0 1m\ndatadog-agent-kube-state-metrics-577fcf6778-kc2gk 1/1 Running 0 1m\ndatadog-agent-qfsl2 3/3 Running 0 1m\ndatadog-agent-s5r5r 3/3 Running 0 1m\n"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"finish-setup"},"Finish Setup"),Object(o.b)("p",null,"Once Datadog receives your data, you should be able to click ",Object(o.b)("inlineCode",{parentName:"p"},"Next")," on the wizard. You might need to refresh the page in some cases. It can take a couple minutes before your data is ready."),Object(o.b)("p",null,"You will then arrive on ",Object(o.b)("inlineCode",{parentName:"p"},"Step 4")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/2.png",alt:"Datadog - Console"})),Object(o.b)("p",null,"You can skip this part if you're not interested in monitoring your cloud account."),Object(o.b)("p",null,"Finally, restart your applications if you are using APM.")))),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"You now have Datadog agent running on your Qovery cluster. You can check their ",Object(o.b)("inlineCode",{parentName:"p"},"Getting Started")," guide to familiarize yourself with the product: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.datadoghq.com/fr/getting_started"}),"https://docs.datadoghq.com/fr/getting_started"),"."))}b.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},d=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},p=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=u(n),p=a,m=d["".concat(i,".").concat(p)]||d[p]||b[p]||o;return n?r.a.createElement(m,c({ref:t},s,{components:n})):r.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=p;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(430),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,d=Object(c.a)(u),b=Object(r.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&d&&window.docusaurus.prefetch(u),function(){p&&t&&t.disconnect()}}),[u,p,d]),u&&d?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,a;p&&e&&d&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},428:function(e,t,n){"use strict";var a=n(432),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(n(a,e,i.length))})),i.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,d=e.to,b=c()("jump-to","jump-to--"+s,n),p=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:d,target:u,className:b},p):r.a.createElement(o.a,{to:d,className:b},p)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(a.useState)(null),d=u[0],b=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!d&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==d&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see b5eab6bb.4643d690.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[181],{332:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return b}));var a=n(1),r=n(9),o=(n(0),n(425)),i=n(434),c=(n(424),n(429)),l=(n(431),{last_modified_on:"2022-09-23",$schema:"/.meta/.schemas/guides.json",title:"Kubernetes observability and monitoring with Datadog",description:"How to integrate Datadog with Kubernetes on Qovery.",author_github:"https://github.com/l0ck3",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Kubernetes observability and monitoring with Datadog",description:"How to integrate Datadog with Kubernetes on Qovery.",permalink:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog",readingTime:"4 min read",source:"@site/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Kubernetes observability and monitoring with Datadog",truncated:!1,prevItem:{title:"Integrate your application logs to Cloudwatch",permalink:"/guides/tutorial/cloudwatch-integration"},nextItem:{title:"Managing Environment Variables in React (create-react-app)",permalink:"/guides/tutorial/managing-env-variables-in-create-react-app"}},u=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],d={rightToc:u};function b(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"While Qovery will soon provide basic metrics on apps resources usage, you might need a more advanced view on what happens on your infrastructure. There are many solutions on the market, one of them being Datadog.\nDatadog is one of the leading platforms for monitoring and observability, and it's pretty easy to integrate it with Qovery."),Object(o.b)(c.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Qovery cluster running"),Object(o.b)("li",{parentName:"ul"},"You have access to your Kubernetes cluster through kubectl: ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"see how here")),Object(o.b)("li",{parentName:"ul"},"Helm v3 is installed on your machine: ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://helm.sh/docs/intro/install/"}),"https://helm.sh/docs/intro/install/")))),Object(o.b)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"In this tutorial, we will install the Datadog agent on a Qovery cluster to gather metrics about infrastructure and applications."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-datadog-account"},"Create a Datadog Account"),Object(o.b)("p",null," The first step is to create an account on Datadog: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.datadoghq.com"}),"https://www.datadoghq.com"),"."),Object(o.b)("p",null," You will be prompted to enter some information. An important decision you have to make is which site to use. It will determine where your data get stored."),Object(o.b)("p",null," Warning: You can't migrate your data between regions, so chose carefully. More information here: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.datadoghq.com/fr/getting_started/site/"}),"https://docs.datadoghq.com/fr/getting_started/site/")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/0.png",alt:"Datadog - Console"})),Object(o.b)("p",null,"After signup, you will be redirected to a wizard. Fill-in the information until you get to step 3.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"prepare-the-agent-helm-chart-values"},"Prepare the agent Helm chart values"),Object(o.b)("p",null,"When you get to step 3, ",Object(o.b)("inlineCode",{parentName:"p"},"Agent Setup"),", select ",Object(o.b)("inlineCode",{parentName:"p"},"Kubernetes")," in the list."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/1.png",alt:"Datadog - Console"})),Object(o.b)("p",null,"This screen shows you all the information you need to install the agent."),Object(o.b)("p",null,"Create a ",Object(o.b)("inlineCode",{parentName:"p"},"datadog-values.yaml")," file with the following content:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'datadog:\n clusterName: qovery-dx-cluster\n\n # datadog.site -- The site of the Datadog intake to send Agent data to\n ## Set to \'datadoghq.eu\' to send data to the EU site.\n site: datadoghq.eu\n\n # Export custom Kubernetes labels as tags\n podLabelsAsTags:\n "qovery.com/*": "%%label%%"\n\n logs:\n enabled: true\n containerCollectAll: true\n\n # Set to false if you are not using APM.\n apm:\n enabled: true\n \n containerExcludeLogs: "kube_namespace:kube-system kube_namespace:qovery kube_namespace:cert-manager kube_namespace:nginx-ingress kube_namespace:logging kube_namespace:prometheus"\n\n# You can remove this part if you are not using APM.\n# Note that it it will be enabled for all your applications.\nclusterAgent:\n admissionController:\n enabled: true\n mutateUnlabelled: true\n')),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Replace ",Object(o.b)("inlineCode",{parentName:"li"},"")," with a meaningful name to identify your cluster."),Object(o.b)("li",{parentName:"ul"},"Set the ",Object(o.b)("inlineCode",{parentName:"li"},"site")," value corresponding to the one you selected upon account creation (you can find the information under ",Object(o.b)("inlineCode",{parentName:"li"},"1 > With Helm V3 > --set datadog.site="),")")),Object(o.b)("p",null,"There are many other values you can set. For advanced usage, check: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Datadog/helm-charts/blob/main/charts/datadog/values.yaml"}),"https://github.com/Datadog/helm-charts/blob/main/charts/datadog/values.yaml"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"install-datadog-agent-in-your-cluster"},"Install Datadog agent in your cluster"),Object(o.b)("p",null,"The Datadog agent is a program that will collect data from your cluster and forward it to Datadog.\nWe'll install it uning ",Object(o.b)("inlineCode",{parentName:"p"},"Helm"),"."),Object(o.b)("p",null,"First add the ",Object(o.b)("inlineCode",{parentName:"p"},"datadog")," Helm repository and update your local list:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add datadog https://helm.datadoghq.com\nhelm repo update\n")),Object(o.b)("p",null,"Then we will install the agent in the ",Object(o.b)("inlineCode",{parentName:"p"},"datadog")," namespace:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"helm install datadog-agent \\ \n -n datadog --create-namespace \\\n -f \\\n --set datadog.apiKey='' \\\n datadog/datadog\n")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Edit the path to the ",Object(o.b)("inlineCode",{parentName:"li"},"datadog-values.yaml")," file you created"),Object(o.b)("li",{parentName:"ul"},"Replace ",Object(o.b)("inlineCode",{parentName:"li"},"")," with your actual API KEY. You can find it under ",Object(o.b)("inlineCode",{parentName:"li"},"1 > With Helm V3 > --set datadog.apiKey=")))),Object(o.b)("li",null,Object(o.b)("h4",{id:"check-the-agent-is-running-properly"},"Check the agent is running properly"),Object(o.b)("p",null,"Wait for a minute then run the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get pods -n datadog\n")),Object(o.b)("p",null,"If the installation was successful, you should see an output similar to this one: "),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"NAME READY STATUS RESTARTS AGE\ndatadog-agent-2xhsv 3/3 Running 0 1m\ndatadog-agent-cluster-agent-7f8bddd44-pwjnl 1/1 Running 0 1m\ndatadog-agent-kube-state-metrics-577fcf6778-kc2gk 1/1 Running 0 1m\ndatadog-agent-qfsl2 3/3 Running 0 1m\ndatadog-agent-s5r5r 3/3 Running 0 1m\n"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"finish-setup"},"Finish Setup"),Object(o.b)("p",null,"Once Datadog receives your data, you should be able to click ",Object(o.b)("inlineCode",{parentName:"p"},"Next")," on the wizard. You might need to refresh the page in some cases. It can take a couple minutes before your data is ready."),Object(o.b)("p",null,"You will then arrive on ",Object(o.b)("inlineCode",{parentName:"p"},"Step 4")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/2.png",alt:"Datadog - Console"})),Object(o.b)("p",null,"You can skip this part if you're not interested in monitoring your cloud account."),Object(o.b)("p",null,"Finally, restart your applications if you are using APM.")))),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"You now have Datadog agent running on your Qovery cluster. You can check their ",Object(o.b)("inlineCode",{parentName:"p"},"Getting Started")," guide to familiarize yourself with the product: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.datadoghq.com/fr/getting_started"}),"https://docs.datadoghq.com/fr/getting_started"),"."))}b.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},d=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},p=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=u(n),p=a,m=d["".concat(i,".").concat(p)]||d[p]||b[p]||o;return n?r.a.createElement(m,c({ref:t},s,{components:n})):r.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=p;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(432),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,d=Object(c.a)(u),b=Object(r.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&d&&window.docusaurus.prefetch(u),function(){p&&t&&t.disconnect()}}),[u,p,d]),u&&d?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,a;p&&e&&d&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,d=e.to,b=c()("jump-to","jump-to--"+s,n),p=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:d,target:u,className:b},p):r.a.createElement(o.a,{to:d,className:b},p)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},433:function(e,t,n){"use strict";var a=n(435),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(n(a,e,i.length))})),i.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(a.useState)(null),d=u[0],b=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!d&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==d&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/b74d0aaa.a4b5b202.js.LICENSE.txt b/b5eab6bb.4643d690.js.LICENSE.txt similarity index 100% rename from b74d0aaa.a4b5b202.js.LICENSE.txt rename to b5eab6bb.4643d690.js.LICENSE.txt diff --git a/b7280cb5.8ba4c5aa.js b/b7280cb5.5cc5b553.js similarity index 93% rename from b7280cb5.8ba4c5aa.js rename to b7280cb5.5cc5b553.js index d24e75f103..8e59da1e5c 100644 --- a/b7280cb5.8ba4c5aa.js +++ b/b7280cb5.5cc5b553.js @@ -1,2 +1,2 @@ -/*! For license information please see b7280cb5.8ba4c5aa.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[179],{330:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),o=(n(0),n(422)),i=n(421),c=n(431),s={last_modified_on:"2023-02-23",$schema:"/.meta/.schemas/guides.json",title:"Environment variables",description:"How to manage environment variables in your projects and applications",series_position:4,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},l={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Environment variables",description:"How to manage environment variables in your projects and applications",permalink:"/guides/getting-started/managing-environment-variables",readingTime:"2 min read",seriesPosition:4,source:"@site/guides/getting-started/managing-environment-variables.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Environment variables",truncated:!1,prevItem:{title:"Custom domain",permalink:"/guides/getting-started/setting-custom-domain"},nextItem:{title:"Debugging",permalink:"/guides/getting-started/debugging"}},u=[{value:"Tutorial",id:"tutorial",children:[{value:"Create an environment variable",id:"create-an-environment-variable",children:[]},{value:"Use the environment variable in the app",id:"use-the-environment-variable-in-the-app",children:[]}]}],p={rightToc:u};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Sometimes you need to pass data to your application. E.g: API key, credentials, debug parameters. For this reason, Qovery allows you to\nsecurely pass your data by using ",Object(o.b)("em",{parentName:"p"},"Environment Variables"),"."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you need to keep secure your environment variable? Use ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Secret")," instead of ",Object(o.b)("strong",{parentName:"p"},"Environment\nVariable"),".")),Object(o.b)("p",null,"Here is a short video to show how to use environment variables."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/af6d9c36b6b643eda2dc29d8b3629328",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("h2",{id:"tutorial"},"Tutorial"),Object(o.b)("p",null,"Here is an example on how to pass an environment variable to a NodeJS app."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Steps are similar for Secrets.")),Object(o.b)("p",null,"Let's first create a new Node.js application that uses environment variables."),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h3",{id:"create-an-environment-variable"},"Create an environment variable"),Object(o.b)("p",null,"Let's say that we pass an environment variable ",Object(o.b)("inlineCode",{parentName:"p"},"ENABLE_DEBUG")," that turns on the debug info from the app."),Object(o.b)("p",null,"Click on the ",Object(o.b)("inlineCode",{parentName:"p"},"environment variables")," tab inside your app view."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/environment_variables_.png",alt:"List environment variables"})),Object(o.b)("p",null,'Click on "create", and then add the ',Object(o.b)("inlineCode",{parentName:"p"},"ENABLE_DEBUG")," variable with a boolean value."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/create_environment_variable_.png",alt:"Create environment variable"}))),Object(o.b)("li",null,Object(o.b)("h3",{id:"use-the-environment-variable-in-the-app"},"Use the environment variable in the app"),Object(o.b)("p",null,"Create ",Object(o.b)("inlineCode",{parentName:"p"},"app.js")," file - a simple Node.js HTTP server application:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-javascript",metastring:'title="app.js" {6-10}',title:'"app.js"',"{6-10}":!0}),"const http = require('http');\n\nconst hostname = '0.0.0.0';\nconst port = 3333;\n\nconst enableDebug = process.env.ENABLE_DEBUG\n\nif (enableDebug) {\n console.log(\"debug mode enabled\");\n}\n\nconst server = http.createServer((req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/plain');\n res.end(\"hello world\");\n});\n\nserver.listen(port, hostname, () => {\n console.log(`Server running at http://${hostname}:${port}/`);\n});\n")),Object(o.b)("p",null,"As you can see, to get access to your environment variable you just need to use process.env.",Object(o.b)("inlineCode",{parentName:"p"},"ENABLE_DEBUG"),". Environment variables are\ninjected at the build and run time.")))),Object(o.b)("p",null,"This guide was an introduction on how to use the Environment Variables. To know more\nabout ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Environment Variables")," and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Secrets"),",\ngo to our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/"}),"detailed documentation"),"."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you want to bulk import your Environment Variables? ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli/"}),"Check out this tutorial"))))}b.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return n?a.a.createElement(m,c({ref:t},l,{components:n})):a.a.createElement(m,c({ref:t},l))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:a(s,n);l>c;)t[c++]=e;return t}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),u=Object(r.useState)(null),p=u[0],b=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see b7280cb5.5cc5b553.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[182],{333:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),o=(n(0),n(425)),i=n(424),c=n(434),s={last_modified_on:"2023-02-23",$schema:"/.meta/.schemas/guides.json",title:"Environment variables",description:"How to manage environment variables in your projects and applications",series_position:4,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},l={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Environment variables",description:"How to manage environment variables in your projects and applications",permalink:"/guides/getting-started/managing-environment-variables",readingTime:"2 min read",seriesPosition:4,source:"@site/guides/getting-started/managing-environment-variables.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Environment variables",truncated:!1,prevItem:{title:"Custom domain",permalink:"/guides/getting-started/setting-custom-domain"},nextItem:{title:"Debugging",permalink:"/guides/getting-started/debugging"}},u=[{value:"Tutorial",id:"tutorial",children:[{value:"Create an environment variable",id:"create-an-environment-variable",children:[]},{value:"Use the environment variable in the app",id:"use-the-environment-variable-in-the-app",children:[]}]}],p={rightToc:u};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Sometimes you need to pass data to your application. E.g: API key, credentials, debug parameters. For this reason, Qovery allows you to\nsecurely pass your data by using ",Object(o.b)("em",{parentName:"p"},"Environment Variables"),"."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you need to keep secure your environment variable? Use ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Secret")," instead of ",Object(o.b)("strong",{parentName:"p"},"Environment\nVariable"),".")),Object(o.b)("p",null,"Here is a short video to show how to use environment variables."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/af6d9c36b6b643eda2dc29d8b3629328",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)("h2",{id:"tutorial"},"Tutorial"),Object(o.b)("p",null,"Here is an example on how to pass an environment variable to a NodeJS app."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Steps are similar for Secrets.")),Object(o.b)("p",null,"Let's first create a new Node.js application that uses environment variables."),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h3",{id:"create-an-environment-variable"},"Create an environment variable"),Object(o.b)("p",null,"Let's say that we pass an environment variable ",Object(o.b)("inlineCode",{parentName:"p"},"ENABLE_DEBUG")," that turns on the debug info from the app."),Object(o.b)("p",null,"Click on the ",Object(o.b)("inlineCode",{parentName:"p"},"environment variables")," tab inside your app view."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/environment_variables_.png",alt:"List environment variables"})),Object(o.b)("p",null,'Click on "create", and then add the ',Object(o.b)("inlineCode",{parentName:"p"},"ENABLE_DEBUG")," variable with a boolean value."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/create_environment_variable_.png",alt:"Create environment variable"}))),Object(o.b)("li",null,Object(o.b)("h3",{id:"use-the-environment-variable-in-the-app"},"Use the environment variable in the app"),Object(o.b)("p",null,"Create ",Object(o.b)("inlineCode",{parentName:"p"},"app.js")," file - a simple Node.js HTTP server application:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-javascript",metastring:'title="app.js" {6-10}',title:'"app.js"',"{6-10}":!0}),"const http = require('http');\n\nconst hostname = '0.0.0.0';\nconst port = 3333;\n\nconst enableDebug = process.env.ENABLE_DEBUG\n\nif (enableDebug) {\n console.log(\"debug mode enabled\");\n}\n\nconst server = http.createServer((req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/plain');\n res.end(\"hello world\");\n});\n\nserver.listen(port, hostname, () => {\n console.log(`Server running at http://${hostname}:${port}/`);\n});\n")),Object(o.b)("p",null,"As you can see, to get access to your environment variable you just need to use process.env.",Object(o.b)("inlineCode",{parentName:"p"},"ENABLE_DEBUG"),". Environment variables are\ninjected at the build and run time.")))),Object(o.b)("p",null,"This guide was an introduction on how to use the Environment Variables. To know more\nabout ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Environment Variables")," and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Secrets"),",\ngo to our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/"}),"detailed documentation"),"."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you want to bulk import your Environment Variables? ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli/"}),"Check out this tutorial"))))}b.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),u=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return n?a.a.createElement(m,c({ref:t},l,{components:n})):a.a.createElement(m,c({ref:t},l))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,l=void 0===s?n:a(s,n);l>c;)t[c++]=e;return t}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),u=Object(r.useState)(null),p=u[0],b=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/b76eb9a9.97dac5fd.js.LICENSE.txt b/b7280cb5.5cc5b553.js.LICENSE.txt similarity index 100% rename from b76eb9a9.97dac5fd.js.LICENSE.txt rename to b7280cb5.5cc5b553.js.LICENSE.txt diff --git a/5b95bed2.61d54c87.js b/b74d0aaa.77f8f8af.js similarity index 96% rename from 5b95bed2.61d54c87.js rename to b74d0aaa.77f8f8af.js index 34c22d423f..75e3fcd5fe 100644 --- a/5b95bed2.61d54c87.js +++ b/b74d0aaa.77f8f8af.js @@ -1,2 +1,2 @@ -/*! For license information please see 5b95bed2.61d54c87.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[108],{259:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return s})),t.d(n,"metadata",(function(){return c})),t.d(n,"rightToc",(function(){return l})),t.d(n,"default",(function(){return p}));var a=t(1),r=t(9),o=(t(0),t(422)),i=t(421),s=(t(426),t(429),{last_modified_on:"2022-01-06",$schema:"/.meta/.schemas/guides.json",title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3",readingTime:"9 min read",source:"@site/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",truncated:!1,prevItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2"},nextItem:{title:"How to connect to a managed MongoDB instance on AWS",permalink:"/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws"}},l=[{value:"Bootstrapping Frontend",id:"bootstrapping-frontend",children:[]},{value:"Connecting Backend",id:"connecting-backend",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],u={rightToc:l};function p(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},u,t,{components:n,mdxType:"MDXLayout"}),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},"We assume you are familiar with the previous parts of the AppWrite Cloud series."),Object(o.b)("p",null,"In this part of the series, we will go through the process of adding a web user interface to our AppWrite Cloud platform. We\u2019ll use the Next.js framework to create the frontend application, connect it to our AppWrite Cloud GraphQL API and deploy the app on top of Qovery."),Object(o.b)("h2",{id:"bootstrapping-frontend"},"Bootstrapping Frontend"),Object(o.b)("p",null,"In the first step, let\u2019s create a scaffolding to our frontend application:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"yarn create next-app --example with-tailwindcss frontend\n")),Object(o.b)("p",null,"We use ",Object(o.b)("inlineCode",{parentName:"p"},"Tailwind")," for styling, so the command above bootstraps a ",Object(o.b)("inlineCode",{parentName:"p"},"Next.js")," app with TailwindCSS already set up."),Object(o.b)("p",null,"After the scaffolding is created, create a new remote Git repository on Github, Gitlab or Bitbucket with the application code."),Object(o.b)("p",null,"For building and deploying the app on Qovery, we\u2019ll use Docker - to dockerize the application please add a ",Object(o.b)("inlineCode",{parentName:"p"},"Dockerfile")," with the following content:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'# Install dependencies only when needed\nFROM node:alpine AS deps\n# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.\nRUN apk add --no-cache libc6-compat\nWORKDIR /app\nCOPY package.json yarn.lock ./\nRUN yarn install --frozen-lockfile\n\n# Rebuild the source code only when needed\nFROM node:alpine AS builder\nWORKDIR /app\nCOPY . .\nCOPY --from=deps /app/node_modules ./node_modules\nRUN yarn build && yarn install --production --ignore-scripts --prefer-offline\n\n# Production image, copy all the files and run next\nFROM node:alpine AS runner\nWORKDIR /app\n\nENV NODE_ENV production\n\nRUN addgroup -g 1001 -S nodejs\nRUN adduser -S nextjs -u 1001\n\n# You only need to copy next.config.js if you are NOT using the default configuration\n# COPY --from=builder /app/next.config.js ./\nCOPY --from=builder /app/public ./public\nCOPY --from=builder --chown=nextjs:nodejs /app/.next ./.next\nCOPY --from=builder /app/node_modules ./node_modules\nCOPY --from=builder /app/package.json ./package.json\n\nUSER nextjs\n\nEXPOSE 3000\n\n# Next.js collects completely anonymous telemetry data about general usage.\n# Learn more here: https://nextjs.org/telemetry\n# Uncomment the following line in case you want to disable telemetry.\n# ENV NEXT_TELEMETRY_DISABLED 1\n\nCMD ["yarn", "start"]\n')),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"Dockerfile")," will let Qovery know how to build and run the application. After the Dockerfile is created, add a new application in the AppWrite Cloud project on Qovery with port ",Object(o.b)("inlineCode",{parentName:"p"},"3000")," and ",Object(o.b)("inlineCode",{parentName:"p"},"Docker")," build mode:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/1.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"In the next step let\u2019s add a ",Object(o.b)("inlineCode",{parentName:"p"},"APPWRITE_GRAPHQL_BACKEND")," env variable that we will, later on, use in our frontend. This variable will be an alias to the location of our Hasura application, so we can access its GraphQL API:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/2.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h2",{id:"connecting-backend"},"Connecting Backend"),Object(o.b)("p",null,"Now to quickly deploy the app and test the integration, let\u2019s replace the content of ",Object(o.b)("inlineCode",{parentName:"p"},"index.tsx")," with the following:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'import { Disclosure, Menu, Transition } from \'@headlessui/react\';\nimport { BellIcon, MenuIcon, XIcon } from \'@heroicons/react/outline\';\nimport axios from \'axios\';\nimport { Fragment, useState } from \'react\';\nimport { useMutation } from \'react-query\';\n\nconst anonymous = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLXVzZXItaWQiOiI1IiwieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoiYW5vbnltb3VzIiwieC1oYXN1cmEtYWxsb3dlZC1yb2xlcyI6WyJhbm9ueW1vdXMiXX0sImV4cCI6MTY2NjA3NzAwNn0.Op7qVJAlMm3O2p1sSTMueuTUoUJls1K4pdmiusaz1R0"\n\nconst user = {\n name: \'Tom Cook\',\n email: \'tom@example.com\',\n imageUrl:\n \'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80\',\n};\nconst navigation = [{ name: \'Dashboard\', href: \'#\', current: true }];\nconst userNavigation = [\n { name: \'Your Profile\', href: \'#\' },\n { name: \'Settings\', href: \'#\' },\n { name: \'Sign out\', href: \'#\' },\n];\n\nfunction classNames(...classes) {\n return classes.filter(Boolean).join(\' \');\n}\n\nexport default function Dashboard() {\n return (\n
\n
\n \n {({ open }) => (\n <>\n
\n
\n
\n
\n
\n \n
\n
\n
\n {navigation.map((item) => (\n \n {item.name}\n \n ))}\n
\n
\n
\n
\n
\n \n View notifications\n
\n
\n
\n {/* Mobile menu button */}\n \n Open main menu\n {open ? (\n \n
\n
\n
\n
\n\n \n
\n {navigation.map((item) => (\n \n {item.name}\n \n ))}\n
\n
\n
\n
\n \n
\n
\n
\n {user.name}\n
\n
\n {user.email}\n
\n
\n \n View notifications\n
\n
\n {userNavigation.map((item) => (\n \n {item.name}\n \n ))}\n
\n
\n
\n \n )}\n
\n
\n
\n

Dashboard

\n
\n
\n
\n\n
\n
\n \n \n
\n
\n
\n
\n
\n
\n \n );\n}\n\nconst Signin = (email, password) => {\n const mutation = useMutation((event) => {\n event.preventDefault();\n return axios({\n url: graphqlApiEndpoint,\n method: \'post\',\n headers: { \'Authorization\': \'Bearer \' + anonymous },\n data: {\n query: `\n query Singin {\n Singin(email: "${email}", password: "${password}") {\n accessToken\n }\n }\n `,\n },\n })\n });\n return ;\n};\n\nconst Signup = (email, password) => {\n const mutation = useMutation((event) => {\n event.preventDefault();\n return axios({\n url: graphqlApiEndpoint,\n method: \'post\',\n headers: { \'Authorization\': \'Bearer \' + anonymous },\n data: {\n query: `\n query Signup {\n Signup(email: "${email}", password: "${password}") {\n accessToken\n }\n }\n `,\n },\n })\n });\n return ;\n};\n')),Object(o.b)("p",null,"This makes the skeleton of our UI:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/3.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"Clicking on the signup will send a test signup request to our backend - click ",Object(o.b)("inlineCode",{parentName:"p"},"Signup")," and see the response with an access token in the network tab of your browser:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/4.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"To send the request, we use the following piece of code:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"axios({\n url: graphqlApiEndpoint,\n method: 'post',\n headers: { Authorization: 'Bearer ' + anonymous },\n data: {\n query: `\n mutation {\n Signup(input: {email: \"${email}\", password: \"${password}\"}) {\n accessToken\n }\n }\n `,\n },\n}\n")),Object(o.b)("p",null,"We use ",Object(o.b)("inlineCode",{parentName:"p"},"axios")," HTTP library to send a ",Object(o.b)("inlineCode",{parentName:"p"},"POST")," request to our ",Object(o.b)("inlineCode",{parentName:"p"},"graphqlApiEndpoint")," (that uses the value of the environment variable we set previously) to run a GraphQL mutation that creates a new user with a given email and password in our AppWrite Cloud backend. In the response, we receive an access token that we can use in the name of the user to interact with the API."),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"anonymous")," token sent in the request is a way to interact with unauthenticated endpoints in the Hasura backend."),Object(o.b)("p",null,"In the next step let\u2019s take care of the list of user projects:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),"const { isLoading, error, data } = useQuery('projects', () => {\n return axios({\n url: graphqlApiEndpoint,\n method: 'POST',\n headers: { Authorization: 'Bearer ' + token },\n data: {\n query: `query Projects {\n project {\n id\n name\n url\n }\n }\n `,\n },\n });\n });\n")),Object(o.b)("p",null,"In the snippet above, we use ",Object(o.b)("inlineCode",{parentName:"p"},"ReactQuery")," to manage the server state (store the info about the project client-side) and axios for performing the HTTP request. In the headers, we send users\u2019 ",Object(o.b)("inlineCode",{parentName:"p"},"accessToken"),", and the payload allows us to specify data that we are interested in about projects we have access to."),Object(o.b)("p",null,"The response from the query contains info we can use to render the list of AppWrite projects managed by AppWriteCloud:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/5.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"Now, to display it, add the following piece of code into our dashboard component:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),'{appwriteProjects.map((project) => (\n\n \n\n))}\n')),Object(o.b)("p",null,"This should allow us to display a list of user\u2019s projects in the dashboard like this:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/6.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"After improving the sign in form (see the whole code repository ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/appwrite-ui"}),"here"),", the whole flow should now look like this:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/7.gif",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"In this article, we bootstrapped a frontend application and added it to our app write cloud. We created the first version of our frontend that makes use of React, Next.js, ReactQuery and Tailwind. The UI is integrated with our backend GraphQL API that is deployed on Qovery and allows us to manage AppWrite projects deployed on AWS for AppWrite Cloud clients."))}p.isMDXComponent=!0},420:function(e,n,t){var a;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=r.a.createContext({}),u=function(e){var n=r.a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):s({},n,{},e)),t},p=function(e){var n=u(e.components);return r.a.createElement(l.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},m=Object(a.forwardRef)((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=u(t),m=a,b=p["".concat(i,".").concat(m)]||p[m]||d[m]||o;return t?r.a.createElement(b,s({ref:n},l,{components:t})):r.a.createElement(b,s({ref:n},l))}));function b(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,i=new Array(o);i[0]=m;var s={};for(var c in n)hasOwnProperty.call(n,c)&&(s[c]=n[c]);s.originalType=e,s.mdxType="string"==typeof e?e:a,i[1]=s;for(var l=2;l1?arguments[1]:void 0,t),c=i>2?arguments[2]:void 0,l=void 0===c?t:r(c,t);l>s;)n[s++]=e;return n}},425:function(e,n,t){var a=t(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||t(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,n,t){"use strict";t(425);var a=t(0),r=t.n(a),o=t(421);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},427:function(e,n,t){"use strict";var a=t(1),r=t(0),o=t.n(r),i=t(39),s=t(430),c=t(20),l=t.n(c);n.a=function(e){var n,t=e.to,c=e.href,u=t||c,p=Object(s.a)(u),d=Object(r.useRef)(!1),m=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&p&&window.docusaurus.prefetch(u),function(){m&&n&&n.disconnect()}}),[u,m,p]),u&&p?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(u),d.current=!0)},innerRef:function(e){var t,a;m&&e&&p&&(t=e,a=function(){window.docusaurus.prefetch(u)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),a())}))}))).observe(t))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},429:function(e,n,t){"use strict";var a=t(0),r=t.n(a),o=t(427),i=t(420),s=t.n(i);t(133);n.a=function(e){var n=e.children,t=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,l=e.size,u=e.target,p=e.to,d=s()("jump-to","jump-to--"+l,t),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",n),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:p,target:u,className:d},m):r.a.createElement(o.a,{to:p,className:d},m)}},430:function(e,n,t){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see b74d0aaa.77f8f8af.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[183],{334:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return s})),t.d(n,"metadata",(function(){return c})),t.d(n,"rightToc",(function(){return l})),t.d(n,"default",(function(){return p}));var a=t(1),r=t(9),o=(t(0),t(425)),i=t(424),s=(t(429),t(431),{last_modified_on:"2022-01-06",$schema:"/.meta/.schemas/guides.json",title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3",readingTime:"9 min read",source:"@site/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",truncated:!1,prevItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2"},nextItem:{title:"How to connect to a managed MongoDB instance on AWS",permalink:"/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws"}},l=[{value:"Bootstrapping Frontend",id:"bootstrapping-frontend",children:[]},{value:"Connecting Backend",id:"connecting-backend",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],u={rightToc:l};function p(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},u,t,{components:n,mdxType:"MDXLayout"}),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},"We assume you are familiar with the previous parts of the AppWrite Cloud series."),Object(o.b)("p",null,"In this part of the series, we will go through the process of adding a web user interface to our AppWrite Cloud platform. We\u2019ll use the Next.js framework to create the frontend application, connect it to our AppWrite Cloud GraphQL API and deploy the app on top of Qovery."),Object(o.b)("h2",{id:"bootstrapping-frontend"},"Bootstrapping Frontend"),Object(o.b)("p",null,"In the first step, let\u2019s create a scaffolding to our frontend application:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"yarn create next-app --example with-tailwindcss frontend\n")),Object(o.b)("p",null,"We use ",Object(o.b)("inlineCode",{parentName:"p"},"Tailwind")," for styling, so the command above bootstraps a ",Object(o.b)("inlineCode",{parentName:"p"},"Next.js")," app with TailwindCSS already set up."),Object(o.b)("p",null,"After the scaffolding is created, create a new remote Git repository on Github, Gitlab or Bitbucket with the application code."),Object(o.b)("p",null,"For building and deploying the app on Qovery, we\u2019ll use Docker - to dockerize the application please add a ",Object(o.b)("inlineCode",{parentName:"p"},"Dockerfile")," with the following content:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'# Install dependencies only when needed\nFROM node:alpine AS deps\n# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.\nRUN apk add --no-cache libc6-compat\nWORKDIR /app\nCOPY package.json yarn.lock ./\nRUN yarn install --frozen-lockfile\n\n# Rebuild the source code only when needed\nFROM node:alpine AS builder\nWORKDIR /app\nCOPY . .\nCOPY --from=deps /app/node_modules ./node_modules\nRUN yarn build && yarn install --production --ignore-scripts --prefer-offline\n\n# Production image, copy all the files and run next\nFROM node:alpine AS runner\nWORKDIR /app\n\nENV NODE_ENV production\n\nRUN addgroup -g 1001 -S nodejs\nRUN adduser -S nextjs -u 1001\n\n# You only need to copy next.config.js if you are NOT using the default configuration\n# COPY --from=builder /app/next.config.js ./\nCOPY --from=builder /app/public ./public\nCOPY --from=builder --chown=nextjs:nodejs /app/.next ./.next\nCOPY --from=builder /app/node_modules ./node_modules\nCOPY --from=builder /app/package.json ./package.json\n\nUSER nextjs\n\nEXPOSE 3000\n\n# Next.js collects completely anonymous telemetry data about general usage.\n# Learn more here: https://nextjs.org/telemetry\n# Uncomment the following line in case you want to disable telemetry.\n# ENV NEXT_TELEMETRY_DISABLED 1\n\nCMD ["yarn", "start"]\n')),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"Dockerfile")," will let Qovery know how to build and run the application. After the Dockerfile is created, add a new application in the AppWrite Cloud project on Qovery with port ",Object(o.b)("inlineCode",{parentName:"p"},"3000")," and ",Object(o.b)("inlineCode",{parentName:"p"},"Docker")," build mode:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/1.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"In the next step let\u2019s add a ",Object(o.b)("inlineCode",{parentName:"p"},"APPWRITE_GRAPHQL_BACKEND")," env variable that we will, later on, use in our frontend. This variable will be an alias to the location of our Hasura application, so we can access its GraphQL API:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/2.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h2",{id:"connecting-backend"},"Connecting Backend"),Object(o.b)("p",null,"Now to quickly deploy the app and test the integration, let\u2019s replace the content of ",Object(o.b)("inlineCode",{parentName:"p"},"index.tsx")," with the following:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'import { Disclosure, Menu, Transition } from \'@headlessui/react\';\nimport { BellIcon, MenuIcon, XIcon } from \'@heroicons/react/outline\';\nimport axios from \'axios\';\nimport { Fragment, useState } from \'react\';\nimport { useMutation } from \'react-query\';\n\nconst anonymous = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLXVzZXItaWQiOiI1IiwieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoiYW5vbnltb3VzIiwieC1oYXN1cmEtYWxsb3dlZC1yb2xlcyI6WyJhbm9ueW1vdXMiXX0sImV4cCI6MTY2NjA3NzAwNn0.Op7qVJAlMm3O2p1sSTMueuTUoUJls1K4pdmiusaz1R0"\n\nconst user = {\n name: \'Tom Cook\',\n email: \'tom@example.com\',\n imageUrl:\n \'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80\',\n};\nconst navigation = [{ name: \'Dashboard\', href: \'#\', current: true }];\nconst userNavigation = [\n { name: \'Your Profile\', href: \'#\' },\n { name: \'Settings\', href: \'#\' },\n { name: \'Sign out\', href: \'#\' },\n];\n\nfunction classNames(...classes) {\n return classes.filter(Boolean).join(\' \');\n}\n\nexport default function Dashboard() {\n return (\n
\n
\n \n {({ open }) => (\n <>\n
\n
\n
\n
\n
\n \n
\n
\n
\n {navigation.map((item) => (\n \n {item.name}\n \n ))}\n
\n
\n
\n
\n
\n \n View notifications\n
\n
\n
\n {/* Mobile menu button */}\n \n Open main menu\n {open ? (\n \n
\n
\n
\n
\n\n \n
\n {navigation.map((item) => (\n \n {item.name}\n \n ))}\n
\n
\n
\n
\n \n
\n
\n
\n {user.name}\n
\n
\n {user.email}\n
\n
\n \n View notifications\n
\n
\n {userNavigation.map((item) => (\n \n {item.name}\n \n ))}\n
\n
\n
\n \n )}\n
\n
\n
\n

Dashboard

\n
\n
\n
\n\n
\n
\n \n \n
\n
\n
\n
\n
\n
\n \n );\n}\n\nconst Signin = (email, password) => {\n const mutation = useMutation((event) => {\n event.preventDefault();\n return axios({\n url: graphqlApiEndpoint,\n method: \'post\',\n headers: { \'Authorization\': \'Bearer \' + anonymous },\n data: {\n query: `\n query Singin {\n Singin(email: "${email}", password: "${password}") {\n accessToken\n }\n }\n `,\n },\n })\n });\n return ;\n};\n\nconst Signup = (email, password) => {\n const mutation = useMutation((event) => {\n event.preventDefault();\n return axios({\n url: graphqlApiEndpoint,\n method: \'post\',\n headers: { \'Authorization\': \'Bearer \' + anonymous },\n data: {\n query: `\n query Signup {\n Signup(email: "${email}", password: "${password}") {\n accessToken\n }\n }\n `,\n },\n })\n });\n return ;\n};\n')),Object(o.b)("p",null,"This makes the skeleton of our UI:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/3.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"Clicking on the signup will send a test signup request to our backend - click ",Object(o.b)("inlineCode",{parentName:"p"},"Signup")," and see the response with an access token in the network tab of your browser:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/4.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"To send the request, we use the following piece of code:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"axios({\n url: graphqlApiEndpoint,\n method: 'post',\n headers: { Authorization: 'Bearer ' + anonymous },\n data: {\n query: `\n mutation {\n Signup(input: {email: \"${email}\", password: \"${password}\"}) {\n accessToken\n }\n }\n `,\n },\n}\n")),Object(o.b)("p",null,"We use ",Object(o.b)("inlineCode",{parentName:"p"},"axios")," HTTP library to send a ",Object(o.b)("inlineCode",{parentName:"p"},"POST")," request to our ",Object(o.b)("inlineCode",{parentName:"p"},"graphqlApiEndpoint")," (that uses the value of the environment variable we set previously) to run a GraphQL mutation that creates a new user with a given email and password in our AppWrite Cloud backend. In the response, we receive an access token that we can use in the name of the user to interact with the API."),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"anonymous")," token sent in the request is a way to interact with unauthenticated endpoints in the Hasura backend."),Object(o.b)("p",null,"In the next step let\u2019s take care of the list of user projects:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),"const { isLoading, error, data } = useQuery('projects', () => {\n return axios({\n url: graphqlApiEndpoint,\n method: 'POST',\n headers: { Authorization: 'Bearer ' + token },\n data: {\n query: `query Projects {\n project {\n id\n name\n url\n }\n }\n `,\n },\n });\n });\n")),Object(o.b)("p",null,"In the snippet above, we use ",Object(o.b)("inlineCode",{parentName:"p"},"ReactQuery")," to manage the server state (store the info about the project client-side) and axios for performing the HTTP request. In the headers, we send users\u2019 ",Object(o.b)("inlineCode",{parentName:"p"},"accessToken"),", and the payload allows us to specify data that we are interested in about projects we have access to."),Object(o.b)("p",null,"The response from the query contains info we can use to render the list of AppWrite projects managed by AppWriteCloud:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/5.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"Now, to display it, add the following piece of code into our dashboard component:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),'{appwriteProjects.map((project) => (\n\n \n\n))}\n')),Object(o.b)("p",null,"This should allow us to display a list of user\u2019s projects in the dashboard like this:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/6.png",alt:"AppWrite Qovery Case Study"})),Object(o.b)("p",null,"After improving the sign in form (see the whole code repository ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/pjeziorowski/appwrite-ui"}),"here"),", the whole flow should now look like this:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/appwrite-3/7.gif",alt:"AppWrite Qovery Case Study"})),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"In this article, we bootstrapped a frontend application and added it to our app write cloud. We created the first version of our frontend that makes use of React, Next.js, ReactQuery and Tailwind. The UI is integrated with our backend GraphQL API that is deployed on Qovery and allows us to manage AppWrite projects deployed on AWS for AppWrite Cloud clients."))}p.isMDXComponent=!0},423:function(e,n,t){var a;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=r.a.createContext({}),u=function(e){var n=r.a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):s({},n,{},e)),t},p=function(e){var n=u(e.components);return r.a.createElement(l.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},m=Object(a.forwardRef)((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=u(t),m=a,b=p["".concat(i,".").concat(m)]||p[m]||d[m]||o;return t?r.a.createElement(b,s({ref:n},l,{components:t})):r.a.createElement(b,s({ref:n},l))}));function b(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,i=new Array(o);i[0]=m;var s={};for(var c in n)hasOwnProperty.call(n,c)&&(s[c]=n[c]);s.originalType=e,s.mdxType="string"==typeof e?e:a,i[1]=s;for(var l=2;l1?arguments[1]:void 0,t),c=i>2?arguments[2]:void 0,l=void 0===c?t:r(c,t);l>s;)n[s++]=e;return n}},428:function(e,n,t){var a=t(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||t(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,n,t){"use strict";t(428);var a=t(0),r=t.n(a),o=t(424);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},430:function(e,n,t){"use strict";var a=t(1),r=t(0),o=t.n(r),i=t(39),s=t(432),c=t(20),l=t.n(c);n.a=function(e){var n,t=e.to,c=e.href,u=t||c,p=Object(s.a)(u),d=Object(r.useRef)(!1),m=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&p&&window.docusaurus.prefetch(u),function(){m&&n&&n.disconnect()}}),[u,m,p]),u&&p?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(u),d.current=!0)},innerRef:function(e){var t,a;m&&e&&p&&(t=e,a=function(){window.docusaurus.prefetch(u)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),a())}))}))).observe(t))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},431:function(e,n,t){"use strict";var a=t(0),r=t.n(a),o=t(430),i=t(423),s=t.n(i);t(133);n.a=function(e){var n=e.children,t=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,l=e.size,u=e.target,p=e.to,d=s()("jump-to","jump-to--"+l,t),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",n),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:p,target:u,className:d},m):r.a.createElement(o.a,{to:p,className:d},m)}},432:function(e,n,t){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/b79e7411.97c49087.js.LICENSE.txt b/b74d0aaa.77f8f8af.js.LICENSE.txt similarity index 100% rename from b79e7411.97c49087.js.LICENSE.txt rename to b74d0aaa.77f8f8af.js.LICENSE.txt diff --git a/b76eb9a9.97dac5fd.js b/b76eb9a9.372cd51e.js similarity index 92% rename from b76eb9a9.97dac5fd.js rename to b76eb9a9.372cd51e.js index f3f7a67e06..7e2686e77b 100644 --- a/b76eb9a9.97dac5fd.js +++ b/b76eb9a9.372cd51e.js @@ -1,2 +1,2 @@ -/*! For license information please see b76eb9a9.97dac5fd.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[181],{332:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return d}));var r=n(1),a=n(9),o=(n(0),n(422)),i=n(426),c=n(431),l={last_modified_on:"2023-03-31",$schema:"/.meta/.schemas/guides.json",title:"Customizing Preview URL with Qovery CLI",description:"How to customize preview url with qovery cli",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},u={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Customizing Preview URL with Qovery CLI",description:"How to customize preview url with qovery cli",permalink:"/guides/tutorial/customizing-preview-url-with-qovery-cli",readingTime:"3 min read",source:"@site/guides/tutorial/customizing-preview-url-with-qovery-cli.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Customizing Preview URL with Qovery CLI",truncated:!1,prevItem:{title:"Creating API clients using OpenAPI Tools",permalink:"/guides/tutorial/generate-qovery-api-client"},nextItem:{title:"Deploy API Gateway",permalink:"/guides/advanced/deploy-api-gateway"}},s=[{value:"Wrapping up",id:"wrapping-up",children:[]}],p={rightToc:s};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"In this quick guide, we will show you how to automatically customize your preview URL when a new environment has been created using the Qovery CLI. By following these steps, you can create a custom domain for your service and link it to your DNS provider."),Object(o.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI")," installed"),Object(o.b)("li",{parentName:"ul"},"Access to your DNS provider"))),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-custom-domain-for-your-service"},"Create a Custom Domain for Your Service"),Object(o.b)("p",null,"To create a custom domain for your service, run the following command in your terminal:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'# Get Pull Request ID from Qovery Environment Variables\n$ PR_ID=`qovery application env list -n "Backend" --show-values | grep "QOVERY_PROJECT_ID" | awk \'{print $10}\'`\n\n# Create a custom domain\n$ qovery application domain create -n "app name" --domain app-$PR_ID.domain.name\n')),Object(o.b)("p",null,"Replace ",Object(o.b)("inlineCode",{parentName:"p"},"app name")," with the name of your application and ",Object(o.b)("inlineCode",{parentName:"p"},"app.domain.name")," with your desired custom domain."),Object(o.b)("p",null,"User ",Object(o.b)("inlineCode",{parentName:"p"},"--organization"),", ",Object(o.b)("inlineCode",{parentName:"p"},"--project"),", ",Object(o.b)("inlineCode",{parentName:"p"},"--environment")," flags to specify the organization, project, and environment where you want to create the custom domain.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"retrieve-the-validation-domain"},"Retrieve the Validation Domain"),Object(o.b)("p",null,"To get the validation domain required for the next step, run the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ qovery application domain list -n "app name" | grep "app-$PR_ID.domain.name" | awk \'{print $7}\'\n')),Object(o.b)("p",null,"Replace ",Object(o.b)("inlineCode",{parentName:"p"},"app name")," and ",Object(o.b)("inlineCode",{parentName:"p"},"app.domain.name")," with the appropriate values. This command will output the validation domain.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-cname-record-in-your-dns-provider"},"Create a CNAME Record in Your DNS Provider"),Object(o.b)("p",null,"Use the validation domain from the previous step to create a CNAME record in your DNS provider. The CNAME record should point to the validation domain."),Object(o.b)("p",null,"Example with Route53:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ aws cli route53 change-resource-record-sets --hosted-zone-id "hosted zone id" --change-batch \'{"Changes":[{"Action":"CREATE","ResourceRecordSet":{"Name":"app-$PR_ID.domain.name","Type":"CNAME","TTL":300,"ResourceRecords":[{"Value":"validation-domain"}]}}]}\'\n')),Object(o.b)("p",null,"Example with Cloudflare:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records" \\\n -H "X-Auth-Email: {email}" \\\n -H "X-Auth-Key: {key}" \\\n -H "Content-Type: application/json" \\\n --data \'{"type":"CNAME","name":"app-$PR_ID.domain.name","content":"validation-domain","ttl":1,"proxied":false}\'\n')),Object(o.b)("p",null,"The idea here is to create a CNAME record that points to the validation domain. The validation domain is a temporary domain that is used to validate the ownership of the custom domain.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"redeploy-your-application"},"Redeploy your application"),Object(o.b)("p",null,"Once the DNS changes have propagated, redeploy your application to complete the process."),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ qovery application redeploy -n "app name" -w\n')),Object(o.b)("p",null,"Your application should now be available at ",Object(o.b)("inlineCode",{parentName:"p"},"app-{PR ID}.domain.name"),".")))),Object(o.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(o.b)("p",null,"Congratulations! You have successfully customized your preview URL using the Qovery CLI. Now, whenever a new environment is created, the custom domain will be automatically configured. If you encounter any issues, please reach out to our support team on the Qovery forum."))}d.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),m=r,b=p["".concat(i,".").concat(m)]||p[m]||d[m]||o;return n?a.a.createElement(b,c({ref:t},u,{components:n})):a.a.createElement(b,c({ref:t},u))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),s=Object(r.useState)(null),p=s[0],d=s[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see b76eb9a9.372cd51e.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[184],{335:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return d}));var r=n(1),a=n(9),o=(n(0),n(425)),i=n(429),c=n(434),l={last_modified_on:"2023-03-31",$schema:"/.meta/.schemas/guides.json",title:"Customizing Preview URL with Qovery CLI",description:"How to customize preview url with qovery cli",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},u={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Customizing Preview URL with Qovery CLI",description:"How to customize preview url with qovery cli",permalink:"/guides/tutorial/customizing-preview-url-with-qovery-cli",readingTime:"3 min read",source:"@site/guides/tutorial/customizing-preview-url-with-qovery-cli.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Customizing Preview URL with Qovery CLI",truncated:!1,prevItem:{title:"Creating API clients using OpenAPI Tools",permalink:"/guides/tutorial/generate-qovery-api-client"},nextItem:{title:"Deploy API Gateway",permalink:"/guides/advanced/deploy-api-gateway"}},s=[{value:"Wrapping up",id:"wrapping-up",children:[]}],p={rightToc:s};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"In this quick guide, we will show you how to automatically customize your preview URL when a new environment has been created using the Qovery CLI. By following these steps, you can create a custom domain for your service and link it to your DNS provider."),Object(o.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI")," installed"),Object(o.b)("li",{parentName:"ul"},"Access to your DNS provider"))),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-custom-domain-for-your-service"},"Create a Custom Domain for Your Service"),Object(o.b)("p",null,"To create a custom domain for your service, run the following command in your terminal:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'# Get Pull Request ID from Qovery Environment Variables\n$ PR_ID=`qovery application env list -n "Backend" --show-values | grep "QOVERY_PROJECT_ID" | awk \'{print $10}\'`\n\n# Create a custom domain\n$ qovery application domain create -n "app name" --domain app-$PR_ID.domain.name\n')),Object(o.b)("p",null,"Replace ",Object(o.b)("inlineCode",{parentName:"p"},"app name")," with the name of your application and ",Object(o.b)("inlineCode",{parentName:"p"},"app.domain.name")," with your desired custom domain."),Object(o.b)("p",null,"User ",Object(o.b)("inlineCode",{parentName:"p"},"--organization"),", ",Object(o.b)("inlineCode",{parentName:"p"},"--project"),", ",Object(o.b)("inlineCode",{parentName:"p"},"--environment")," flags to specify the organization, project, and environment where you want to create the custom domain.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"retrieve-the-validation-domain"},"Retrieve the Validation Domain"),Object(o.b)("p",null,"To get the validation domain required for the next step, run the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ qovery application domain list -n "app name" | grep "app-$PR_ID.domain.name" | awk \'{print $7}\'\n')),Object(o.b)("p",null,"Replace ",Object(o.b)("inlineCode",{parentName:"p"},"app name")," and ",Object(o.b)("inlineCode",{parentName:"p"},"app.domain.name")," with the appropriate values. This command will output the validation domain.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-cname-record-in-your-dns-provider"},"Create a CNAME Record in Your DNS Provider"),Object(o.b)("p",null,"Use the validation domain from the previous step to create a CNAME record in your DNS provider. The CNAME record should point to the validation domain."),Object(o.b)("p",null,"Example with Route53:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ aws cli route53 change-resource-record-sets --hosted-zone-id "hosted zone id" --change-batch \'{"Changes":[{"Action":"CREATE","ResourceRecordSet":{"Name":"app-$PR_ID.domain.name","Type":"CNAME","TTL":300,"ResourceRecords":[{"Value":"validation-domain"}]}}]}\'\n')),Object(o.b)("p",null,"Example with Cloudflare:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records" \\\n -H "X-Auth-Email: {email}" \\\n -H "X-Auth-Key: {key}" \\\n -H "Content-Type: application/json" \\\n --data \'{"type":"CNAME","name":"app-$PR_ID.domain.name","content":"validation-domain","ttl":1,"proxied":false}\'\n')),Object(o.b)("p",null,"The idea here is to create a CNAME record that points to the validation domain. The validation domain is a temporary domain that is used to validate the ownership of the custom domain.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"redeploy-your-application"},"Redeploy your application"),Object(o.b)("p",null,"Once the DNS changes have propagated, redeploy your application to complete the process."),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ qovery application redeploy -n "app name" -w\n')),Object(o.b)("p",null,"Your application should now be available at ",Object(o.b)("inlineCode",{parentName:"p"},"app-{PR ID}.domain.name"),".")))),Object(o.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(o.b)("p",null,"Congratulations! You have successfully customized your preview URL using the Qovery CLI. Now, whenever a new environment is created, the custom domain will be automatically configured. If you encounter any issues, please reach out to our support team on the Qovery forum."))}d.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),m=r,b=p["".concat(i,".").concat(m)]||p[m]||d[m]||o;return n?a.a.createElement(b,c({ref:t},u,{components:n})):a.a.createElement(b,c({ref:t},u))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),s=Object(r.useState)(null),p=s[0],d=s[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/b7d53051.48e12bb8.js.LICENSE.txt b/b76eb9a9.372cd51e.js.LICENSE.txt similarity index 100% rename from b7d53051.48e12bb8.js.LICENSE.txt rename to b76eb9a9.372cd51e.js.LICENSE.txt diff --git a/b795af1c.0ed9b0e4.js b/b795af1c.ecaec881.js similarity index 74% rename from b795af1c.0ed9b0e4.js rename to b795af1c.ecaec881.js index c1d9fe034b..c6590cd8d6 100644 --- a/b795af1c.0ed9b0e4.js +++ b/b795af1c.ecaec881.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[182],{333:function(s){s.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"cloud-provider-aws","name":"cloud_provider: aws","count":12,"permalink":"/guides/tags/cloud-provider-aws"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[185],{336:function(s){s.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"cloud-provider-aws","name":"cloud_provider: aws","count":12,"permalink":"/guides/tags/cloud-provider-aws"}')}}]); \ No newline at end of file diff --git a/b79e7411.97c49087.js b/b79e7411.de97bc02.js similarity index 85% rename from b79e7411.97c49087.js rename to b79e7411.de97bc02.js index 55d13c71eb..cf52fece11 100644 --- a/b79e7411.97c49087.js +++ b/b79e7411.de97bc02.js @@ -1,2 +1,2 @@ -/*! For license information please see b79e7411.97c49087.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[183],{334:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return u}));var r=n(1),a=n(9),o=(n(0),n(422)),i=(n(429),n(421),n(426),{last_modified_on:"2023-05-11",title:"Deployment Strategies",description:"Learn how to use the deployment strategies"}),c={id:"using-qovery/deployment/deployment-strategies",title:"Deployment Strategies",description:"Learn how to use the deployment strategies",source:"@site/docs/using-qovery/deployment/deployment-strategies.md",permalink:"/docs/using-qovery/deployment/deployment-strategies",sidebar:"docs",previous:{title:"Logs",permalink:"/docs/using-qovery/deployment/logs"},next:{title:"Image Mirroring",permalink:"/docs/using-qovery/deployment/image-mirroring"}},l=[],s={rightToc:l};function u(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery supports 2 ways of application deployment:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"RollingUpdate (default)"),": Qovery will gracefully rollout new versions. It will automatically rollback if the new version fails to start | Useful to avoid downtime and load spikes during update"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Recreate"),": Qovery will stop all current versions and create new ones once all old ones have been shutdown.")),Object(o.b)("p",null,"To make it more clear, here is a representation of the 2 strategies. First and default one, the ",Object(o.b)("strong",{parentName:"p"},"RollingUpdate")," strategy:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/advanced_settings/deployment_rolling_update.gif",alt:"Rolling update strategy"})),Object(o.b)("p",null,"And ",Object(o.b)("strong",{parentName:"p"},"Recreate")," deployment strategy:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/advanced_settings/deployment_recreate.gif",alt:"Recreate strategy"})))}u.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),m=r,d=p["".concat(i,".").concat(m)]||p[m]||f[m]||o;return n?a.a.createElement(d,c({ref:t},s,{components:n})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(430),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,p=Object(c.a)(u),f=Object(a.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!m&&p&&window.docusaurus.prefetch(u),function(){m&&t&&t.disconnect()}}),[u,m,p]),u&&p?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){f.current||(window.docusaurus.preload(u),f.current=!0)},innerRef:function(e){var n,r;m&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(r.a)({},e,{href:u}))}},429:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,f=c()("jump-to","jump-to--"+s,n),m=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?a.a.createElement("a",{href:p,target:u,className:f},m):a.a.createElement(o.a,{to:p,className:f},m)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file +/*! For license information please see b79e7411.de97bc02.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[186],{337:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return u}));var r=n(1),a=n(9),o=(n(0),n(425)),i=(n(431),n(424),n(429),{last_modified_on:"2023-05-11",title:"Deployment Strategies",description:"Learn how to use the deployment strategies"}),c={id:"using-qovery/deployment/deployment-strategies",title:"Deployment Strategies",description:"Learn how to use the deployment strategies",source:"@site/docs/using-qovery/deployment/deployment-strategies.md",permalink:"/docs/using-qovery/deployment/deployment-strategies",sidebar:"docs",previous:{title:"Logs",permalink:"/docs/using-qovery/deployment/logs"},next:{title:"Image Mirroring",permalink:"/docs/using-qovery/deployment/image-mirroring"}},l=[],s={rightToc:l};function u(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery supports 2 ways of application deployment:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"RollingUpdate (default)"),": Qovery will gracefully rollout new versions. It will automatically rollback if the new version fails to start | Useful to avoid downtime and load spikes during update"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Recreate"),": Qovery will stop all current versions and create new ones once all old ones have been shutdown.")),Object(o.b)("p",null,"To make it more clear, here is a representation of the 2 strategies. First and default one, the ",Object(o.b)("strong",{parentName:"p"},"RollingUpdate")," strategy:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/advanced_settings/deployment_rolling_update.gif",alt:"Rolling update strategy"})),Object(o.b)("p",null,"And ",Object(o.b)("strong",{parentName:"p"},"Recreate")," deployment strategy:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/advanced_settings/deployment_recreate.gif",alt:"Recreate strategy"})))}u.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),m=r,d=p["".concat(i,".").concat(m)]||p[m]||f[m]||o;return n?a.a.createElement(d,c({ref:t},s,{components:n})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(432),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,p=Object(c.a)(u),f=Object(a.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!m&&p&&window.docusaurus.prefetch(u),function(){m&&t&&t.disconnect()}}),[u,m,p]),u&&p?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){f.current||(window.docusaurus.preload(u),f.current=!0)},innerRef:function(e){var n,r;m&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(r.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,f=c()("jump-to","jump-to--"+s,n),m=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?a.a.createElement("a",{href:p,target:u,className:f},m):a.a.createElement(o.a,{to:p,className:f},m)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/b8490823.70e379af.js.LICENSE.txt b/b79e7411.de97bc02.js.LICENSE.txt similarity index 100% rename from b8490823.70e379af.js.LICENSE.txt rename to b79e7411.de97bc02.js.LICENSE.txt diff --git a/5e5fefd2.f91a8e6d.js b/b7d53051.d0a408ae.js similarity index 89% rename from 5e5fefd2.f91a8e6d.js rename to b7d53051.d0a408ae.js index 784b0ced00..95786bd08b 100644 --- a/5e5fefd2.f91a8e6d.js +++ b/b7d53051.d0a408ae.js @@ -1,2 +1,2 @@ -/*! For license information please see 5e5fefd2.f91a8e6d.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[109],{260:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),o=(n(0),n(422)),i=(n(431),n(426),n(421),{last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Deploy API Gateway",description:"Learn how to deploy an API Gateway with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),c={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Deploy API Gateway",description:"Learn how to deploy an API Gateway with Qovery",permalink:"/guides/advanced/deploy-api-gateway",readingTime:"1 min read",source:"@site/guides/advanced/deploy-api-gateway.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Deploy API Gateway",truncated:!1,prevItem:{title:"Customizing Preview URL with Qovery CLI",permalink:"/guides/tutorial/customizing-preview-url-with-qovery-cli"},nextItem:{title:"Deploy AWS Services",permalink:"/guides/advanced/deploy-aws-services"}},s=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],u={rightToc:s};function l(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"An API Gateway is a web service that acts as an interface between consumers and your services. It acts as a single point of entry into a system and is responsible for request routing, composition, and protocol translation. It's essentially a middleman that processes requests from clients to services."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to deploy your API Gateway with Qovery"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services/"}),"NGINX API Gateway")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services/"}),"Deploy a NGINX API Gateway with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=api%20gateway"}),'Forum "API Gateway"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=api%20gateway"}),'List "API Gateway" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}l.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),l=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),f=r,m=p["".concat(i,".").concat(f)]||p[f]||d[f]||o;return n?a.a.createElement(m,c({ref:t},u,{components:n})):a.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,u=void 0===s?n:a(s,n);u>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),p=l[0],d=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see b7d53051.d0a408ae.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[187],{338:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),o=(n(0),n(425)),i=(n(434),n(429),n(424),{last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Deploy API Gateway",description:"Learn how to deploy an API Gateway with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),c={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Deploy API Gateway",description:"Learn how to deploy an API Gateway with Qovery",permalink:"/guides/advanced/deploy-api-gateway",readingTime:"1 min read",source:"@site/guides/advanced/deploy-api-gateway.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Deploy API Gateway",truncated:!1,prevItem:{title:"Customizing Preview URL with Qovery CLI",permalink:"/guides/tutorial/customizing-preview-url-with-qovery-cli"},nextItem:{title:"Deploy AWS Services",permalink:"/guides/advanced/deploy-aws-services"}},s=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],u={rightToc:s};function l(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"An API Gateway is a web service that acts as an interface between consumers and your services. It acts as a single point of entry into a system and is responsible for request routing, composition, and protocol translation. It's essentially a middleman that processes requests from clients to services."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to deploy your API Gateway with Qovery"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services/"}),"NGINX API Gateway")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services/"}),"Deploy a NGINX API Gateway with Qovery")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=api%20gateway"}),'Forum "API Gateway"')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=api%20gateway"}),'List "API Gateway" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}l.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),l=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),f=r,m=p["".concat(i,".").concat(f)]||p[f]||d[f]||o;return n?a.a.createElement(m,c({ref:t},u,{components:n})):a.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,u=void 0===s?n:a(s,n);u>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),p=l[0],d=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/b8d420d8.048b5eb8.js.LICENSE.txt b/b7d53051.d0a408ae.js.LICENSE.txt similarity index 100% rename from b8d420d8.048b5eb8.js.LICENSE.txt rename to b7d53051.d0a408ae.js.LICENSE.txt diff --git a/b8490823.70e379af.js b/b8490823.4ee41491.js similarity index 91% rename from b8490823.70e379af.js rename to b8490823.4ee41491.js index d341cdaf0e..927acd8da6 100644 --- a/b8490823.70e379af.js +++ b/b8490823.4ee41491.js @@ -1,2 +1,2 @@ -/*! For license information please see b8490823.70e379af.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[185],{336:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var i=n(1),a=n(9),r=(n(0),n(422)),o=(n(429),n(421)),c=(n(426),{last_modified_on:"2023-05-27",title:"Audit Logs",description:"Learn how to access the audit logs"}),l={id:"using-qovery/audit-logs",title:"Audit Logs",description:"Learn how to access the audit logs",source:"@site/docs/using-qovery/audit-logs.md",permalink:"/docs/using-qovery/audit-logs",sidebar:"docs",previous:{title:"Cluster Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/cluster-troubleshoot"},next:{title:"Maintenance",permalink:"/docs/using-qovery/maintenance"}},s=[{value:"Event information",id:"event-information",children:[]},{value:"Filters",id:"filters",children:[{value:"Quick Filters",id:"quick-filters",children:[]}]},{value:"Export",id:"export",children:[]}],u={rightToc:s};function p(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(r.b)("wrapper",Object(i.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"This feature is available in ",Object(r.b)("strong",{parentName:"p"},"public beta"),". Access and functionalities might change in the future based on your Qovery Plan.")),Object(r.b)("p",null,'Qovery allows you to monitor any action happened within your organization thanks to the audit logs section. This section provides you with a complete view on any change happened within your organization configuration, providing you the answer to "who did what, where, and when?".'),Object(r.b)("p",null,"This is extremely useful when debugging complex issues and trying to understand what happened in a specific timeframe or monitor the actions done by your users within your organization."),Object(r.b)("p",null,"You can access this section by opening the ",Object(r.b)("inlineCode",{parentName:"p"},"Audit logs")," section from the nav bar on the left"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/audit-logs/audit-logs-access.png",alt:"Audit Logs Access"})),Object(r.b)("p",null,"Once entered this section, you will find here the list of events happened within your organization over the past ",Object(r.b)("strong",{parentName:"p"},"30 days")," (this is the maximum retention time)."),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"From a technical point of view, Qovery tracks in the audit logs any call happening on our API for your organization. Example: if you modify the configuration of an application via the Qovery console, Qovery will track the call to the api endpoint ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"https://api-doc.qovery.com/#tag/Application-Main-Calls/operation/editApplication"}),"/application")," and log an ",Object(r.b)("strong",{parentName:"p"},"UPDATE")," event.")),Object(r.b)("h2",{id:"event-information"},"Event information"),Object(r.b)("p",null,"Each event in the list is composed by the following information:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"Timestamp"),": it tells you ",Object(r.b)("inlineCode",{parentName:"li"},"when")," the event happened"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"Event Type"),": it describe the type of event (Create, Update, Delete, Trigger Deployment etc..)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"Target Type"),": it defines the type of object that has been modified (Environment, Cluster, Role, Image registry etc..)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"Target"),": it defines the object that has been modified. You can get additional information on the target by hovering on it."),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"Change"),": it describes ",Object(r.b)("inlineCode",{parentName:"li"},"what")," has been modified (high level information: its config, a deployment rule etc..)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"User"),": it describes ",Object(r.b)("inlineCode",{parentName:"li"},"who")," modified the object. If the change has been done via API, you will find the ",Object(r.b)("a",Object(i.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/api-token/"}),Object(r.b)("inlineCode",{parentName:"a"},"API token"))," name that has changed it."),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"Tool"),": it describes ",Object(r.b)("inlineCode",{parentName:"li"},"how")," the object has been changed (via the console, the qovery terraform provider, via a git push etc..)")),Object(r.b)("p",null,"Since the audit logs are based on the calls done on our API, Qovery provides you with the JSON sent in the API response for each API call (and thus, for each event). This JSON represents the status of the target object ",Object(r.b)("strong",{parentName:"p"},"after")," the event has happened. You can access the JSON by clicking on the event and might be useful to get a more granular information of what has changed between two events of the same type by comparing their JSON."),Object(r.b)("p",null,"Example: if an update happened on the configuration of an application , the stored ",Object(r.b)("inlineCode",{parentName:"p"},"UPDATE")," event will provide you access to the JSON returned by the API when the ",Object(r.b)("inlineCode",{parentName:"p"},"/application")," endpoint was called. This JSON will thus contain the configuration of the application after the update."),Object(r.b)("h2",{id:"filters"},"Filters"),Object(r.b)("p",null,"To simplify the research within the audit logs, you can filter the events by:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Time range"),Object(r.b)("li",{parentName:"ul"},"Target: you will have to specify a target type (cluster, environment, service etc..) and then specify the name of the target. For example, if you want to look for the changes happened on the cluster ",Object(r.b)("inlineCode",{parentName:"li"},"Production"),", you will have to select ",Object(r.b)("inlineCode",{parentName:"li"},"Cluster")," as Target type and then you will have to select ",Object(r.b)("inlineCode",{parentName:"li"},"Production")," from within the cluster list.")),Object(r.b)("h3",{id:"quick-filters"},"Quick Filters"),Object(r.b)("p",null,"While navigating within the console, a few quick filters allow you to jump on the audit logs and get the events happened on that specific object. For example, you can quickly get the events happened on a specific environment, by clicking on the ",Object(r.b)("inlineCode",{parentName:"p"},"See Events")," button available within the ",Object(r.b)("inlineCode",{parentName:"p"},"3 dots")," sub-menu"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/audit-logs/see-events.png",alt:"See Events Quick Filter"})),Object(r.b)("h2",{id:"export"},"Export"),Object(r.b)("p",null,"Not yet available, feature coming soon!"))}p.isMDXComponent=!0},420:function(e,t,n){var i;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},h=Object(i.forwardRef)((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),h=i,d=p["".concat(o,".").concat(h)]||p[h]||b[h]||r;return n?a.a.createElement(d,c({ref:t},s,{components:n})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=h;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:i,o[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=o>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var i=n(28).f,a=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in a||n(10)&&i(a,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var i=n(0),a=n.n(i),r=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var i=n(1),a=n(0),r=n.n(a),o=n(39),c=n(430),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,p=Object(c.a)(u),b=Object(a.useRef)(!1),h=s.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!h&&p&&window.docusaurus.prefetch(u),function(){h&&t&&t.disconnect()}}),[u,h,p]),u&&p?r.a.createElement(o.b,Object(i.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,i;h&&e&&p&&(n=e,i=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),i())}))}))).observe(n))},to:u})):r.a.createElement("a",Object(i.a)({},e,{href:u}))}},429:function(e,t,n){"use strict";var i=n(0),a=n.n(i),r=n(427),o=n(420),c=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,i=e.badge,o=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+s,n),h=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},o&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+o})),a.a.createElement("div",{className:"jump-to--main"},i?a.a.createElement("span",{className:"badge badge--primary badge--right"},i):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?a.a.createElement("a",{href:p,target:u,className:b},h):a.a.createElement(r.a,{to:p,className:b},h)}},430:function(e,t,n){"use strict";function i(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return i}))}}]); \ No newline at end of file +/*! For license information please see b8490823.4ee41491.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[188],{339:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var i=n(1),a=n(9),r=(n(0),n(425)),o=(n(431),n(424)),c=(n(429),{last_modified_on:"2023-05-27",title:"Audit Logs",description:"Learn how to access the audit logs"}),l={id:"using-qovery/audit-logs",title:"Audit Logs",description:"Learn how to access the audit logs",source:"@site/docs/using-qovery/audit-logs.md",permalink:"/docs/using-qovery/audit-logs",sidebar:"docs",previous:{title:"Cluster Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/cluster-troubleshoot"},next:{title:"Maintenance",permalink:"/docs/using-qovery/maintenance"}},s=[{value:"Event information",id:"event-information",children:[]},{value:"Filters",id:"filters",children:[{value:"Quick Filters",id:"quick-filters",children:[]}]},{value:"Export",id:"export",children:[]}],u={rightToc:s};function p(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(r.b)("wrapper",Object(i.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"This feature is available in ",Object(r.b)("strong",{parentName:"p"},"public beta"),". Access and functionalities might change in the future based on your Qovery Plan.")),Object(r.b)("p",null,'Qovery allows you to monitor any action happened within your organization thanks to the audit logs section. This section provides you with a complete view on any change happened within your organization configuration, providing you the answer to "who did what, where, and when?".'),Object(r.b)("p",null,"This is extremely useful when debugging complex issues and trying to understand what happened in a specific timeframe or monitor the actions done by your users within your organization."),Object(r.b)("p",null,"You can access this section by opening the ",Object(r.b)("inlineCode",{parentName:"p"},"Audit logs")," section from the nav bar on the left"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/audit-logs/audit-logs-access.png",alt:"Audit Logs Access"})),Object(r.b)("p",null,"Once entered this section, you will find here the list of events happened within your organization over the past ",Object(r.b)("strong",{parentName:"p"},"30 days")," (this is the maximum retention time)."),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"From a technical point of view, Qovery tracks in the audit logs any call happening on our API for your organization. Example: if you modify the configuration of an application via the Qovery console, Qovery will track the call to the api endpoint ",Object(r.b)("a",Object(i.a)({parentName:"p"},{href:"https://api-doc.qovery.com/#tag/Application-Main-Calls/operation/editApplication"}),"/application")," and log an ",Object(r.b)("strong",{parentName:"p"},"UPDATE")," event.")),Object(r.b)("h2",{id:"event-information"},"Event information"),Object(r.b)("p",null,"Each event in the list is composed by the following information:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"Timestamp"),": it tells you ",Object(r.b)("inlineCode",{parentName:"li"},"when")," the event happened"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"Event Type"),": it describe the type of event (Create, Update, Delete, Trigger Deployment etc..)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"Target Type"),": it defines the type of object that has been modified (Environment, Cluster, Role, Image registry etc..)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"Target"),": it defines the object that has been modified. You can get additional information on the target by hovering on it."),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"Change"),": it describes ",Object(r.b)("inlineCode",{parentName:"li"},"what")," has been modified (high level information: its config, a deployment rule etc..)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"User"),": it describes ",Object(r.b)("inlineCode",{parentName:"li"},"who")," modified the object. If the change has been done via API, you will find the ",Object(r.b)("a",Object(i.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/api-token/"}),Object(r.b)("inlineCode",{parentName:"a"},"API token"))," name that has changed it."),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"Tool"),": it describes ",Object(r.b)("inlineCode",{parentName:"li"},"how")," the object has been changed (via the console, the qovery terraform provider, via a git push etc..)")),Object(r.b)("p",null,"Since the audit logs are based on the calls done on our API, Qovery provides you with the JSON sent in the API response for each API call (and thus, for each event). This JSON represents the status of the target object ",Object(r.b)("strong",{parentName:"p"},"after")," the event has happened. You can access the JSON by clicking on the event and might be useful to get a more granular information of what has changed between two events of the same type by comparing their JSON."),Object(r.b)("p",null,"Example: if an update happened on the configuration of an application , the stored ",Object(r.b)("inlineCode",{parentName:"p"},"UPDATE")," event will provide you access to the JSON returned by the API when the ",Object(r.b)("inlineCode",{parentName:"p"},"/application")," endpoint was called. This JSON will thus contain the configuration of the application after the update."),Object(r.b)("h2",{id:"filters"},"Filters"),Object(r.b)("p",null,"To simplify the research within the audit logs, you can filter the events by:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Time range"),Object(r.b)("li",{parentName:"ul"},"Target: you will have to specify a target type (cluster, environment, service etc..) and then specify the name of the target. For example, if you want to look for the changes happened on the cluster ",Object(r.b)("inlineCode",{parentName:"li"},"Production"),", you will have to select ",Object(r.b)("inlineCode",{parentName:"li"},"Cluster")," as Target type and then you will have to select ",Object(r.b)("inlineCode",{parentName:"li"},"Production")," from within the cluster list.")),Object(r.b)("h3",{id:"quick-filters"},"Quick Filters"),Object(r.b)("p",null,"While navigating within the console, a few quick filters allow you to jump on the audit logs and get the events happened on that specific object. For example, you can quickly get the events happened on a specific environment, by clicking on the ",Object(r.b)("inlineCode",{parentName:"p"},"See Events")," button available within the ",Object(r.b)("inlineCode",{parentName:"p"},"3 dots")," sub-menu"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/configuration/audit-logs/see-events.png",alt:"See Events Quick Filter"})),Object(r.b)("h2",{id:"export"},"Export"),Object(r.b)("p",null,"Not yet available, feature coming soon!"))}p.isMDXComponent=!0},423:function(e,t,n){var i;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},h=Object(i.forwardRef)((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),h=i,d=p["".concat(o,".").concat(h)]||p[h]||b[h]||r;return n?a.a.createElement(d,c({ref:t},s,{components:n})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=h;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:i,o[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=o>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var i=n(28).f,a=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in a||n(10)&&i(a,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var i=n(0),a=n.n(i),r=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var i=n(1),a=n(0),r=n.n(a),o=n(39),c=n(432),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,p=Object(c.a)(u),b=Object(a.useRef)(!1),h=s.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!h&&p&&window.docusaurus.prefetch(u),function(){h&&t&&t.disconnect()}}),[u,h,p]),u&&p?r.a.createElement(o.b,Object(i.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,i;h&&e&&p&&(n=e,i=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),i())}))}))).observe(n))},to:u})):r.a.createElement("a",Object(i.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var i=n(0),a=n.n(i),r=n(430),o=n(423),c=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,i=e.badge,o=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+s,n),h=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},o&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+o})),a.a.createElement("div",{className:"jump-to--main"},i?a.a.createElement("span",{className:"badge badge--primary badge--right"},i):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?a.a.createElement("a",{href:p,target:u,className:b},h):a.a.createElement(r.a,{to:p,className:b},h)}},432:function(e,t,n){"use strict";function i(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return i}))}}]); \ No newline at end of file diff --git a/b98931a2.3dce09ef.js.LICENSE.txt b/b8490823.4ee41491.js.LICENSE.txt similarity index 100% rename from b98931a2.3dce09ef.js.LICENSE.txt rename to b8490823.4ee41491.js.LICENSE.txt diff --git a/b8d420d8.048b5eb8.js b/b8d420d8.ff5f8dbe.js similarity index 87% rename from b8d420d8.048b5eb8.js rename to b8d420d8.ff5f8dbe.js index 91aea462d4..2a1578c515 100644 --- a/b8d420d8.048b5eb8.js +++ b/b8d420d8.ff5f8dbe.js @@ -1,2 +1,2 @@ -/*! For license information please see b8d420d8.048b5eb8.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[186],{337:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return a})),r.d(t,"metadata",(function(){return c})),r.d(t,"rightToc",(function(){return u})),r.d(t,"default",(function(){return l}));var n=r(1),o=r(9),i=(r(0),r(422)),a=(r(431),r(421),r(426),{last_modified_on:"2023-11-25",title:"Other Cloud Service Provider",description:"Learn how to configure Qovery on any Cloud Service Provider"}),c={id:"using-qovery/configuration/cloud-service-provider/other-csps",title:"Other Cloud Service Provider",description:"Learn how to configure Qovery on any Cloud Service Provider",source:"@site/docs/using-qovery/configuration/cloud-service-provider/other-csps.md",permalink:"/docs/using-qovery/configuration/cloud-service-provider/other-csps",sidebar:"docs",previous:{title:"Scaleway (SCW)",permalink:"/docs/using-qovery/configuration/cloud-service-provider/scaleway"},next:{title:"Provider",permalink:"/docs/using-qovery/configuration/provider"}},u=[],s={rightToc:u};function l(e){var t=e.components,r=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Are you looking to install Qovery on a cloud provider that is not listed?"),Object(i.b)("blockquote",null,Object(i.b)("p",{parentName:"blockquote"},Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/provider/kubernetes/"}),"Check out how you can install Qovery on any cloud provider by installing it on Kubernetes"))))}l.isMDXComponent=!0},420:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},f=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,a=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),f=l(r),d=n,v=f["".concat(a,".").concat(d)]||f[d]||p[d]||i;return r?o.a.createElement(v,c({ref:t},s,{components:r})):o.a.createElement(v,c({ref:t},s))}));function v(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,a=new Array(i);a[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,a[1]=c;for(var s=2;s1?arguments[1]:void 0,r),u=a>2?arguments[2]:void 0,s=void 0===u?r:o(u,r);s>c;)t[c++]=e;return t}},425:function(e,t,r){var n=r(28).f,o=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in o||r(10)&&n(o,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},426:function(e,t,r){"use strict";r(425);var n=r(0),o=r.n(n),i=r(421);t.a=function(e){var t=e.children,r=e.name;return o.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},428:function(e,t,r){"use strict";var n=r(432),o=r(51);function i(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=o({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),r(decodeURIComponent(o),i,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[i(t,e),"[",n,"]"].join(""):[i(t,e),"[",i(n,e),"]=",i(r,e)].join("")};case"bracket":return function(t,r){return null===r?i(t,e):[i(t,e),"[]=",i(r,e)].join("")};default:return function(t,r){return null===r?i(t,e):[i(t,e),"=",i(r,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var o=e[n];if(void 0===o)return"";if(null===o)return i(n,t);if(Array.isArray(o)){var a=[];return o.slice().forEach((function(e){void 0!==e&&a.push(r(n,e,a.length))})),a.join("&")}return i(n,t)+"="+i(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,r){"use strict";var n=r(0),o=r.n(n),i=(r(420),r(428)),a=r.n(i);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,i=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(u),l=Object(n.useState)(null),f=l[0],p=l[1];return o.a.createElement("div",{className:"steps steps--h"+r},t,!i&&!f&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see b8d420d8.ff5f8dbe.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[189],{340:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return a})),r.d(t,"metadata",(function(){return c})),r.d(t,"rightToc",(function(){return u})),r.d(t,"default",(function(){return l}));var n=r(1),o=r(9),i=(r(0),r(425)),a=(r(434),r(424),r(429),{last_modified_on:"2023-11-25",title:"Other Cloud Service Provider",description:"Learn how to configure Qovery on any Cloud Service Provider"}),c={id:"using-qovery/configuration/cloud-service-provider/other-csps",title:"Other Cloud Service Provider",description:"Learn how to configure Qovery on any Cloud Service Provider",source:"@site/docs/using-qovery/configuration/cloud-service-provider/other-csps.md",permalink:"/docs/using-qovery/configuration/cloud-service-provider/other-csps",sidebar:"docs",previous:{title:"Scaleway (SCW)",permalink:"/docs/using-qovery/configuration/cloud-service-provider/scaleway"},next:{title:"Provider",permalink:"/docs/using-qovery/configuration/provider"}},u=[],s={rightToc:u};function l(e){var t=e.components,r=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Are you looking to install Qovery on a cloud provider that is not listed?"),Object(i.b)("blockquote",null,Object(i.b)("p",{parentName:"blockquote"},Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/provider/kubernetes/"}),"Check out how you can install Qovery on any cloud provider by installing it on Kubernetes"))))}l.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},f=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,a=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),f=l(r),d=n,v=f["".concat(a,".").concat(d)]||f[d]||p[d]||i;return r?o.a.createElement(v,c({ref:t},s,{components:r})):o.a.createElement(v,c({ref:t},s))}));function v(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,a=new Array(i);a[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,a[1]=c;for(var s=2;s1?arguments[1]:void 0,r),u=a>2?arguments[2]:void 0,s=void 0===u?r:o(u,r);s>c;)t[c++]=e;return t}},428:function(e,t,r){var n=r(28).f,o=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in o||r(10)&&n(o,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,t,r){"use strict";r(428);var n=r(0),o=r.n(n),i=r(424);t.a=function(e){var t=e.children,r=e.name;return o.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},433:function(e,t,r){"use strict";var n=r(435),o=r(51);function i(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=o({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),r(decodeURIComponent(o),i,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[i(t,e),"[",n,"]"].join(""):[i(t,e),"[",i(n,e),"]=",i(r,e)].join("")};case"bracket":return function(t,r){return null===r?i(t,e):[i(t,e),"[]=",i(r,e)].join("")};default:return function(t,r){return null===r?i(t,e):[i(t,e),"=",i(r,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var o=e[n];if(void 0===o)return"";if(null===o)return i(n,t);if(Array.isArray(o)){var a=[];return o.slice().forEach((function(e){void 0!==e&&a.push(r(n,e,a.length))})),a.join("&")}return i(n,t)+"="+i(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,r){"use strict";var n=r(0),o=r.n(n),i=(r(423),r(433)),a=r.n(i);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,i=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(u),l=Object(n.useState)(null),f=l[0],p=l[1];return o.a.createElement("div",{className:"steps steps--h"+r},t,!i&&!f&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/ba43933d.a692223e.js.LICENSE.txt b/b8d420d8.ff5f8dbe.js.LICENSE.txt similarity index 100% rename from ba43933d.a692223e.js.LICENSE.txt rename to b8d420d8.ff5f8dbe.js.LICENSE.txt diff --git a/b98931a2.3dce09ef.js b/b98931a2.83cec4bc.js similarity index 89% rename from b98931a2.3dce09ef.js rename to b98931a2.83cec4bc.js index 1b10683c06..fb1a3e9076 100644 --- a/b98931a2.3dce09ef.js +++ b/b98931a2.83cec4bc.js @@ -1,2 +1,2 @@ -/*! For license information please see b98931a2.3dce09ef.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[187],{338:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return c})),t.d(r,"metadata",(function(){return l})),t.d(r,"rightToc",(function(){return s})),t.d(r,"default",(function(){return p}));var n=t(1),a=t(9),i=(t(0),t(422)),o=t(421),c={last_modified_on:"2021-07-26",title:"Backup and Restore",description:"Your data are safe and can be easily restored"},l={id:"security-and-compliance/backup-and-restore",title:"Backup and Restore",description:"Your data are safe and can be easily restored",source:"@site/docs/security-and-compliance/backup-and-restore.md",permalink:"/docs/security-and-compliance/backup-and-restore",sidebar:"docs",previous:{title:"Security and Compliance",permalink:"/docs/security-and-compliance"},next:{title:"Encryption",permalink:"/docs/security-and-compliance/encryption"}},s=[{value:"Backups",id:"backups",children:[{value:"Applications",id:"applications",children:[]},{value:"Services",id:"services",children:[]}]},{value:"Restore",id:"restore",children:[{value:"Applications",id:"applications-1",children:[]},{value:"Services",id:"services-1",children:[]}]}],u={rightToc:s};function p(e){var r=e.components,t=Object(a.a)(e,["components"]);return Object(i.b)("wrapper",Object(n.a)({},u,t,{components:r,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Backups and restore are frequently a nightmare to setup. Especially for databases. Qovery helps you to get this part ",Object(i.b)("strong",{parentName:"p"},"always automatically managed by the Cloud provider"),"."),Object(i.b)("h2",{id:"backups"},"Backups"),Object(i.b)("h3",{id:"applications"},"Applications"),Object(i.b)("p",null,"When containers' applications are successfully built, ",Object(i.b)("strong",{parentName:"p"},"all containers are kept for possible future rollback"),"."),Object(i.b)("h3",{id:"services"},"Services"),Object(i.b)("p",null,"Take a look at the desired service to know how they are backed up."),Object(i.b)("h2",{id:"restore"},"Restore"),Object(i.b)("h3",{id:"applications-1"},"Applications"),Object(i.b)("p",null,"As the Qovery configuration file is in your git repository and versioned, you can rollback any version when you want."),Object(i.b)(o.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"When you rollback a commit containing a Qovery configuration change, ensure there are no other changes to avoid unwanted behavior.")),Object(i.b)("h3",{id:"services-1"},"Services"),Object(i.b)("p",null,"Take a look at the desired service to know how you can restore it."))}p.isMDXComponent=!0},420:function(e,r,t){var n;!function(){"use strict";var t={}.hasOwnProperty;function a(){for(var e=[],r=0;r=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=a.a.createContext({}),u=function(e){var r=a.a.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},p=function(e){var r=u(e.components);return a.a.createElement(s.Provider,{value:r},e.children)},d={inlineCode:"code",wrapper:function(e){var r=e.children;return a.a.createElement(a.a.Fragment,{},r)}},f=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,i=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(t),f=n,b=p["".concat(o,".").concat(f)]||p[f]||d[f]||i;return t?a.a.createElement(b,c({ref:r},s,{components:t})):a.a.createElement(b,c({ref:r},s))}));function b(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var i=t.length,o=new Array(i);o[0]=f;var c={};for(var l in r)hasOwnProperty.call(r,l)&&(c[l]=r[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,o[1]=c;for(var s=2;s1?arguments[1]:void 0,t),l=o>2?arguments[2]:void 0,s=void 0===l?t:a(l,t);s>c;)r[c++]=e;return r}}}]); \ No newline at end of file +/*! For license information please see b98931a2.83cec4bc.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[190],{341:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return c})),t.d(r,"metadata",(function(){return l})),t.d(r,"rightToc",(function(){return s})),t.d(r,"default",(function(){return p}));var n=t(1),a=t(9),i=(t(0),t(425)),o=t(424),c={last_modified_on:"2021-07-26",title:"Backup and Restore",description:"Your data are safe and can be easily restored"},l={id:"security-and-compliance/backup-and-restore",title:"Backup and Restore",description:"Your data are safe and can be easily restored",source:"@site/docs/security-and-compliance/backup-and-restore.md",permalink:"/docs/security-and-compliance/backup-and-restore",sidebar:"docs",previous:{title:"Security and Compliance",permalink:"/docs/security-and-compliance"},next:{title:"Encryption",permalink:"/docs/security-and-compliance/encryption"}},s=[{value:"Backups",id:"backups",children:[{value:"Applications",id:"applications",children:[]},{value:"Services",id:"services",children:[]}]},{value:"Restore",id:"restore",children:[{value:"Applications",id:"applications-1",children:[]},{value:"Services",id:"services-1",children:[]}]}],u={rightToc:s};function p(e){var r=e.components,t=Object(a.a)(e,["components"]);return Object(i.b)("wrapper",Object(n.a)({},u,t,{components:r,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Backups and restore are frequently a nightmare to setup. Especially for databases. Qovery helps you to get this part ",Object(i.b)("strong",{parentName:"p"},"always automatically managed by the Cloud provider"),"."),Object(i.b)("h2",{id:"backups"},"Backups"),Object(i.b)("h3",{id:"applications"},"Applications"),Object(i.b)("p",null,"When containers' applications are successfully built, ",Object(i.b)("strong",{parentName:"p"},"all containers are kept for possible future rollback"),"."),Object(i.b)("h3",{id:"services"},"Services"),Object(i.b)("p",null,"Take a look at the desired service to know how they are backed up."),Object(i.b)("h2",{id:"restore"},"Restore"),Object(i.b)("h3",{id:"applications-1"},"Applications"),Object(i.b)("p",null,"As the Qovery configuration file is in your git repository and versioned, you can rollback any version when you want."),Object(i.b)(o.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"When you rollback a commit containing a Qovery configuration change, ensure there are no other changes to avoid unwanted behavior.")),Object(i.b)("h3",{id:"services-1"},"Services"),Object(i.b)("p",null,"Take a look at the desired service to know how you can restore it."))}p.isMDXComponent=!0},423:function(e,r,t){var n;!function(){"use strict";var t={}.hasOwnProperty;function a(){for(var e=[],r=0;r=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=a.a.createContext({}),u=function(e){var r=a.a.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},p=function(e){var r=u(e.components);return a.a.createElement(s.Provider,{value:r},e.children)},d={inlineCode:"code",wrapper:function(e){var r=e.children;return a.a.createElement(a.a.Fragment,{},r)}},f=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,i=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(t),f=n,b=p["".concat(o,".").concat(f)]||p[f]||d[f]||i;return t?a.a.createElement(b,c({ref:r},s,{components:t})):a.a.createElement(b,c({ref:r},s))}));function b(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var i=t.length,o=new Array(i);o[0]=f;var c={};for(var l in r)hasOwnProperty.call(r,l)&&(c[l]=r[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,o[1]=c;for(var s=2;s1?arguments[1]:void 0,t),l=o>2?arguments[2]:void 0,s=void 0===l?t:a(l,t);s>c;)r[c++]=e;return r}}}]); \ No newline at end of file diff --git a/bbedfc29.f41e01be.js.LICENSE.txt b/b98931a2.83cec4bc.js.LICENSE.txt similarity index 100% rename from bbedfc29.f41e01be.js.LICENSE.txt rename to b98931a2.83cec4bc.js.LICENSE.txt diff --git a/ba43933d.a692223e.js b/ba43933d.f7fa6d7a.js similarity index 91% rename from ba43933d.a692223e.js rename to ba43933d.f7fa6d7a.js index d54f9e37ee..13abe56214 100644 --- a/ba43933d.a692223e.js +++ b/ba43933d.f7fa6d7a.js @@ -1,2 +1,2 @@ -/*! For license information please see ba43933d.a692223e.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[188],{339:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var a=n(1),r=n(9),o=(n(0),n(422)),i=n(421),l=(n(426),n(429),{last_modified_on:"2023-12-12",$schema:"/.meta/.schemas/guides.json",title:"Setting up Cloudflare and Custom Domain on Qovery",description:"Using Cloudflare for applications deployed on Qovery",author_github:"https://github.com/jul-dan",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Setting up Cloudflare and Custom Domain on Qovery",description:"Using Cloudflare for applications deployed on Qovery",permalink:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery",readingTime:"4 min read",source:"@site/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Setting up Cloudflare and Custom Domain on Qovery",truncated:!1,prevItem:{title:"Seed Database",permalink:"/guides/advanced/seed-database"},nextItem:{title:"Setup VPC peering on AWS with Qovery",permalink:"/guides/tutorial/aws-vpc-peering-with-qovery"}},u=[{value:"Adding a Custom Domain",id:"adding-a-custom-domain",children:[]},{value:"Cloudflare Configuration",id:"cloudflare-configuration",children:[{value:"CNAME",id:"cname",children:[]},{value:"SSL/TLS",id:"ssltls",children:[]},{value:"Restrict application access",id:"restrict-application-access",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],s={rightToc:u};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"The guide assumes that you have an application up and running on Qovery. We'll go through the process of adding a new Custom Domain to the application and use Cloudflare as the domain provider. We also assume that you own a custom domain on Cloudflare (or any other domain registrar):"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/1.png",alt:"Cloudflare"})),Object(o.b)("h2",{id:"adding-a-custom-domain"},"Adding a Custom Domain"),Object(o.b)("p",null,"First, let's open application settings:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/2.png",alt:"Cloudflare"})),Object(o.b)("p",null,"Add your Cloudflare managed domain in ",Object(o.b)("inlineCode",{parentName:"p"},"Domain")," section:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/3.png",alt:"Cloudflare"})),Object(o.b)("h2",{id:"cloudflare-configuration"},"Cloudflare Configuration"),Object(o.b)("h3",{id:"cname"},"CNAME"),Object(o.b)("p",null,"To finish the configuration on Cloudfalre, open the DNS Settings:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/4.png",alt:"Cloudflare"})),Object(o.b)("p",null,"And add a CNAME entry with the value taken from the Qovery Console just like this:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/5.png",alt:"Cloudflare"})),Object(o.b)("p",null,"You can safely use the ",Object(o.b)("inlineCode",{parentName:"p"},"Proxy")," mode."),Object(o.b)("h3",{id:"ssltls"},"SSL/TLS"),Object(o.b)("p",null,"The last step to configure the domain Cloudflare side properly, is to use the ",Object(o.b)("inlineCode",{parentName:"p"},"Full")," TLS encryption:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/6.png",alt:"Cloudflare"})),Object(o.b)("p",null,"This is the requirement to make Custom Domain work properly using Cloudflare as the domain provider on Qovery."),Object(o.b)("h3",{id:"restrict-application-access"},"Restrict application access"),Object(o.b)("p",null,"If you want to limit the application access via Cloudflare only, you have two ways to perform it:"),Object(o.b)("h4",{id:"ip-whitelisting"},"IP whitelisting"),Object(o.b)("p",null,"In Qovery it is possible to whitelist a range of IPs that can reach your application:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"In the advanced settings section of your application:",Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/8.png",alt:"Cloudflare"}))),Object(o.b)("li",{parentName:"ul"},"Get the ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.cloudflare.com/ips-v4/"}),"Cloudflare ips")),Object(o.b)("li",{parentName:"ul"},"Edit the ",Object(o.b)("inlineCode",{parentName:"li"},"network.ingress.whitelist_source_range")," setting and add the Cloudflare IPs separated with a comma:",Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/9.png",alt:"Cloudflare"}))),Object(o.b)("li",{parentName:"ul"},"Save and redeploy your application")),Object(o.b)("h4",{id:"cloudflared"},"Cloudflared"),Object(o.b)("p",null,"Cloudflared establishes outbound connections (tunnels) between your resources and Cloudflare\u2019s global network."),Object(o.b)("p",null,"You have different ways to install Cloudflared on your cluster, you can find the installation instructions within this ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel/"}),"documentation"),"\nSince Cloudflared establishes a tunnel for you and the domain and TLS management is done by Cloudflare, you don't need to expose publicly the application during the setup (See ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#ports"}),"port setup")),Object(o.b)("p",null,"You can decide to install Cloudflared by yourself or via Qovery. Within the section below, you will find documentation on how to install Cloudflared as a container in one of the Qovery environments.\nBy creating and deploying the following service, using the Cloudflared image:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/10.png",alt:"Cloudflare"})),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Create a ",Object(o.b)("inlineCode",{parentName:"p"},"TUNNEL_TOKEN")," secret environment variable (Scope: Environment) to pass the Cloudflare token."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/13.png",alt:"Cloudflare"}))),Object(o.b)("p",null,"Once your tunnel is created and connected, you have to set the public hostname and the related service settings."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/11.png",alt:"Cloudflare"})),Object(o.b)("p",null,"To get the service name of your application deployed by Qovery, you can get it in your application variables:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/12.png",alt:"Cloudflare"})),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This setup works for static environments but not for dynamic ones since the service name is dynamic. We should probably suggest to use the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/cloudflare/helm-charts"}),"cloudflared helm chart")," once we release helm deployment")),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"After following the steps from above, our application should be accessible using the custom domain we selected:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/7.png",alt:"Cloudflare"})),Object(o.b)("p",null,"In the guide we went through all the necessary steps to configure Cloudflare and Qovery to make use of your custom domain."))}d.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var u=r.a.createContext({}),s=function(e){var t=r.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},d=function(e){var t=s(e.components);return r.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},b=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),d=s(n),b=a,f=d["".concat(i,".").concat(b)]||d[b]||p[b]||o;return n?r.a.createElement(f,l({ref:t},u,{components:n})):r.a.createElement(f,l({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=b;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,i[1]=l;for(var u=2;u1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,u=void 0===c?n:r(c,n);u>l;)t[l++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(430),c=n(20),u=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,s=n||c,d=Object(l.a)(s),p=Object(r.useRef)(!1),b=u.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!b&&d&&window.docusaurus.prefetch(s),function(){b&&t&&t.disconnect()}}),[s,b,d]),s&&d?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,a;b&&e&&d&&(n=e,a=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:s})):o.a.createElement("a",Object(a.a)({},e,{href:s}))}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),i=n(420),l=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,u=e.size,s=e.target,d=e.to,p=l()("jump-to","jump-to--"+u,n),b=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return s?r.a.createElement("a",{href:d,target:s,className:p},b):r.a.createElement(o.a,{to:d,className:p},b)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see ba43933d.f7fa6d7a.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[191],{342:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var a=n(1),r=n(9),o=(n(0),n(425)),i=n(424),l=(n(429),n(431),{last_modified_on:"2023-12-12",$schema:"/.meta/.schemas/guides.json",title:"Setting up Cloudflare and Custom Domain on Qovery",description:"Using Cloudflare for applications deployed on Qovery",author_github:"https://github.com/jul-dan",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Setting up Cloudflare and Custom Domain on Qovery",description:"Using Cloudflare for applications deployed on Qovery",permalink:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery",readingTime:"4 min read",source:"@site/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Setting up Cloudflare and Custom Domain on Qovery",truncated:!1,prevItem:{title:"Seed Database",permalink:"/guides/advanced/seed-database"},nextItem:{title:"Setup VPC peering on AWS with Qovery",permalink:"/guides/tutorial/aws-vpc-peering-with-qovery"}},u=[{value:"Adding a Custom Domain",id:"adding-a-custom-domain",children:[]},{value:"Cloudflare Configuration",id:"cloudflare-configuration",children:[{value:"CNAME",id:"cname",children:[]},{value:"SSL/TLS",id:"ssltls",children:[]},{value:"Restrict application access",id:"restrict-application-access",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],s={rightToc:u};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"The guide assumes that you have an application up and running on Qovery. We'll go through the process of adding a new Custom Domain to the application and use Cloudflare as the domain provider. We also assume that you own a custom domain on Cloudflare (or any other domain registrar):"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/1.png",alt:"Cloudflare"})),Object(o.b)("h2",{id:"adding-a-custom-domain"},"Adding a Custom Domain"),Object(o.b)("p",null,"First, let's open application settings:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/2.png",alt:"Cloudflare"})),Object(o.b)("p",null,"Add your Cloudflare managed domain in ",Object(o.b)("inlineCode",{parentName:"p"},"Domain")," section:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/3.png",alt:"Cloudflare"})),Object(o.b)("h2",{id:"cloudflare-configuration"},"Cloudflare Configuration"),Object(o.b)("h3",{id:"cname"},"CNAME"),Object(o.b)("p",null,"To finish the configuration on Cloudfalre, open the DNS Settings:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/4.png",alt:"Cloudflare"})),Object(o.b)("p",null,"And add a CNAME entry with the value taken from the Qovery Console just like this:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/5.png",alt:"Cloudflare"})),Object(o.b)("p",null,"You can safely use the ",Object(o.b)("inlineCode",{parentName:"p"},"Proxy")," mode."),Object(o.b)("h3",{id:"ssltls"},"SSL/TLS"),Object(o.b)("p",null,"The last step to configure the domain Cloudflare side properly, is to use the ",Object(o.b)("inlineCode",{parentName:"p"},"Full")," TLS encryption:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/6.png",alt:"Cloudflare"})),Object(o.b)("p",null,"This is the requirement to make Custom Domain work properly using Cloudflare as the domain provider on Qovery."),Object(o.b)("h3",{id:"restrict-application-access"},"Restrict application access"),Object(o.b)("p",null,"If you want to limit the application access via Cloudflare only, you have two ways to perform it:"),Object(o.b)("h4",{id:"ip-whitelisting"},"IP whitelisting"),Object(o.b)("p",null,"In Qovery it is possible to whitelist a range of IPs that can reach your application:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"In the advanced settings section of your application:",Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/8.png",alt:"Cloudflare"}))),Object(o.b)("li",{parentName:"ul"},"Get the ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.cloudflare.com/ips-v4/"}),"Cloudflare ips")),Object(o.b)("li",{parentName:"ul"},"Edit the ",Object(o.b)("inlineCode",{parentName:"li"},"network.ingress.whitelist_source_range")," setting and add the Cloudflare IPs separated with a comma:",Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/9.png",alt:"Cloudflare"}))),Object(o.b)("li",{parentName:"ul"},"Save and redeploy your application")),Object(o.b)("h4",{id:"cloudflared"},"Cloudflared"),Object(o.b)("p",null,"Cloudflared establishes outbound connections (tunnels) between your resources and Cloudflare\u2019s global network."),Object(o.b)("p",null,"You have different ways to install Cloudflared on your cluster, you can find the installation instructions within this ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel/"}),"documentation"),"\nSince Cloudflared establishes a tunnel for you and the domain and TLS management is done by Cloudflare, you don't need to expose publicly the application during the setup (See ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#ports"}),"port setup")),Object(o.b)("p",null,"You can decide to install Cloudflared by yourself or via Qovery. Within the section below, you will find documentation on how to install Cloudflared as a container in one of the Qovery environments.\nBy creating and deploying the following service, using the Cloudflared image:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/10.png",alt:"Cloudflare"})),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Create a ",Object(o.b)("inlineCode",{parentName:"p"},"TUNNEL_TOKEN")," secret environment variable (Scope: Environment) to pass the Cloudflare token."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/13.png",alt:"Cloudflare"}))),Object(o.b)("p",null,"Once your tunnel is created and connected, you have to set the public hostname and the related service settings."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/11.png",alt:"Cloudflare"})),Object(o.b)("p",null,"To get the service name of your application deployed by Qovery, you can get it in your application variables:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/12.png",alt:"Cloudflare"})),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This setup works for static environments but not for dynamic ones since the service name is dynamic. We should probably suggest to use the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/cloudflare/helm-charts"}),"cloudflared helm chart")," once we release helm deployment")),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"After following the steps from above, our application should be accessible using the custom domain we selected:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/7.png",alt:"Cloudflare"})),Object(o.b)("p",null,"In the guide we went through all the necessary steps to configure Cloudflare and Qovery to make use of your custom domain."))}d.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var u=r.a.createContext({}),s=function(e){var t=r.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},d=function(e){var t=s(e.components);return r.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},b=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),d=s(n),b=a,f=d["".concat(i,".").concat(b)]||d[b]||p[b]||o;return n?r.a.createElement(f,l({ref:t},u,{components:n})):r.a.createElement(f,l({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=b;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,i[1]=l;for(var u=2;u1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,u=void 0===c?n:r(c,n);u>l;)t[l++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(432),c=n(20),u=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,s=n||c,d=Object(l.a)(s),p=Object(r.useRef)(!1),b=u.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!b&&d&&window.docusaurus.prefetch(s),function(){b&&t&&t.disconnect()}}),[s,b,d]),s&&d?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,a;b&&e&&d&&(n=e,a=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:s})):o.a.createElement("a",Object(a.a)({},e,{href:s}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),i=n(423),l=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,u=e.size,s=e.target,d=e.to,p=l()("jump-to","jump-to--"+u,n),b=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return s?r.a.createElement("a",{href:d,target:s,className:p},b):r.a.createElement(o.a,{to:d,className:p},b)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/bbfbe73c.23608854.js.LICENSE.txt b/ba43933d.f7fa6d7a.js.LICENSE.txt similarity index 100% rename from bbfbe73c.23608854.js.LICENSE.txt rename to ba43933d.f7fa6d7a.js.LICENSE.txt diff --git a/baf9cc25.aface988.js b/baf9cc25.c2504d14.js similarity index 96% rename from baf9cc25.aface988.js rename to baf9cc25.c2504d14.js index 40b185b68c..ec25510095 100644 --- a/baf9cc25.aface988.js +++ b/baf9cc25.c2504d14.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[189],{340:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return c})),r.d(t,"rightToc",(function(){return s})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),o=(r(0),r(422)),i={last_modified_on:"2023-04-04",title:"PostgreSQL",description:"How to set up and use a PostgreSQL database"},c={id:"using-qovery/configuration/database/postgresql",title:"PostgreSQL",description:"How to set up and use a PostgreSQL database",source:"@site/docs/using-qovery/configuration/database/postgresql.md",permalink:"/docs/using-qovery/configuration/database/postgresql",sidebar:"docs",previous:{title:"Databases",permalink:"/docs/using-qovery/configuration/database"},next:{title:"MySQL",permalink:"/docs/using-qovery/configuration/database/mysql"}},s=[{value:"Supported Versions and Cloud Providers",id:"supported-versions-and-cloud-providers",children:[]}],l={rightToc:s};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},l,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"PostgreSQL is a powerful, open source object-relational database system with over 30 years of active development that has earned it a strong reputation for reliability, feature robustness, and performance."),Object(o.b)("h2",{id:"supported-versions-and-cloud-providers"},"Supported Versions and Cloud Providers"),Object(o.b)("p",null,"You can find the supported versions directly within the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),"."),Object(o.b)("p",null,"Availability of the Container version or Cloud Provider Managed versions depends on the chosen Cloud Provider "),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Cloud provider"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Container supported"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Managed supported"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"AWS"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Yes"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Yes (RDS)")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Scaleway"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Yes"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"No")))),Object(o.b)("p",null,"Have a look at the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/"}),"Database page")," to know more about the database creation and setup."))}p.isMDXComponent=!0},422:function(e,t,r){"use strict";r.d(t,"a",(function(){return u})),r.d(t,"b",(function(){return f}));var n=r(0),a=r.n(n);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=a.a.createContext({}),p=function(e){var t=a.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},u=function(e){var t=p(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=p(r),d=n,f=u["".concat(i,".").concat(d)]||u[d]||b[d]||o;return r?a.a.createElement(f,c({ref:t},l,{components:r})):a.a.createElement(f,c({ref:t},l))}));function f(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=a.a.createContext({}),p=function(e){var t=a.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},u=function(e){var t=p(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=p(r),d=n,f=u["".concat(i,".").concat(d)]||u[d]||b[d]||o;return r?a.a.createElement(f,c({ref:t},l,{components:r})):a.a.createElement(f,c({ref:t},l))}));function f(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l")," and we select the environment variables to import:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery env import .env.development\n\nQovery: dot env file to import: '.env.development'\n? Do you want to import Environment Variables or Secrets? Environment Variables\n? What environment variables do you want to import? [Use arrows to move, space to select, to all, to none, type to filter]\n [x] COLOR_BACKGROUND=fff\n [ ] AUTH0_API_KEY_SECRET=0xb33f\n> [x] API_URL=https://api.mytld.com\n [ ] STRAPI_API_KEY=x.xxyyyzzz\n")),Object(r.b)("p",null,"Once validated you will see the following import validation:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"? What environment variables do you want to import? COLOR_BACKGROUND=fff, API_URL=https://api.mytld.com\nQovery: \u2705 Environment Variables successfully imported!\n")),Object(r.b)("p",null,"If during the import something goes wrong, you will see the errors and why it failed."),Object(r.b)("h3",{id:"secrets"},"Secrets"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Check out the documentation")," to learn more on how Secrets works.")),Object(r.b)("p",null,"To import the Secrets, you need to run the same command ",Object(r.b)("inlineCode",{parentName:"p"},"qovery env import ")," and select the secrets to import."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery env import .env.development\n\nQovery: dot env file to import: '.env.development'\n? Do you want to import Environment Variables or Secrets? Secrets\n? What environment variables do you want to import? [Use arrows to move, space to select, to all, to none, type to filter]\n [ ] COLOR_BACKGROUND=fff\n [x] AUTH0_API_KEY_SECRET=0xb33f\n [ ] API_URL=https://api.mytld.com\n> [x] STRAPI_API_KEY=x.xxyyyzzz\n")),Object(r.b)("p",null,"Once validated you will see the following import validation:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"? What environment variables do you want to import? STRAPI_API_KEY=x.xxyyyzzz, AUTH0_API_KEY_SECRET=0xb33\nQovery: \u2705 Secrets successfully imported!\n")),Object(r.b)("h2",{id:"check"},"Check"),Object(r.b)("p",null,"Open your environment variables console to check that everything has been set correctly."))}d.isMDXComponent=!0},421:function(e,t,a){"use strict";a(423);var n=a(0),o=a.n(n),r=a(420),l=a.n(r);a(132);t.a=function(e){var t=e.children,a=e.classNames,n=e.fill,r=e.icon,c=e.type,i=null;switch(c){case"danger":i="alert-triangle";break;case"success":i="check-circle";break;case"warning":i="alert-triangle";break;default:i="info"}return o.a.createElement("div",{className:l()(a,"alert","alert--"+c,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&o.a.createElement("i",{className:l()("feather","icon-"+(r||i))}),t)}},425:function(e,t,a){var n=a(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||a(10)&&n(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var n=a(0),o=a.n(n),r=a(421);t.a=function(e){var t=e.children,a=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},427:function(e,t,a){"use strict";var n=a(1),o=a(0),r=a.n(o),l=a(39),c=a(430),i=a(20),s=a.n(i);t.a=function(e){var t,a=e.to,i=e.href,b=a||i,u=Object(c.a)(b),m=Object(o.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!p&&u&&window.docusaurus.prefetch(b),function(){p&&t&&t.disconnect()}}),[b,p,u]),b&&u?r.a.createElement(l.b,Object(n.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(b),m.current=!0)},innerRef:function(e){var a,n;p&&e&&u&&(a=e,n=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:b})):r.a.createElement("a",Object(n.a)({},e,{href:b}))}},429:function(e,t,a){"use strict";var n=a(0),o=a.n(n),r=a(427),l=a(420),c=a.n(l);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,l=e.leftIcon,i=e.rightIcon,s=e.size,b=e.target,u=e.to,m=c()("jump-to","jump-to--"+s,a),p=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},l&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+l})),o.a.createElement("div",{className:"jump-to--main"},n?o.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(i||"chevron-right")+" arrow"}))));return b?o.a.createElement("a",{href:u,target:b,className:m},p):o.a.createElement(r.a,{to:u,className:m},p)}},430:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},434:function(e,t,a){"use strict";var n=a(1),o=(a(439),a(436),a(52),a(29),a(22),a(21),a(0)),r=a.n(o),l=a(446),c=a(420),i=a.n(c),s=a(428),b=a.n(s),u=a(445),m=37,p=39;function d(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,o=e.className,l=e.handleKeydown,c=e.style,s=e.values,b=e.selectedValue,u=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:i()("tabs",o,{"tabs--block":t}),style:c},s.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:i()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return l(u,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function v(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,o=e.size,c=e.values,i=c;if(i[0].group){var s=_.groupBy(i,"group");i=Object.keys(s).map((function(e){return{label:e,options:s[e]}}))}return r.a.createElement(l.a,{className:"react-select-container react-select--"+o,classNamePrefix:"react-select",options:i,isClearable:a,placeholder:t,value:c.find((function(e){return e.value==a})),onChange:function(e){return n(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,a=e.defaultValue,l=e.groupId,c=e.label,i=e.placeholder,s=e.select,h=e.size,y=(e.style,e.values),O=e.urlKey,f=Object(u.a)(),j=f.tabGroupChoices,g=f.setTabGroupChoices,w=Object(o.useState)(a),N=w[0],x=w[1];if(null!=l){var I=j[l];null!=I&&I!==N&&x(I)}var T=function(e){x(e),null!=l&&g(l,e)},C=[],E=function(e,t,a){switch(a.keyCode){case p:!function(e,t){var a=e.indexOf(t)+1;e[a]?e[a].focus():e[0].focus()}(e,t);break;case m:!function(e,t){var a=e.indexOf(t)-1;e[a]?e[a].focus():e[e.length-1].focus()}(e,t)}};return Object(o.useEffect)((function(){if("undefined"!=typeof window&&window.location&&O){var e=b.a.parse(window.location.search);e[O]&&x(e[O])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(h||"md")},c&&r.a.createElement("div",{className:"margin-vert--sm"},c),y.length>1&&(s?r.a.createElement(v,Object(n.a)({changeSelectedValue:T,handleKeydown:E,placeholder:i,selectedValue:N,size:h,tabRefs:C},e)):r.a.createElement(d,Object(n.a)({changeSelectedValue:T,handleKeydown:E,selectedValue:N,tabRefs:C},e)))),o.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},441:function(e,t,a){"use strict";var n=a(0),o=a.n(n);t.a=function(e){return o.a.createElement(o.a.Fragment,null,e.children)}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[193],{344:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return b})),a.d(t,"metadata",(function(){return u})),a.d(t,"rightToc",(function(){return m})),a.d(t,"default",(function(){return d}));var n=a(1),o=a(9),r=(a(0),a(425)),l=a(437),c=a(444),i=a(424),s=a(429),b=(a(431),{last_modified_on:"2023-04-23",$schema:"/.meta/.schemas/guides.json",title:"Import your environment variables with the Qovery CLI",description:"How to import your environment variables and secrets from your dotenv file with the Qovery CLI",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),u={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Import your environment variables with the Qovery CLI",description:"How to import your environment variables and secrets from your dotenv file with the Qovery CLI",permalink:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli",readingTime:"5 min read",source:"@site/guides/tutorial/import-your-environment-variables-with-the-qovery-cli.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Import your environment variables with the Qovery CLI",truncated:!1,prevItem:{title:"How to write a Dockerfile",permalink:"/guides/tutorial/how-to-write-a-dockerfile"},nextItem:{title:"Install Qovery on your Amazon Web Services account",permalink:"/guides/cloud-provider/guide-amazon-web-services"}},m=[{value:"Install Qovery CLI",id:"install-qovery-cli",children:[]},{value:"Set your context",id:"set-your-context",children:[]},{value:"Import",id:"import",children:[{value:"Environment Variables",id:"environment-variables",children:[]},{value:"Secrets",id:"secrets",children:[]}]},{value:"Check",id:"check",children:[]}],p={rightToc:m};function d(e){var t=e.components,a=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(n.a)({},p,a,{components:t,mdxType:"MDXLayout"}),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"The Qovery Web Interface support ",Object(r.b)("inlineCode",{parentName:"p"},".env")," (dot env) file import now. ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#import-environment-variables"}),"Check out the documentation"))),Object(r.b)("p",null,"When dealing with dozens of environment variables, it can be tedious to import them one by one. This is where the Qovery CLI with the env vars import feature helps. In this tutorial, you will learn how to import your environment variables and secrets via the Qovery CLI."),Object(r.b)(s.a,{mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Your dotenv (",Object(r.b)("inlineCode",{parentName:"li"},".env"),") file is ",Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://smartmob-rfc.readthedocs.io/en/latest/2-dotenv.html"}),"compliant to the following specs")),Object(r.b)("li",{parentName:"ul"},"You have created your application in Qovery"))),Object(r.b)("h2",{id:"install-qovery-cli"},"Install Qovery CLI"),Object(r.b)(l.a,{centered:!0,className:"rounded",defaultValue:"linux",placeholder:"Select your OS",select:!1,size:null,values:[{group:"Platforms",label:"Linux",value:"linux"},{group:"Platforms",label:"MacOS",value:"macos"},{group:"Platforms",label:"Windows",value:"windows"},{group:"Platforms",label:"Docker",value:"docker"}],mdxType:"Tabs"},Object(r.b)(c.a,{value:"linux",mdxType:"TabItem"},Object(r.b)(l.a,{centered:!0,className:"rounded",defaultValue:"universal",values:[{label:"*nix",value:"universal"},{label:"Arch Linux",value:"arch"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(c.a,{value:"universal",mdxType:"TabItem"},Object(r.b)("p",null,"To download and install Qovery CLI on any Linux distribution:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(r.b)(c.a,{value:"arch",mdxType:"TabItem"},Object(r.b)("p",null,"Qovery is part of ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(r.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Linux manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(r.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(r.b)(c.a,{value:"macos",mdxType:"TabItem"},Object(r.b)(l.a,{centered:!0,className:"rounded",defaultValue:"homebrew",values:[{label:"Homebrew",value:"homebrew"},{label:"Script",value:"script"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(c.a,{value:"homebrew",mdxType:"TabItem"},Object(r.b)("p",null,"The common solution to install a command line binary on the MacOS is to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery brew repository\n$ brew tap Qovery/qovery-cli\n\n# Install the CLI\n$ brew install qovery-cli\n"))),Object(r.b)(c.a,{value:"script",mdxType:"TabItem"},Object(r.b)("p",null,"To download and install Qovery CLI from the command line:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(r.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Mac OS manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(r.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(r.b)(c.a,{value:"windows",mdxType:"TabItem"},Object(r.b)(l.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(c.a,{value:"scoop",mdxType:"TabItem"},Object(r.b)("p",null,"The classic way to install binaries on Windows is to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery bucket\n$ scoop bucket add qovery https://github.com/Qovery/scoop-qovery-cli\n\n# Install the CLI\n$ scoop install qovery-cli\n"))),Object(r.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Windows manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to\n",Object(r.b)("inlineCode",{parentName:"p"},"C:\\Windows"),".")))),Object(r.b)(c.a,{value:"docker",mdxType:"TabItem"},Object(r.b)("p",null,"Install Docker on your local machine and run the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Pull and Run the latest Qovery CLI\n$ docker run ghcr.io/qovery/qovery-cli:latest help\n")),Object(r.b)("p",null,"Change ",Object(r.b)("inlineCode",{parentName:"p"},"latest")," by the version you want to use. For example, to use the version 0.58.4, run:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ docker run ghcr.io/qovery/qovery-cli:0.58.4 help\n")),Object(r.b)("p",null,"Note: ",Object(r.b)("inlineCode",{parentName:"p"},"ghcr.io")," is the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/pkgs/container/qovery-cli"}),"GitHub Container Registry"),"."))),Object(r.b)("h2",{id:"set-your-context"},"Set your context"),Object(r.b)("p",null,"Once you are authenticated with ",Object(r.b)("inlineCode",{parentName:"p"},"qovery auth"),", you must choose the application where you want to set the environment variables with the command ",Object(r.b)("inlineCode",{parentName:"p"},"qovery context set"),"."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="connect to qovery"',title:'"connect',to:!0,'qovery"':!0}),"$ qovery auth\n")),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="set the context"',title:'"set',the:!0,'context"':!0}),"~/Desktop $ qovery context set\nQovery: Current context:\nOrganization | Qovery Community\nProject | posthog\nEnvironment | prod\nApplication | proxy\n\nQovery: Select new context\nOrganization:\n\u2714 Qovery Realm\nProject:\n\u2714 Posthog\nEnvironment:\n\u2714 prod\nApplication:\n\u2714 nginx-proxy\n\nQovery: New context:\nOrganization | Qovery Realm\nProject | Posthog\nEnvironment | prod\nApplication | nginx-proxy\n")),Object(r.b)("h2",{id:"import"},"Import"),Object(r.b)("p",null,"With Qovery, you make the distinction between Environment Variables and Secrets. Basically, the value of a Secret is encrypted and cannot be revealed."),Object(r.b)("p",null,"Let's say that we have the following dotenv file ",Object(r.b)("inlineCode",{parentName:"p"},".env.development")," that we want to import:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-text",metastring:"title=.env.development",title:".env.development"}),"STRAPI_API_KEY=x.xxyyyzzz\nCOLOR_BACKGROUND=fff\nAUTH0_API_KEY_SECRET=0xb33f\nAPI_URL=https://api.mytld.com\n")),Object(r.b)("p",null,"The ",Object(r.b)("inlineCode",{parentName:"p"},"STRAPI_API_KEY")," and ",Object(r.b)("inlineCode",{parentName:"p"},"AUTH0_API_KEY_SECRET")," are Secrets. ",Object(r.b)("inlineCode",{parentName:"p"},"COLOR_BACKGROUND")," and ",Object(r.b)("inlineCode",{parentName:"p"},"API_URL")," are Environment Variables."),Object(r.b)("h3",{id:"environment-variables"},"Environment Variables"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Check out the documentation")," to learn more on how Environment Variables works.")),Object(r.b)("p",null,"To import the Environment Variables from this file we run the command ",Object(r.b)("inlineCode",{parentName:"p"},"qovery env import ")," and we select the environment variables to import:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery env import .env.development\n\nQovery: dot env file to import: '.env.development'\n? Do you want to import Environment Variables or Secrets? Environment Variables\n? What environment variables do you want to import? [Use arrows to move, space to select, to all, to none, type to filter]\n [x] COLOR_BACKGROUND=fff\n [ ] AUTH0_API_KEY_SECRET=0xb33f\n> [x] API_URL=https://api.mytld.com\n [ ] STRAPI_API_KEY=x.xxyyyzzz\n")),Object(r.b)("p",null,"Once validated you will see the following import validation:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"? What environment variables do you want to import? COLOR_BACKGROUND=fff, API_URL=https://api.mytld.com\nQovery: \u2705 Environment Variables successfully imported!\n")),Object(r.b)("p",null,"If during the import something goes wrong, you will see the errors and why it failed."),Object(r.b)("h3",{id:"secrets"},"Secrets"),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"Check out the documentation")," to learn more on how Secrets works.")),Object(r.b)("p",null,"To import the Secrets, you need to run the same command ",Object(r.b)("inlineCode",{parentName:"p"},"qovery env import ")," and select the secrets to import."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery env import .env.development\n\nQovery: dot env file to import: '.env.development'\n? Do you want to import Environment Variables or Secrets? Secrets\n? What environment variables do you want to import? [Use arrows to move, space to select, to all, to none, type to filter]\n [ ] COLOR_BACKGROUND=fff\n [x] AUTH0_API_KEY_SECRET=0xb33f\n [ ] API_URL=https://api.mytld.com\n> [x] STRAPI_API_KEY=x.xxyyyzzz\n")),Object(r.b)("p",null,"Once validated you will see the following import validation:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"? What environment variables do you want to import? STRAPI_API_KEY=x.xxyyyzzz, AUTH0_API_KEY_SECRET=0xb33\nQovery: \u2705 Secrets successfully imported!\n")),Object(r.b)("h2",{id:"check"},"Check"),Object(r.b)("p",null,"Open your environment variables console to check that everything has been set correctly."))}d.isMDXComponent=!0},424:function(e,t,a){"use strict";a(426);var n=a(0),o=a.n(n),r=a(423),l=a.n(r);a(132);t.a=function(e){var t=e.children,a=e.classNames,n=e.fill,r=e.icon,c=e.type,i=null;switch(c){case"danger":i="alert-triangle";break;case"success":i="check-circle";break;case"warning":i="alert-triangle";break;default:i="info"}return o.a.createElement("div",{className:l()(a,"alert","alert--"+c,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&o.a.createElement("i",{className:l()("feather","icon-"+(r||i))}),t)}},428:function(e,t,a){var n=a(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||a(10)&&n(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var n=a(0),o=a.n(n),r=a(424);t.a=function(e){var t=e.children,a=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},430:function(e,t,a){"use strict";var n=a(1),o=a(0),r=a.n(o),l=a(39),c=a(432),i=a(20),s=a.n(i);t.a=function(e){var t,a=e.to,i=e.href,b=a||i,u=Object(c.a)(b),m=Object(o.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!p&&u&&window.docusaurus.prefetch(b),function(){p&&t&&t.disconnect()}}),[b,p,u]),b&&u?r.a.createElement(l.b,Object(n.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(b),m.current=!0)},innerRef:function(e){var a,n;p&&e&&u&&(a=e,n=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:b})):r.a.createElement("a",Object(n.a)({},e,{href:b}))}},431:function(e,t,a){"use strict";var n=a(0),o=a.n(n),r=a(430),l=a(423),c=a.n(l);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,l=e.leftIcon,i=e.rightIcon,s=e.size,b=e.target,u=e.to,m=c()("jump-to","jump-to--"+s,a),p=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},l&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+l})),o.a.createElement("div",{className:"jump-to--main"},n?o.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(i||"chevron-right")+" arrow"}))));return b?o.a.createElement("a",{href:u,target:b,className:m},p):o.a.createElement(r.a,{to:u,className:m},p)}},432:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},437:function(e,t,a){"use strict";var n=a(1),o=(a(442),a(439),a(52),a(29),a(22),a(21),a(0)),r=a.n(o),l=a(449),c=a(423),i=a.n(c),s=a(433),b=a.n(s),u=a(448),m=37,p=39;function d(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,o=e.className,l=e.handleKeydown,c=e.style,s=e.values,b=e.selectedValue,u=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:i()("tabs",o,{"tabs--block":t}),style:c},s.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:i()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return l(u,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function v(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,o=e.size,c=e.values,i=c;if(i[0].group){var s=_.groupBy(i,"group");i=Object.keys(s).map((function(e){return{label:e,options:s[e]}}))}return r.a.createElement(l.a,{className:"react-select-container react-select--"+o,classNamePrefix:"react-select",options:i,isClearable:a,placeholder:t,value:c.find((function(e){return e.value==a})),onChange:function(e){return n(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,a=e.defaultValue,l=e.groupId,c=e.label,i=e.placeholder,s=e.select,h=e.size,y=(e.style,e.values),O=e.urlKey,f=Object(u.a)(),j=f.tabGroupChoices,g=f.setTabGroupChoices,w=Object(o.useState)(a),N=w[0],x=w[1];if(null!=l){var I=j[l];null!=I&&I!==N&&x(I)}var T=function(e){x(e),null!=l&&g(l,e)},C=[],E=function(e,t,a){switch(a.keyCode){case p:!function(e,t){var a=e.indexOf(t)+1;e[a]?e[a].focus():e[0].focus()}(e,t);break;case m:!function(e,t){var a=e.indexOf(t)-1;e[a]?e[a].focus():e[e.length-1].focus()}(e,t)}};return Object(o.useEffect)((function(){if("undefined"!=typeof window&&window.location&&O){var e=b.a.parse(window.location.search);e[O]&&x(e[O])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(h||"md")},c&&r.a.createElement("div",{className:"margin-vert--sm"},c),y.length>1&&(s?r.a.createElement(v,Object(n.a)({changeSelectedValue:T,handleKeydown:E,placeholder:i,selectedValue:N,size:h,tabRefs:C},e)):r.a.createElement(d,Object(n.a)({changeSelectedValue:T,handleKeydown:E,selectedValue:N,tabRefs:C},e)))),o.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},444:function(e,t,a){"use strict";var n=a(0),o=a.n(n);t.a=function(e){return o.a.createElement(o.a.Fragment,null,e.children)}}}]); \ No newline at end of file diff --git a/bbedfc29.f41e01be.js b/bbedfc29.01fda465.js similarity index 93% rename from bbedfc29.f41e01be.js rename to bbedfc29.01fda465.js index 8e5ca03af8..adf03fa8f1 100644 --- a/bbedfc29.f41e01be.js +++ b/bbedfc29.01fda465.js @@ -1,2 +1,2 @@ -/*! For license information please see bbedfc29.f41e01be.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[191],{342:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return c})),n.d(t,"default",(function(){return b}));var a=n(1),r=n(9),o=(n(0),n(422)),i=(n(421),n(426),n(429),{last_modified_on:"2021-12-28",$schema:"/.meta/.schemas/guides.json",title:"Using Amazon SQS and Lambda on Qovery",description:"How to integrate Amazon SQS and Lambda on Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Using Amazon SQS and Lambda on Qovery",description:"How to integrate Amazon SQS and Lambda on Qovery",permalink:"/guides/tutorial/aws-sqs-lambda-with-qovery",readingTime:"5 min read",source:"@site/guides/tutorial/aws-sqs-lambda-with-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Using Amazon SQS and Lambda on Qovery",truncated:!1,prevItem:{title:"Use AWS IAM roles with Qovery",permalink:"/guides/tutorial/use-aws-iam-roles-with-qovery"},nextItem:{title:"Working with Git Submodules",permalink:"/guides/tutorial/working-with-git-submodules"}},c=[{value:"Goal",id:"goal",children:[]},{value:"Configure SQS",id:"configure-sqs",children:[]},{value:"Create Message Producer",id:"create-message-producer",children:[]},{value:"Create Lambda Consumers",id:"create-lambda-consumers",children:[]},{value:"Create Lambda Trigger",id:"create-lambda-trigger",children:[]},{value:"Configure Permissions",id:"configure-permissions",children:[]},{value:"Test Lambda as an SQS Consumer Flow",id:"test-lambda-as-an-sqs-consumer-flow",children:[]},{value:"Conclusions",id:"conclusions",children:[]}],l={rightToc:c};function b(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Message queuing service enables you to decouple and scale microservices, distributed systems, and serverless applications. In this guide, we'll show you how to leverage a queue system (",Object(o.b)("inlineCode",{parentName:"p"},"Amazon SQS"),") to build a highly scalable backend."),Object(o.b)("p",null,"Using Amazon SQS eliminates the complexity and overhead associated with managing and operating message-oriented middleware and empowers developers to focus on differentiating work. With SQS, you can send, store, and receive messages between software components at any volume without losing messages or requiring other services to be available."),Object(o.b)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"In this guide, we'll create a backend microservice that sends messages on an event queue. Additionally, we'll go through two ways of consuming and processing those messages:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"We will use ",Object(o.b)("inlineCode",{parentName:"li"},"AWS Lambda")," to process events from the queue in a serverless way"),Object(o.b)("li",{parentName:"ul"},"We will use Qovery-managed backend application workers to process events from the queue")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/1.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"As for now, Qovery does not natively integrate with AWS Lambda and SQS, but the integration part is quite easy, and we will go through it in the following steps."),Object(o.b)("p",null,"The backend application and workers servers that consume messages from the queue will be fully managed and deployed by Qovery."),Object(o.b)("p",null,"Let's get started."),Object(o.b)("h2",{id:"configure-sqs"},"Configure SQS"),Object(o.b)("p",null,"Open ",Object(o.b)("inlineCode",{parentName:"p"},"Amazon SQS")," service in AWS Console and click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create Queue")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/2.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"We will use the ",Object(o.b)("inlineCode",{parentName:"p"},"Standard")," queue and leave all the settings in defaults for now. Type in the name of the queue and click ",Object(o.b)("inlineCode",{parentName:"p"},"Create"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/3.png",alt:"AWS SQS Lambda"})),Object(o.b)("h2",{id:"create-message-producer"},"Create Message Producer"),Object(o.b)("p",null,"In this step, we will deploy an app that pushes messages to the SQS queue. The source code of the app is available ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/aws-sqs-example/blob/main/index.js"}),"here"),"."),Object(o.b)("p",null,"The source code of the app is simple - it's a web server that sends messages to the SQS queue each time someone hits its API endpoint:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const command = new SendMessageCommand({});\n\nclient.send(command).then(\n (data) => {\n console.log(data);\n res.end('Success');\n // process data.\n },\n (error) => {\n console.error(error);\n res.end('Error');\n // error handling.\n }\n);\n")),Object(o.b)("p",null,"To deploy the app on Qovery, all you need to do is to fork the repository from above and create a new app adding port ",Object(o.b)("inlineCode",{parentName:"p"},"3000"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/4.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Afterwards, we need to add two environment variables:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"accessKeyId")," - your AWS access key ID"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"secretAccessKey")," - your AWS secret access key")),Object(o.b)("p",null,"You can add them in ",Object(o.b)("inlineCode",{parentName:"p"},"Environment Variebles")," ",Object(o.b)("inlineCode",{parentName:"p"},"Secret")," section in your application settings:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/5.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/6.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"After all the setup is all done, click the ",Object(o.b)("inlineCode",{parentName:"p"},"Deploy")," button - the application will be shortly deployed."),Object(o.b)("h2",{id:"create-lambda-consumers"},"Create Lambda Consumers"),Object(o.b)("p",null,"In AWS Console, open ",Object(o.b)("inlineCode",{parentName:"p"},"AWS Lambda")," panel."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/7.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"For the sake of the guide, we will use a simple ",Object(o.b)("inlineCode",{parentName:"p"},"hello-world")," lambda from AWS serverless app repository."),Object(o.b)("p",null,"Browse the app repository and pick the ",Object(o.b)("inlineCode",{parentName:"p"},"hello-world")," function as shown in the screenshot above, and deploy the function"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/8.png",alt:"AWS SQS Lambda"})),Object(o.b)("h2",{id:"create-lambda-trigger"},"Create Lambda Trigger"),Object(o.b)("p",null,"To make our Lambdas consume messages from SQS, we will need to add a ",Object(o.b)("inlineCode",{parentName:"p"},"Lambda Trigger")," in the SQS configuration."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/9.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Click on ",Object(o.b)("inlineCode",{parentName:"p"},"Configure Lambda Function Trigger")," as shown in the screenshot above and select your lambda function from the dropdown, then save the changes:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/10.png",alt:"AWS SQS Lambda"})),Object(o.b)("h2",{id:"configure-permissions"},"Configure Permissions"),Object(o.b)("p",null,"Let's now grant our Lambda functions access to the SQS queue we created before."),Object(o.b)("p",null,"In our lambda view, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Configure"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/11.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Then, click on a role in ",Object(o.b)("inlineCode",{parentName:"p"},"Execution role")," to get redirected to a view where we can alter our Lambda permissions."),Object(o.b)("p",null,"In the role summary screen, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Edit policy")," next to ",Object(o.b)("inlineCode",{parentName:"p"},"helloWorldrolePolicy")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/12.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"In the ",Object(o.b)("inlineCode",{parentName:"p"},"SQS")," section, grant permissions to all Read/Write options in the ",Object(o.b)("inlineCode",{parentName:"p"},"Actions")," ",Object(o.b)("inlineCode",{parentName:"p"},"Access level")," and accept the changes:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/13.png",alt:"AWS SQS Lambda"})),Object(o.b)("h2",{id:"test-lambda-as-an-sqs-consumer-flow"},"Test Lambda as an SQS Consumer Flow"),Object(o.b)("p",null,"To push messages to our SQS queue from the backend app deployed on Qovery, click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Open")," button in the application we deployed in the previous step. It will redirect you to the API endpoint exposed by the backend app - the logic inside the application is made so that it sends messages to the SQS queue."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/14.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Now, in the ",Object(o.b)("inlineCode",{parentName:"p"},"Monitoring")," section of SQS in AWS Console, we will see messages received on metrics charts:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/15.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"To validate that our consumer Lambdas processed the messages, navigate to your lambda ",Object(o.b)("inlineCode",{parentName:"p"},"Monitor")," panel:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/16.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"In the ",Object(o.b)("inlineCode",{parentName:"p"},"Invocations")," chart, you'll notice that our Lambda was triggered several times by the messages sent over the SQS."),Object(o.b)("h2",{id:"conclusions"},"Conclusions"),Object(o.b)("p",null,"In this part of the tutorial, we learned how to send messages over from an application deployed on Qovery to SQS and consume them from serverless Lambda functions. In the next part, we will create a scalable group of worker applications deployed by Qovery that consume messages from the same Queue."))}b.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),b=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s({},t,{},e)),n},u=function(e){var t=b(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=b(n),m=a,p=u["".concat(i,".").concat(m)]||u[m]||d[m]||o;return n?r.a.createElement(p,s({ref:t},l,{components:n})):r.a.createElement(p,s({ref:t},l))}));function p(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s.mdxType="string"==typeof e?e:a,i[1]=s;for(var l=2;l1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,l=void 0===c?n:r(c,n);l>s;)t[s++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),s=n(430),c=n(20),l=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,b=n||c,u=Object(s.a)(b),d=Object(r.useRef)(!1),m=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&u&&window.docusaurus.prefetch(b),function(){m&&t&&t.disconnect()}}),[b,m,u]),b&&u?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(b),d.current=!0)},innerRef:function(e){var n,a;m&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:b})):o.a.createElement("a",Object(a.a)({},e,{href:b}))}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),i=n(420),s=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,l=e.size,b=e.target,u=e.to,d=s()("jump-to","jump-to--"+l,n),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return b?r.a.createElement("a",{href:u,target:b,className:d},m):r.a.createElement(o.a,{to:u,className:d},m)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see bbedfc29.01fda465.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[194],{345:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return c})),n.d(t,"default",(function(){return b}));var a=n(1),r=n(9),o=(n(0),n(425)),i=(n(424),n(429),n(431),{last_modified_on:"2021-12-28",$schema:"/.meta/.schemas/guides.json",title:"Using Amazon SQS and Lambda on Qovery",description:"How to integrate Amazon SQS and Lambda on Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Using Amazon SQS and Lambda on Qovery",description:"How to integrate Amazon SQS and Lambda on Qovery",permalink:"/guides/tutorial/aws-sqs-lambda-with-qovery",readingTime:"5 min read",source:"@site/guides/tutorial/aws-sqs-lambda-with-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Using Amazon SQS and Lambda on Qovery",truncated:!1,prevItem:{title:"Use AWS IAM roles with Qovery",permalink:"/guides/tutorial/use-aws-iam-roles-with-qovery"},nextItem:{title:"Working with Git Submodules",permalink:"/guides/tutorial/working-with-git-submodules"}},c=[{value:"Goal",id:"goal",children:[]},{value:"Configure SQS",id:"configure-sqs",children:[]},{value:"Create Message Producer",id:"create-message-producer",children:[]},{value:"Create Lambda Consumers",id:"create-lambda-consumers",children:[]},{value:"Create Lambda Trigger",id:"create-lambda-trigger",children:[]},{value:"Configure Permissions",id:"configure-permissions",children:[]},{value:"Test Lambda as an SQS Consumer Flow",id:"test-lambda-as-an-sqs-consumer-flow",children:[]},{value:"Conclusions",id:"conclusions",children:[]}],l={rightToc:c};function b(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Message queuing service enables you to decouple and scale microservices, distributed systems, and serverless applications. In this guide, we'll show you how to leverage a queue system (",Object(o.b)("inlineCode",{parentName:"p"},"Amazon SQS"),") to build a highly scalable backend."),Object(o.b)("p",null,"Using Amazon SQS eliminates the complexity and overhead associated with managing and operating message-oriented middleware and empowers developers to focus on differentiating work. With SQS, you can send, store, and receive messages between software components at any volume without losing messages or requiring other services to be available."),Object(o.b)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"In this guide, we'll create a backend microservice that sends messages on an event queue. Additionally, we'll go through two ways of consuming and processing those messages:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"We will use ",Object(o.b)("inlineCode",{parentName:"li"},"AWS Lambda")," to process events from the queue in a serverless way"),Object(o.b)("li",{parentName:"ul"},"We will use Qovery-managed backend application workers to process events from the queue")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/1.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"As for now, Qovery does not natively integrate with AWS Lambda and SQS, but the integration part is quite easy, and we will go through it in the following steps."),Object(o.b)("p",null,"The backend application and workers servers that consume messages from the queue will be fully managed and deployed by Qovery."),Object(o.b)("p",null,"Let's get started."),Object(o.b)("h2",{id:"configure-sqs"},"Configure SQS"),Object(o.b)("p",null,"Open ",Object(o.b)("inlineCode",{parentName:"p"},"Amazon SQS")," service in AWS Console and click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create Queue")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/2.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"We will use the ",Object(o.b)("inlineCode",{parentName:"p"},"Standard")," queue and leave all the settings in defaults for now. Type in the name of the queue and click ",Object(o.b)("inlineCode",{parentName:"p"},"Create"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/3.png",alt:"AWS SQS Lambda"})),Object(o.b)("h2",{id:"create-message-producer"},"Create Message Producer"),Object(o.b)("p",null,"In this step, we will deploy an app that pushes messages to the SQS queue. The source code of the app is available ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/aws-sqs-example/blob/main/index.js"}),"here"),"."),Object(o.b)("p",null,"The source code of the app is simple - it's a web server that sends messages to the SQS queue each time someone hits its API endpoint:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const command = new SendMessageCommand({});\n\nclient.send(command).then(\n (data) => {\n console.log(data);\n res.end('Success');\n // process data.\n },\n (error) => {\n console.error(error);\n res.end('Error');\n // error handling.\n }\n);\n")),Object(o.b)("p",null,"To deploy the app on Qovery, all you need to do is to fork the repository from above and create a new app adding port ",Object(o.b)("inlineCode",{parentName:"p"},"3000"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/4.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Afterwards, we need to add two environment variables:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"accessKeyId")," - your AWS access key ID"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"secretAccessKey")," - your AWS secret access key")),Object(o.b)("p",null,"You can add them in ",Object(o.b)("inlineCode",{parentName:"p"},"Environment Variebles")," ",Object(o.b)("inlineCode",{parentName:"p"},"Secret")," section in your application settings:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/5.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/6.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"After all the setup is all done, click the ",Object(o.b)("inlineCode",{parentName:"p"},"Deploy")," button - the application will be shortly deployed."),Object(o.b)("h2",{id:"create-lambda-consumers"},"Create Lambda Consumers"),Object(o.b)("p",null,"In AWS Console, open ",Object(o.b)("inlineCode",{parentName:"p"},"AWS Lambda")," panel."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/7.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"For the sake of the guide, we will use a simple ",Object(o.b)("inlineCode",{parentName:"p"},"hello-world")," lambda from AWS serverless app repository."),Object(o.b)("p",null,"Browse the app repository and pick the ",Object(o.b)("inlineCode",{parentName:"p"},"hello-world")," function as shown in the screenshot above, and deploy the function"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/8.png",alt:"AWS SQS Lambda"})),Object(o.b)("h2",{id:"create-lambda-trigger"},"Create Lambda Trigger"),Object(o.b)("p",null,"To make our Lambdas consume messages from SQS, we will need to add a ",Object(o.b)("inlineCode",{parentName:"p"},"Lambda Trigger")," in the SQS configuration."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/9.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Click on ",Object(o.b)("inlineCode",{parentName:"p"},"Configure Lambda Function Trigger")," as shown in the screenshot above and select your lambda function from the dropdown, then save the changes:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/10.png",alt:"AWS SQS Lambda"})),Object(o.b)("h2",{id:"configure-permissions"},"Configure Permissions"),Object(o.b)("p",null,"Let's now grant our Lambda functions access to the SQS queue we created before."),Object(o.b)("p",null,"In our lambda view, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Configure"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/11.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Then, click on a role in ",Object(o.b)("inlineCode",{parentName:"p"},"Execution role")," to get redirected to a view where we can alter our Lambda permissions."),Object(o.b)("p",null,"In the role summary screen, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Edit policy")," next to ",Object(o.b)("inlineCode",{parentName:"p"},"helloWorldrolePolicy")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/12.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"In the ",Object(o.b)("inlineCode",{parentName:"p"},"SQS")," section, grant permissions to all Read/Write options in the ",Object(o.b)("inlineCode",{parentName:"p"},"Actions")," ",Object(o.b)("inlineCode",{parentName:"p"},"Access level")," and accept the changes:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/13.png",alt:"AWS SQS Lambda"})),Object(o.b)("h2",{id:"test-lambda-as-an-sqs-consumer-flow"},"Test Lambda as an SQS Consumer Flow"),Object(o.b)("p",null,"To push messages to our SQS queue from the backend app deployed on Qovery, click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Open")," button in the application we deployed in the previous step. It will redirect you to the API endpoint exposed by the backend app - the logic inside the application is made so that it sends messages to the SQS queue."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/14.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Now, in the ",Object(o.b)("inlineCode",{parentName:"p"},"Monitoring")," section of SQS in AWS Console, we will see messages received on metrics charts:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/15.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"To validate that our consumer Lambdas processed the messages, navigate to your lambda ",Object(o.b)("inlineCode",{parentName:"p"},"Monitor")," panel:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/16.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"In the ",Object(o.b)("inlineCode",{parentName:"p"},"Invocations")," chart, you'll notice that our Lambda was triggered several times by the messages sent over the SQS."),Object(o.b)("h2",{id:"conclusions"},"Conclusions"),Object(o.b)("p",null,"In this part of the tutorial, we learned how to send messages over from an application deployed on Qovery to SQS and consume them from serverless Lambda functions. In the next part, we will create a scalable group of worker applications deployed by Qovery that consume messages from the same Queue."))}b.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),b=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s({},t,{},e)),n},u=function(e){var t=b(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=b(n),m=a,p=u["".concat(i,".").concat(m)]||u[m]||d[m]||o;return n?r.a.createElement(p,s({ref:t},l,{components:n})):r.a.createElement(p,s({ref:t},l))}));function p(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s.mdxType="string"==typeof e?e:a,i[1]=s;for(var l=2;l1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,l=void 0===c?n:r(c,n);l>s;)t[s++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),s=n(432),c=n(20),l=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,b=n||c,u=Object(s.a)(b),d=Object(r.useRef)(!1),m=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&u&&window.docusaurus.prefetch(b),function(){m&&t&&t.disconnect()}}),[b,m,u]),b&&u?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(b),d.current=!0)},innerRef:function(e){var n,a;m&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:b})):o.a.createElement("a",Object(a.a)({},e,{href:b}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),i=n(423),s=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,l=e.size,b=e.target,u=e.to,d=s()("jump-to","jump-to--"+l,n),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return b?r.a.createElement("a",{href:u,target:b,className:d},m):r.a.createElement(o.a,{to:u,className:d},m)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/bc592dc7.b840c1c5.js.LICENSE.txt b/bbedfc29.01fda465.js.LICENSE.txt similarity index 100% rename from bc592dc7.b840c1c5.js.LICENSE.txt rename to bbedfc29.01fda465.js.LICENSE.txt diff --git a/bbfbe73c.23608854.js b/bbfbe73c.5a9acd33.js similarity index 93% rename from bbfbe73c.23608854.js rename to bbfbe73c.5a9acd33.js index baa9100bae..597ce32a11 100644 --- a/bbfbe73c.23608854.js +++ b/bbfbe73c.5a9acd33.js @@ -1,2 +1,2 @@ -/*! For license information please see bbfbe73c.23608854.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[192],{343:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return d}));var r=n(1),o=n(9),a=(n(0),n(422)),i=n(421),c=n(429),l=n(426),u={last_modified_on:"2022-05-04",$schema:"/.meta/.schemas/guides.json",title:"How to write a Dockerfile",description:"How to write your first Dockerfile in order to deploy your application with Qovery",author_github:"https://github.com/MacLikorne",tags:["type: tutorial","technology: docker"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to write a Dockerfile",description:"How to write your first Dockerfile in order to deploy your application with Qovery",permalink:"/guides/tutorial/how-to-write-a-dockerfile",readingTime:"5 min read",source:"@site/guides/tutorial/how-to-write-a-dockerfile.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: docker",permalink:"/guides/tags/technology-docker"}],title:"How to write a Dockerfile",truncated:!1,prevItem:{title:"How To Use Lifecycle Job To Deploy Any Kind Of Resources",permalink:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources"},nextItem:{title:"Import your environment variables with the Qovery CLI",permalink:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli"}},p=[{value:"My Sweet Dockerfile",id:"my-sweet-dockerfile",children:[{value:"FROM",id:"from",children:[]},{value:"WORKDIR",id:"workdir",children:[]},{value:"COPY",id:"copy",children:[]},{value:"RUN",id:"run",children:[]},{value:"EXPOSE",id:"expose",children:[]},{value:"CMD",id:"cmd",children:[]},{value:"Build your image",id:"build-your-image",children:[]},{value:"Test your image",id:"test-your-image",children:[]}]},{value:"What's next?",id:"whats-next",children:[]}],b={rightToc:p};function d(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"With Qovery, there are two ways to build and deploy your application:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Without a Dockerfile in your repository: your application is built with ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://docs.qovery.com/docs/using-qovery/configuration/application/#option-1-buildpacks"}),"Buildpacks")),Object(a.b)("li",{parentName:"ol"},"With a Dockerfile: sometimes Buildpacks won't fit your specific setup, and you'll have to write your Dockerfile.")),Object(a.b)("p",null,"In this article, we'll see, step by step, how to quickly write a proper Dockerfile for any application you would like to deploy."),Object(a.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have installed the ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://docs.qovery.com/docs/using-qovery/interface/cli/"}),"Qovery CLI")),Object(a.b)("li",{parentName:"ul"},"You host your code on Github"))),Object(a.b)("hr",null),Object(a.b)("h2",{id:"my-sweet-dockerfile"},"My Sweet Dockerfile"),Object(a.b)("p",null,"If you read this, you probably don't know why Docker is used and what is the purpose of a Dockerfile."),Object(a.b)("p",null,"Docker is a container engine, building and using images to deploy applications in containers. It looks like virtualization, and each container could be compared to a virtual machine with the minimal setup to run an application."),Object(a.b)("p",null,"The Dockerfile is your image builder recipe. When Docker uses it, it will follow all instructions to ",Object(a.b)("strong",{parentName:"p"},"build your application and run it"),"."),Object(a.b)("p",null,"The first step is to create a file named ",Object(a.b)("strong",{parentName:"p"},"Dockerfile")," at your project root level so Qovery would be able to find and use it."),Object(a.b)("p",null,"Also, to avoid unwanted files from your repository (images, .idea, DS_Store etc.), you need to add a ",Object(a.b)("strong",{parentName:"p"},".dockerignore"),". It will prevent heavy copy tasks of useless files, mostly your project dependencies and libraries you'll get back to with your package manager."),Object(a.b)("p",null,"The ",Object(a.b)("strong",{parentName:"p"},".dockerignore")," file works like the ",Object(a.b)("strong",{parentName:"p"},".gitignore"),", so add all the path of the useless files and folders in it."),Object(a.b)("h3",{id:"from"},"FROM"),Object(a.b)("p",null,"The first line you'll add in your Dockerfile is ",Object(a.b)("strong",{parentName:"p"},"FROM"),"."),Object(a.b)("p",null,"It will pull an already existing image from ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.docker.com/"}),"Docker Hub"),". You should most of the time use an image that fits your application language (Node, Python, Java, etc.), but you can go a step backward and begin with a simple Linux image."),Object(a.b)("p",null,"Your Dockerfile's first line should look like this:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM :\n")),Object(a.b)("p",null,"For example, with ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.docker.com/_/python"}),"python"),":"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM python:3\n")),Object(a.b)("h3",{id:"workdir"},"WORKDIR"),Object(a.b)("p",null,"Since most of the images are Linux-based, a good practice is to set up a directory you'll work in. That's the purpose of the ",Object(a.b)("strong",{parentName:"p"},"WORKDIR")," line. It defines a directory and moves you in:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM :\nWORKDIR /app\n")),Object(a.b)("p",null,"If you now work with a relative path (./), it will be in the ",Object(a.b)("em",{parentName:"p"},"app")," directory."),Object(a.b)("h3",{id:"copy"},"COPY"),Object(a.b)("p",null,"Now you have defined your base image and your working directory, it's time to add your code in. ",Object(a.b)("strong",{parentName:"p"},"COPY")," works like ",Object(a.b)("strong",{parentName:"p"},"cp")," linux command. First argument is the source and second one is the destination."),Object(a.b)("p",null,"It's time to copy your source code in the image."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM :\nWORKDIR /app\nCOPY . .\n")),Object(a.b)("p",null,"Here, the elements of your ",Object(a.b)("strong",{parentName:"p"},"root")," folder from your current directory will be added inside the ",Object(a.b)("strong",{parentName:"p"},"/app")," folder."),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"You can use your current repository relative path (",Object(a.b)("strong",{parentName:"p"},".")," can be replaced by ",Object(a.b)("strong",{parentName:"p"},"./"),") if you want to add specific element (except the content of ",Object(a.b)("strong",{parentName:"p"},".dockerignore"),") to your image relative path (as we are already in the ",Object(a.b)("strong",{parentName:"p"},"/app")," folder, we can use ",Object(a.b)("strong",{parentName:"p"},"./"),").")),Object(a.b)("h3",{id:"run"},"RUN"),Object(a.b)("p",null,"One does not simply get source code to run an application."),Object(a.b)("p",null,"Most of the time, you have some stuff to do before an application execution like downloading/installing peer dependencies and build your application."),Object(a.b)("p",null,"That's the purpose of ",Object(a.b)("strong",{parentName:"p"},"RUN")," lines; it will execute a command and wait to finish the task to go forward."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),'FROM :\nWORKDIR /app\nCOPY . .\nRUN echo "Installing or doing stuff."\nRUN \n')),Object(a.b)("p",null,"You can set as many ",Object(a.b)("strong",{parentName:"p"},"RUN")," lines as you need."),Object(a.b)("h3",{id:"expose"},"EXPOSE"),Object(a.b)("p",null,"If your app needs to be reached from outside the container, you have to open its listening port. ",Object(a.b)("strong",{parentName:"p"},"EXPOSE")," is made for this."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),'FROM :\nWORKDIR /app\nCOPY . .\nRUN echo "Installing or doing stuff"\nRUN \nEXPOSE \n')),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Typical mistakes are made application configuration side. Ensure your application will listen on all interfaces ",Object(a.b)("strong",{parentName:"p"},"0.0.0.0")," and not only localhost ",Object(a.b)("strong",{parentName:"p"},"127.0.0.1"),".")),Object(a.b)("h3",{id:"cmd"},"CMD"),Object(a.b)("p",null,"Your application is now ready to run."),Object(a.b)("p",null,"The last thing to do is to specify how to execute it. Add the ",Object(a.b)("strong",{parentName:"p"},"CMD")," line with the same command with all the arguments you use locally to launch your application."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),'FROM :\nWORKDIR /app\nCOPY . .\nRUN echo "Installing or doing stuff"\nRUN \nEXPOSE \nCMD [ "", "", "" ]\n')),Object(a.b)("p",null,"Like a local usage, you can set as many arguments as needed."),Object(a.b)("h3",{id:"build-your-image"},"Build your image"),Object(a.b)("p",null,"When Qovery uses your Dockerfile, it first builds it before running it."),Object(a.b)("p",null,"If the build fails, Qovery won't be able to launch our application. To simplify debugging, you can build your image locally if you have Docker installed on your computer."),Object(a.b)("p",null,"Open a terminal and set the path at the Dockerfile location, and use the command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"cd ~/my/folder/where/my/code/is\ndocker build .\n")),Object(a.b)("p",null,"It will build your image based on your Dockerfile. You'll see all the logs related to all lines you've added in the Dockerfile."),Object(a.b)("p",null,"If something goes wrong, it will be printed onto the terminal, and you'll be able to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://stackoverflow.com/"}),"debug it"),"."),Object(a.b)("h3",{id:"test-your-image"},"Test your image"),Object(a.b)("p",null,"If your image builds properly, you can now check how it will be handle by Qovery with the command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"qovery run\n")),Object(a.b)("h2",{id:"whats-next"},"What's next?"),Object(a.b)("p",null,"If you follow this tutorial and everything works perfectly, it's time to deploy your app on Qovery. You will find all the things you need to know ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.qovery.com/docs/using-qovery/configuration/"}),"here"),"."),Object(a.b)(c.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}d.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return n?o.a.createElement(m,c({ref:t},u,{components:n})):o.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,u=void 0===l?n:o(l,n);u>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(430),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,p=Object(c.a)(s),b=Object(o.useRef)(!1),d=u.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(s),function(){d&&t&&t.disconnect()}}),[s,d,p]),s&&p?a.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(s),b.current=!0)},innerRef:function(e){var n,r;d&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:s})):a.a.createElement("a",Object(r.a)({},e,{href:s}))}},429:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,p=e.to,b=c()("jump-to","jump-to--"+u,n),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?o.a.createElement("a",{href:p,target:s,className:b},d):o.a.createElement(a.a,{to:p,className:b},d)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file +/*! For license information please see bbfbe73c.5a9acd33.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[195],{346:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return d}));var r=n(1),o=n(9),a=(n(0),n(425)),i=n(424),c=n(431),l=n(429),u={last_modified_on:"2022-05-04",$schema:"/.meta/.schemas/guides.json",title:"How to write a Dockerfile",description:"How to write your first Dockerfile in order to deploy your application with Qovery",author_github:"https://github.com/MacLikorne",tags:["type: tutorial","technology: docker"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to write a Dockerfile",description:"How to write your first Dockerfile in order to deploy your application with Qovery",permalink:"/guides/tutorial/how-to-write-a-dockerfile",readingTime:"5 min read",source:"@site/guides/tutorial/how-to-write-a-dockerfile.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: docker",permalink:"/guides/tags/technology-docker"}],title:"How to write a Dockerfile",truncated:!1,prevItem:{title:"How To Use Lifecycle Job To Deploy Any Kind Of Resources",permalink:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources"},nextItem:{title:"Import your environment variables with the Qovery CLI",permalink:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli"}},p=[{value:"My Sweet Dockerfile",id:"my-sweet-dockerfile",children:[{value:"FROM",id:"from",children:[]},{value:"WORKDIR",id:"workdir",children:[]},{value:"COPY",id:"copy",children:[]},{value:"RUN",id:"run",children:[]},{value:"EXPOSE",id:"expose",children:[]},{value:"CMD",id:"cmd",children:[]},{value:"Build your image",id:"build-your-image",children:[]},{value:"Test your image",id:"test-your-image",children:[]}]},{value:"What's next?",id:"whats-next",children:[]}],b={rightToc:p};function d(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"With Qovery, there are two ways to build and deploy your application:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Without a Dockerfile in your repository: your application is built with ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://docs.qovery.com/docs/using-qovery/configuration/application/#option-1-buildpacks"}),"Buildpacks")),Object(a.b)("li",{parentName:"ol"},"With a Dockerfile: sometimes Buildpacks won't fit your specific setup, and you'll have to write your Dockerfile.")),Object(a.b)("p",null,"In this article, we'll see, step by step, how to quickly write a proper Dockerfile for any application you would like to deploy."),Object(a.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have installed the ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://docs.qovery.com/docs/using-qovery/interface/cli/"}),"Qovery CLI")),Object(a.b)("li",{parentName:"ul"},"You host your code on Github"))),Object(a.b)("hr",null),Object(a.b)("h2",{id:"my-sweet-dockerfile"},"My Sweet Dockerfile"),Object(a.b)("p",null,"If you read this, you probably don't know why Docker is used and what is the purpose of a Dockerfile."),Object(a.b)("p",null,"Docker is a container engine, building and using images to deploy applications in containers. It looks like virtualization, and each container could be compared to a virtual machine with the minimal setup to run an application."),Object(a.b)("p",null,"The Dockerfile is your image builder recipe. When Docker uses it, it will follow all instructions to ",Object(a.b)("strong",{parentName:"p"},"build your application and run it"),"."),Object(a.b)("p",null,"The first step is to create a file named ",Object(a.b)("strong",{parentName:"p"},"Dockerfile")," at your project root level so Qovery would be able to find and use it."),Object(a.b)("p",null,"Also, to avoid unwanted files from your repository (images, .idea, DS_Store etc.), you need to add a ",Object(a.b)("strong",{parentName:"p"},".dockerignore"),". It will prevent heavy copy tasks of useless files, mostly your project dependencies and libraries you'll get back to with your package manager."),Object(a.b)("p",null,"The ",Object(a.b)("strong",{parentName:"p"},".dockerignore")," file works like the ",Object(a.b)("strong",{parentName:"p"},".gitignore"),", so add all the path of the useless files and folders in it."),Object(a.b)("h3",{id:"from"},"FROM"),Object(a.b)("p",null,"The first line you'll add in your Dockerfile is ",Object(a.b)("strong",{parentName:"p"},"FROM"),"."),Object(a.b)("p",null,"It will pull an already existing image from ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.docker.com/"}),"Docker Hub"),". You should most of the time use an image that fits your application language (Node, Python, Java, etc.), but you can go a step backward and begin with a simple Linux image."),Object(a.b)("p",null,"Your Dockerfile's first line should look like this:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM :\n")),Object(a.b)("p",null,"For example, with ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.docker.com/_/python"}),"python"),":"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM python:3\n")),Object(a.b)("h3",{id:"workdir"},"WORKDIR"),Object(a.b)("p",null,"Since most of the images are Linux-based, a good practice is to set up a directory you'll work in. That's the purpose of the ",Object(a.b)("strong",{parentName:"p"},"WORKDIR")," line. It defines a directory and moves you in:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM :\nWORKDIR /app\n")),Object(a.b)("p",null,"If you now work with a relative path (./), it will be in the ",Object(a.b)("em",{parentName:"p"},"app")," directory."),Object(a.b)("h3",{id:"copy"},"COPY"),Object(a.b)("p",null,"Now you have defined your base image and your working directory, it's time to add your code in. ",Object(a.b)("strong",{parentName:"p"},"COPY")," works like ",Object(a.b)("strong",{parentName:"p"},"cp")," linux command. First argument is the source and second one is the destination."),Object(a.b)("p",null,"It's time to copy your source code in the image."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"FROM :\nWORKDIR /app\nCOPY . .\n")),Object(a.b)("p",null,"Here, the elements of your ",Object(a.b)("strong",{parentName:"p"},"root")," folder from your current directory will be added inside the ",Object(a.b)("strong",{parentName:"p"},"/app")," folder."),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"You can use your current repository relative path (",Object(a.b)("strong",{parentName:"p"},".")," can be replaced by ",Object(a.b)("strong",{parentName:"p"},"./"),") if you want to add specific element (except the content of ",Object(a.b)("strong",{parentName:"p"},".dockerignore"),") to your image relative path (as we are already in the ",Object(a.b)("strong",{parentName:"p"},"/app")," folder, we can use ",Object(a.b)("strong",{parentName:"p"},"./"),").")),Object(a.b)("h3",{id:"run"},"RUN"),Object(a.b)("p",null,"One does not simply get source code to run an application."),Object(a.b)("p",null,"Most of the time, you have some stuff to do before an application execution like downloading/installing peer dependencies and build your application."),Object(a.b)("p",null,"That's the purpose of ",Object(a.b)("strong",{parentName:"p"},"RUN")," lines; it will execute a command and wait to finish the task to go forward."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),'FROM :\nWORKDIR /app\nCOPY . .\nRUN echo "Installing or doing stuff."\nRUN \n')),Object(a.b)("p",null,"You can set as many ",Object(a.b)("strong",{parentName:"p"},"RUN")," lines as you need."),Object(a.b)("h3",{id:"expose"},"EXPOSE"),Object(a.b)("p",null,"If your app needs to be reached from outside the container, you have to open its listening port. ",Object(a.b)("strong",{parentName:"p"},"EXPOSE")," is made for this."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),'FROM :\nWORKDIR /app\nCOPY . .\nRUN echo "Installing or doing stuff"\nRUN \nEXPOSE \n')),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Typical mistakes are made application configuration side. Ensure your application will listen on all interfaces ",Object(a.b)("strong",{parentName:"p"},"0.0.0.0")," and not only localhost ",Object(a.b)("strong",{parentName:"p"},"127.0.0.1"),".")),Object(a.b)("h3",{id:"cmd"},"CMD"),Object(a.b)("p",null,"Your application is now ready to run."),Object(a.b)("p",null,"The last thing to do is to specify how to execute it. Add the ",Object(a.b)("strong",{parentName:"p"},"CMD")," line with the same command with all the arguments you use locally to launch your application."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),'FROM :\nWORKDIR /app\nCOPY . .\nRUN echo "Installing or doing stuff"\nRUN \nEXPOSE \nCMD [ "", "", "" ]\n')),Object(a.b)("p",null,"Like a local usage, you can set as many arguments as needed."),Object(a.b)("h3",{id:"build-your-image"},"Build your image"),Object(a.b)("p",null,"When Qovery uses your Dockerfile, it first builds it before running it."),Object(a.b)("p",null,"If the build fails, Qovery won't be able to launch our application. To simplify debugging, you can build your image locally if you have Docker installed on your computer."),Object(a.b)("p",null,"Open a terminal and set the path at the Dockerfile location, and use the command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"cd ~/my/folder/where/my/code/is\ndocker build .\n")),Object(a.b)("p",null,"It will build your image based on your Dockerfile. You'll see all the logs related to all lines you've added in the Dockerfile."),Object(a.b)("p",null,"If something goes wrong, it will be printed onto the terminal, and you'll be able to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://stackoverflow.com/"}),"debug it"),"."),Object(a.b)("h3",{id:"test-your-image"},"Test your image"),Object(a.b)("p",null,"If your image builds properly, you can now check how it will be handle by Qovery with the command:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"qovery run\n")),Object(a.b)("h2",{id:"whats-next"},"What's next?"),Object(a.b)("p",null,"If you follow this tutorial and everything works perfectly, it's time to deploy your app on Qovery. You will find all the things you need to know ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.qovery.com/docs/using-qovery/configuration/"}),"here"),"."),Object(a.b)(c.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}d.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return n?o.a.createElement(m,c({ref:t},u,{components:n})):o.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,u=void 0===l?n:o(l,n);u>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(432),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,p=Object(c.a)(s),b=Object(o.useRef)(!1),d=u.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(s),function(){d&&t&&t.disconnect()}}),[s,d,p]),s&&p?a.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(s),b.current=!0)},innerRef:function(e){var n,r;d&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:s})):a.a.createElement("a",Object(r.a)({},e,{href:s}))}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,p=e.to,b=c()("jump-to","jump-to--"+u,n),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?o.a.createElement("a",{href:p,target:s,className:b},d):o.a.createElement(a.a,{to:p,className:b},d)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/bd10520b.f65b2c3a.js.LICENSE.txt b/bbfbe73c.5a9acd33.js.LICENSE.txt similarity index 100% rename from bd10520b.f65b2c3a.js.LICENSE.txt rename to bbfbe73c.5a9acd33.js.LICENSE.txt diff --git a/bc592dc7.b840c1c5.js b/bc592dc7.69c0a2c3.js similarity index 96% rename from bc592dc7.b840c1c5.js rename to bc592dc7.69c0a2c3.js index b81316a1a2..588c4350fe 100644 --- a/bc592dc7.b840c1c5.js +++ b/bc592dc7.69c0a2c3.js @@ -1,2 +1,2 @@ -/*! For license information please see bc592dc7.b840c1c5.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[193],{344:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return c})),a.d(t,"metadata",(function(){return s})),a.d(t,"rightToc",(function(){return l})),a.d(t,"default",(function(){return p}));var r=a(1),n=a(9),o=(a(0),a(422)),i=(a(421),a(426),a(429)),c={last_modified_on:"2021-10-18",$schema:"/.meta/.schemas/guides.json",title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1",readingTime:"11 min read",source:"@site/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",truncated:!1,prevItem:{title:"How to activate SSO to connect to your EKS cluster",permalink:"/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster"},nextItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2"}},l=[{value:"Before getting started",id:"before-getting-started",children:[{value:"Motivation",id:"motivation",children:[]},{value:"Why AppWrite",id:"why-appwrite",children:[]}]},{value:"Technologies",id:"technologies",children:[]},{value:"Architecture",id:"architecture",children:[{value:"User flow 1: Customer request an AppWrite instance",id:"user-flow-1-customer-request-an-appwrite-instance",children:[]},{value:"User flow 2: customer deletes an AppWrite instance",id:"user-flow-2-customer-deletes-an-appwrite-instance",children:[]},{value:"AppWrite cloud frontend and backend (control plane)",id:"appwrite-cloud-frontend-and-backend-control-plane",children:[]},{value:"Qovery and AWS",id:"qovery-and-aws",children:[]},{value:"Qovery and other cloud providers",id:"qovery-and-other-cloud-providers",children:[]},{value:"MariaDB - Data persistence and backup",id:"mariadb---data-persistence-and-backup",children:[]}]},{value:"Contributors",id:"contributors",children:[]},{value:"What\u2019s next",id:"whats-next",children:[]}],u={rightToc:l};function p(e){var t=e.components,a=Object(n.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"As a developer, I am super impressed by the number of great open-source projects popping around. I think of ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://supabase.io/"}),"Supabase")," (an open-source alternative to Firebase), ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://strapi.io/"}),"Strapi")," (open-source headless CMS), ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.meilisearch.com/"}),"Meilisearch")," (open-source search engine), ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://posthog.com/"}),"Posthog")," (open-source product analytics tool), and so many others. For me, these are the tools that most developers will use in the future. One common method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. It is exactly what ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hasura.io/cloud/"}),"Hasura")," did with its cloud version - and it is pretty convenient to use their product in production. However, building a cloud version takes months (sometimes years). What takes time? Hiring platform engineers, building the infrastructure, testing it, monitoring it... All of that takes a considerable amount of time and effort. Luckily, at Qovery, we provide the infrastructure stack that every open-source project needs to build 90% of their cloud-managed version. The remaining 10% are the UI and the business model logic. In this 6-part article series, I will attempt to explain how to build a cloud-managed version of AppWrite. Let\u2019s go!"),Object(o.b)("p",null,"Articles:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Part 1: Introduction and architecture"),Object(o.b)("li",{parentName:"ul"},"Part 2: Build our AppWrite cloud backend and integrate it with the Qovery API"),Object(o.b)("li",{parentName:"ul"},"Part 3: Build our AppWrite cloud frontend and combine it with our cloud backend"),Object(o.b)("li",{parentName:"ul"},"Part 4: Monitor our AppWrite cloud version"),Object(o.b)("li",{parentName:"ul"},"Part 5: Integrate the payment system with Stripe (optional)"),Object(o.b)("li",{parentName:"ul"},"Part 6: Integrate email notification with Courier (optional)"),Object(o.b)("li",{parentName:"ul"},"Part 7: Give your customer a production, staging, and dev environment (optional)")),Object(o.b)("h2",{id:"before-getting-started"},"Before getting started"),Object(o.b)("h3",{id:"motivation"},"Motivation"),Object(o.b)("p",null,"Since I launched ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/"}),"Qovery")," in 2019, I have talked to dozens of founders from great open-source software companies. Most of them were looking to build their cloud-managed service at some point. Some of them even asked me for feedback on building one and asked me to use Qovery as a white-label technology when they discovered it was a full-time job. Qovery is a product simplifying app deployment and infrastructure management on AWS. Time flies, and as Qovery evolves, it is now possible for any open-source project to use Qovery as a white-label technology to provide a cloud version of an open-source project. No hidden cost. Just pick the plan that fits you best and build your cloud version in days instead of months. My team will be proud to help you in your success."),Object(o.b)("h3",{id:"why-appwrite"},"Why AppWrite"),Object(o.b)("p",null,Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://appwrite.io/"}),"AppWrite")," is quite representative of a \u201cmodern web open-source project\u201d. In this guide, AppWrite is used as a demo project to demonstrate the concept of building a cloud-managed version for an open-source web project. AppWrite is written in PHP for the backend and JS for the frontend. It provides a user-friendly web interface connected to a web API, and it stores the data in MariaDB and Redis databases. The idea is: if it works for AppWrite, then it is good to work for any other web open-source project with a similar technical stack. Feel free to ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://twitter.com/rophilogene"}),"contact me")," if you have any concerns."),Object(o.b)("h2",{id:"technologies"},"Technologies"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"AppWrite is a Backend as a Service open-source software. It is similar to Supabase and Firebase to create a backend in a few minutes.")),Object(o.b)("p",null,"Our goal is to provide a fully managed cloud version of AppWrite. Meaning we need to deliver to our customers a way to order their AppWrite instance and use it, while the maintenance is handled by us. It is the most common managed version out there - think MongoDB Atlas. To achieve this, we will use the following technologies:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://appwrite.io/"}),"AppWrite")),": We will use ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.docker.com/r/appwrite/appwrite"}),"AppWrite Docker container image")," to run the latest version of AppWrite."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://mariadb.org/"}),"MariaDB")),": AppWrite is using a MariaDB server for managing persistent database data."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://redis.io/"}),"Redis")),": AppWrite uses a Redis server for managing cache, queues, and scheduled tasks."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://aws.amazon.com/fr/"}),"AWS")),": We will host AppWrite on AWS EKS (Kubernetes), Redis (in-memory database), and MariaDB (AWS RDS) for each customer on AWS."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.qovery.com/"}),"Qovery")),": Qovery will create an environment composed of AppWrite, Redis, and MariaDB for each customer on our AWS account."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://hasura.io/"}),"Hasura")),": Low-code GraphQL backend to manage our customers\u2019 data."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.gatsbyjs.com/"}),"GatsbyJS")),": JS frontend framework to provide a web interface to our customers."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.postgresql.org/"}),"PostgreSQL")),": database to store our customers\u2019 data"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://auth0.com/fr"}),"Auth0")),": To manage the auth of our customers."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://stripe.com/fr"}),"Stripe")),": To charge our customers."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.courier.com/"}),"Courier")),": To send an email and Slack notifications to our customers.")),Object(o.b)("p",null,"This bunch of technologies combined enable us to build a cloud version for AppWrite. Let\u2019s take a deeper look at how all of them are interconnected."),Object(o.b)("h2",{id:"architecture"},"Architecture"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/oss-cloud-managed/part-1/architecture.svg",alt:"architecture schema"})),Object(o.b)("p",null,"This schema represents the different layers composing the cloud version of AppWrite. From top to bottom, we will give the details of each layer."),Object(o.b)("h3",{id:"user-flow-1-customer-request-an-appwrite-instance"},"User flow 1: Customer request an AppWrite instance"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/oss-cloud-managed/part-1/flow1.png",alt:"customer request an appwrite instance - behind the scene"})),Object(o.b)("p",null,"Here is what happens when the customer requests a cloud AppWrite instance:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"The customer connects on ",Object(o.b)("inlineCode",{parentName:"li"},"cloud.appwrite.com")," (fake domain to represent \u201cAppWrite cloud frontend\u201d)."),Object(o.b)("li",{parentName:"ol"},"The customer requests a new AppWrite instance."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create an ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/environment/"}),"Environment"),"."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create a MariaDB database."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create a Redis database."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create an AppWrite application."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to bind the AppWrite application to the MariaDB and Redis databases."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to start the Environment."),Object(o.b)("li",{parentName:"ol"},"The Qovery API returns the temporary URL to the AppWrite cloud backend."),Object(o.b)("li",{parentName:"ol"},"The customer receives the URL of his instance via the AppWrite cloud frontend."),Object(o.b)("li",{parentName:"ol"},"The customer can use his AppWrite instance.")),Object(o.b)("h3",{id:"user-flow-2-customer-deletes-an-appwrite-instance"},"User flow 2: customer deletes an AppWrite instance"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/oss-cloud-managed/part-1/flow2.png",alt:"customer deletes an appwrite instance - behind the scene"})),Object(o.b)("p",null,"Let\u2019s say our customer now wants to delete his cloud AppWrite instance; this is what happens:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"The customer connects on ",Object(o.b)("inlineCode",{parentName:"li"},"cloud.appwrite.com")," (fake domain to represent \u201cAppWrite cloud frontend\u201d)."),Object(o.b)("li",{parentName:"ol"},"The customer removes his AppWrite instance."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to delete the customer ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/environment/"}),"Environment"),"."),Object(o.b)("li",{parentName:"ol"},"Qovery deletes the AppWrite application, MariaDB, and Redis databases.")),Object(o.b)("p",null,"We can add other steps like payment (part 5), notifications (part 6), and everything you want - they are not required to make our cloud version functional. Let\u2019s now take a deeper look at the infrastructure."),Object(o.b)("h3",{id:"appwrite-cloud-frontend-and-backend-control-plane"},"AppWrite cloud frontend and backend (control plane)"),Object(o.b)("p",null,"The AppWrite cloud frontend and backend are the two components that we have to build from scratch. It includes our business logic and customer management system. We will use ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hasura.io/"}),"Hasura")," for the backend and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.gatsbyjs.com/"}),"GatsbyJS")," for the frontend. We will connect the frontend to the backend via a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://graphql.org/"}),"GraphQL")," API. The advantage of using Hasura instead of coding our web backend is that we have access to many features (Auth0, Stripe support...) right away. Saving days of work."),Object(o.b)("p",null,"The goal here is to provide to the customers a web interface to:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Create, update, stop, restart, delete AppWrite instances."),Object(o.b)("li",{parentName:"ul"},"Configure their custom domain."),Object(o.b)("li",{parentName:"ul"},"Charge our customers and let them pay for their subscriptions")),Object(o.b)("h3",{id:"qovery-and-aws"},"Qovery and AWS"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/"}),"Qovery")," is the simplest way to deploy apps and manage your infrastructure on AWS. We will use Qovery as an Infrastructure as Code (IaC) API.")),Object(o.b)("p",null,"Qovery provides a production-ready infrastructure on our AWS account in 30 minutes that we will use to host our customers\u2019 instances. The ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API")," provides a high-level abstraction to create for each customer an isolated ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/environment/"}),"Environment")," including:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"An AppWrite app instance with the possibility to scale it horizontally."),Object(o.b)("li",{parentName:"ol"},"A MariaDB database."),Object(o.b)("li",{parentName:"ol"},"A Redis database."),Object(o.b)("li",{parentName:"ol"},"An HTTPS endpoint."),Object(o.b)("li",{parentName:"ol"},"The option to bind a custom domain with TLS."),Object(o.b)("li",{parentName:"ol"},"A secure API to manage Environment variables and Secrets.")),Object(o.b)("p",null,"Each Environment is isolated and will be accessible for only one customer. And as admin, Qovery provides a web interface to manage all our customers\u2019 instances and troubleshoot any of their issues."),Object(o.b)("p",null,Object(o.b)("em",{parentName:"p"},"Curious to know more about how Qovery works? Take a look at ",Object(o.b)("a",Object(r.a)({parentName:"em"},{href:"https://hub.qovery.com/docs/devops/qovery-for-devops-introduction/"}),"this page"),".")),Object(o.b)("h3",{id:"qovery-and-other-cloud-providers"},"Qovery and other cloud providers"),Object(o.b)("p",null,"Qovery supports ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes/"}),"AWS"),", ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-digital-ocean/"}),"Digital Ocean"),", and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-scaleway/"}),"Scaleway"),". In this guide, we will focus on AWS to make it simpler. But keep in mind that you can use another supported cloud provider. You can even imagine a feature where your customers can choose the cloud provider of their choice. This is exactly what \u201cMongoDB Atlas\u201d and \u201cHasura Cloud\u201d do."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Side note"),": Qovery will support ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-google-cloud-platform/"}),"Google Cloud Platform")," and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-microsoft-azure/"}),"Microsoft Azure")," for S1 2022."),Object(o.b)("h3",{id:"mariadb---data-persistence-and-backup"},"MariaDB - Data persistence and backup"),Object(o.b)("p",null,"Our customers expect us to provide a reliable service and manage the database backups by using a cloud version. For AppWrite, MariaDB is the persistent database and needs to be backed up. Four options with pros and cons do exist:"),Object(o.b)("h4",{id:"1st-option-single-tenant-mariadb-container"},"1st option: single-tenant MariaDB container"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Cheap"),Object(o.b)("li",{parentName:"ul"},"Fast to spawn"),Object(o.b)("li",{parentName:"ul"},"Physical isolation per customer"),Object(o.b)("li",{parentName:"ul"},"Decent performance")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have to manage the backups")),Object(o.b)("h4",{id:"2nd-option-multi-tenant-mariadb-container"},"2nd option: multi-tenant MariaDB container"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The cheapest option (1 container divided by the number of customers means higher margins)"),Object(o.b)("li",{parentName:"ul"},"Fast to spawn")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have to manage the backups"),Object(o.b)("li",{parentName:"ul"},"No physical isolation per customer"),Object(o.b)("li",{parentName:"ul"},"The more you have customers, the poorest the performance is."),Object(o.b)("li",{parentName:"ul"},"Potential security breaches as many customers are using the same database instance.")),Object(o.b)("h4",{id:"3rd-option-single-tenant-managed-mariadb-database-aws-rds-mariadb"},"3rd option: single-tenant managed MariaDB database (AWS RDS MariaDB)"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Backup managed by AWS (point-in-time recovery included)"),Object(o.b)("li",{parentName:"ul"},"Physical isolation per customer (security++)"),Object(o.b)("li",{parentName:"ul"},"The most performant"),Object(o.b)("li",{parentName:"ul"},"Scalable (managed by AWS)")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The most expensive option (~$11 per instance for the cheapest one on AWS US-EAST-2)")),Object(o.b)("h4",{id:"4th-option-multi-tenant-managed-mariadb-database-aws-rds-mariadb"},"4th option: multi-tenant managed MariaDB database (AWS RDS MariaDB)"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Backup managed by AWS (point-in-time recovery included)"),Object(o.b)("li",{parentName:"ul"},"Higher performance than container version"),Object(o.b)("li",{parentName:"ul"},"Scalable (managed by AWS)"),Object(o.b)("li",{parentName:"ul"},"Expensive for a few customers, but the more customers you have, the cheaper it is.")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The most expensive option (~$11 per instance for the cheapest one on AWS us-east-2)"),Object(o.b)("li",{parentName:"ul"},"Potential security breaches as many customers are using the same database instance.")),Object(o.b)("p",null,"We will pick the third option (single-tenant with managed MariaDB database) to create a state-of-the-art cloud version, but you are free to choose the one you want for your customer. Do not forget your customer expects you to take care of their business."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Side note"),": AppWrite uses Redis as a caching system. Then, we will use a Redis container instance which is the cheapest."),Object(o.b)("h2",{id:"contributors"},"Contributors"),Object(o.b)("p",null,"Here is the list of contributors to this first part:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Ricardo Sueiras - Principal Advocate in OSS at AWS"),Object(o.b)("li",{parentName:"ul"},"Raman Sharma - VP Product Marketing at DigitalOcean"),Object(o.b)("li",{parentName:"ul"},"Anton Babenko - AWS Community Hero and Hashicorp Ambassador"),Object(o.b)("li",{parentName:"ul"},"Javier Viola Villanueva - Simulation Network Lead at Parity"),Object(o.b)("li",{parentName:"ul"},"Ziad Ghalleb - Product Marketing Manager at Gitguardian"),Object(o.b)("li",{parentName:"ul"},"Oliver Juhl - CTO and co-founder at Medusa"),Object(o.b)("li",{parentName:"ul"},"Yann Irbah - SRE at Fewlines"),Object(o.b)("li",{parentName:"ul"},"Laurent Doguin - ex VP Developer Relation at Clever Cloud"),Object(o.b)("li",{parentName:"ul"},"Qovery Team and our community ambassadors (Aggis, Stun3r, Kartik)")),Object(o.b)("p",null,"Thank you to our contributors for their review and suggestions."),Object(o.b)("h2",{id:"whats-next"},"What\u2019s next"),Object(o.b)("p",null,"Thank you all for taking the time to read until the end. We will build our AppWrite cloud backend and integrate it into the Qovery API in the next part."),Object(o.b)(i.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}p.isMDXComponent=!0},420:function(e,t,a){var r;!function(){"use strict";var a={}.hasOwnProperty;function n(){for(var e=[],t=0;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var l=n.a.createContext({}),u=function(e){var t=n.a.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):c({},t,{},e)),a},p=function(e){var t=u(e.components);return n.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(a),d=r,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return a?n.a.createElement(m,c({ref:t},l,{components:a})):n.a.createElement(m,c({ref:t},l))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,a),s=i>2?arguments[2]:void 0,l=void 0===s?a:n(s,a);l>c;)t[c++]=e;return t}},425:function(e,t,a){var r=a(28).f,n=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in n||a(10)&&r(n,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var r=a(0),n=a.n(r),o=a(421);t.a=function(e){var t=e.children,a=e.name;return n.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},427:function(e,t,a){"use strict";var r=a(1),n=a(0),o=a.n(n),i=a(39),c=a(430),s=a(20),l=a.n(s);t.a=function(e){var t,a=e.to,s=e.href,u=a||s,p=Object(c.a)(u),b=Object(n.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(n.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var a,r;d&&e&&p&&(a=e,r=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),r())}))}))).observe(a))},to:u})):o.a.createElement("a",Object(r.a)({},e,{href:u}))}},429:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=a(427),i=a(420),c=a.n(i);a(133);t.a=function(e){var t=e.children,a=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+l,a),d=n.a.createElement("div",{className:"jump-to--inner"},n.a.createElement("div",{className:"jump-to--inner-2"},i&&n.a.createElement("div",{className:"jump-to--left"},n.a.createElement("i",{className:"feather icon-"+i})),n.a.createElement("div",{className:"jump-to--main"},r?n.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),n.a.createElement("div",{className:"jump-to--right"},n.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?n.a.createElement("a",{href:p,target:u,className:b},d):n.a.createElement(o.a,{to:p,className:b},d)}},430:function(e,t,a){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return r}))}}]); \ No newline at end of file +/*! For license information please see bc592dc7.69c0a2c3.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[196],{347:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return c})),a.d(t,"metadata",(function(){return s})),a.d(t,"rightToc",(function(){return l})),a.d(t,"default",(function(){return p}));var r=a(1),n=a(9),o=(a(0),a(425)),i=(a(424),a(429),a(431)),c={last_modified_on:"2021-10-18",$schema:"/.meta/.schemas/guides.json",title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",description:"Open-source eat the world. More and more great open-source projects are used. One standard method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. This guide will attempt to explain how to build a cloud-managed version of an open-source project.",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1",readingTime:"11 min read",source:"@site/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1",truncated:!1,prevItem:{title:"How to activate SSO to connect to your EKS cluster",permalink:"/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster"},nextItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2"}},l=[{value:"Before getting started",id:"before-getting-started",children:[{value:"Motivation",id:"motivation",children:[]},{value:"Why AppWrite",id:"why-appwrite",children:[]}]},{value:"Technologies",id:"technologies",children:[]},{value:"Architecture",id:"architecture",children:[{value:"User flow 1: Customer request an AppWrite instance",id:"user-flow-1-customer-request-an-appwrite-instance",children:[]},{value:"User flow 2: customer deletes an AppWrite instance",id:"user-flow-2-customer-deletes-an-appwrite-instance",children:[]},{value:"AppWrite cloud frontend and backend (control plane)",id:"appwrite-cloud-frontend-and-backend-control-plane",children:[]},{value:"Qovery and AWS",id:"qovery-and-aws",children:[]},{value:"Qovery and other cloud providers",id:"qovery-and-other-cloud-providers",children:[]},{value:"MariaDB - Data persistence and backup",id:"mariadb---data-persistence-and-backup",children:[]}]},{value:"Contributors",id:"contributors",children:[]},{value:"What\u2019s next",id:"whats-next",children:[]}],u={rightToc:l};function p(e){var t=e.components,a=Object(n.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"As a developer, I am super impressed by the number of great open-source projects popping around. I think of ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://supabase.io/"}),"Supabase")," (an open-source alternative to Firebase), ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://strapi.io/"}),"Strapi")," (open-source headless CMS), ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.meilisearch.com/"}),"Meilisearch")," (open-source search engine), ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://posthog.com/"}),"Posthog")," (open-source product analytics tool), and so many others. For me, these are the tools that most developers will use in the future. One common method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. It is exactly what ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hasura.io/cloud/"}),"Hasura")," did with its cloud version - and it is pretty convenient to use their product in production. However, building a cloud version takes months (sometimes years). What takes time? Hiring platform engineers, building the infrastructure, testing it, monitoring it... All of that takes a considerable amount of time and effort. Luckily, at Qovery, we provide the infrastructure stack that every open-source project needs to build 90% of their cloud-managed version. The remaining 10% are the UI and the business model logic. In this 6-part article series, I will attempt to explain how to build a cloud-managed version of AppWrite. Let\u2019s go!"),Object(o.b)("p",null,"Articles:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Part 1: Introduction and architecture"),Object(o.b)("li",{parentName:"ul"},"Part 2: Build our AppWrite cloud backend and integrate it with the Qovery API"),Object(o.b)("li",{parentName:"ul"},"Part 3: Build our AppWrite cloud frontend and combine it with our cloud backend"),Object(o.b)("li",{parentName:"ul"},"Part 4: Monitor our AppWrite cloud version"),Object(o.b)("li",{parentName:"ul"},"Part 5: Integrate the payment system with Stripe (optional)"),Object(o.b)("li",{parentName:"ul"},"Part 6: Integrate email notification with Courier (optional)"),Object(o.b)("li",{parentName:"ul"},"Part 7: Give your customer a production, staging, and dev environment (optional)")),Object(o.b)("h2",{id:"before-getting-started"},"Before getting started"),Object(o.b)("h3",{id:"motivation"},"Motivation"),Object(o.b)("p",null,"Since I launched ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/"}),"Qovery")," in 2019, I have talked to dozens of founders from great open-source software companies. Most of them were looking to build their cloud-managed service at some point. Some of them even asked me for feedback on building one and asked me to use Qovery as a white-label technology when they discovered it was a full-time job. Qovery is a product simplifying app deployment and infrastructure management on AWS. Time flies, and as Qovery evolves, it is now possible for any open-source project to use Qovery as a white-label technology to provide a cloud version of an open-source project. No hidden cost. Just pick the plan that fits you best and build your cloud version in days instead of months. My team will be proud to help you in your success."),Object(o.b)("h3",{id:"why-appwrite"},"Why AppWrite"),Object(o.b)("p",null,Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://appwrite.io/"}),"AppWrite")," is quite representative of a \u201cmodern web open-source project\u201d. In this guide, AppWrite is used as a demo project to demonstrate the concept of building a cloud-managed version for an open-source web project. AppWrite is written in PHP for the backend and JS for the frontend. It provides a user-friendly web interface connected to a web API, and it stores the data in MariaDB and Redis databases. The idea is: if it works for AppWrite, then it is good to work for any other web open-source project with a similar technical stack. Feel free to ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://twitter.com/rophilogene"}),"contact me")," if you have any concerns."),Object(o.b)("h2",{id:"technologies"},"Technologies"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"AppWrite is a Backend as a Service open-source software. It is similar to Supabase and Firebase to create a backend in a few minutes.")),Object(o.b)("p",null,"Our goal is to provide a fully managed cloud version of AppWrite. Meaning we need to deliver to our customers a way to order their AppWrite instance and use it, while the maintenance is handled by us. It is the most common managed version out there - think MongoDB Atlas. To achieve this, we will use the following technologies:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://appwrite.io/"}),"AppWrite")),": We will use ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.docker.com/r/appwrite/appwrite"}),"AppWrite Docker container image")," to run the latest version of AppWrite."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://mariadb.org/"}),"MariaDB")),": AppWrite is using a MariaDB server for managing persistent database data."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://redis.io/"}),"Redis")),": AppWrite uses a Redis server for managing cache, queues, and scheduled tasks."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://aws.amazon.com/fr/"}),"AWS")),": We will host AppWrite on AWS EKS (Kubernetes), Redis (in-memory database), and MariaDB (AWS RDS) for each customer on AWS."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.qovery.com/"}),"Qovery")),": Qovery will create an environment composed of AppWrite, Redis, and MariaDB for each customer on our AWS account."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://hasura.io/"}),"Hasura")),": Low-code GraphQL backend to manage our customers\u2019 data."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.gatsbyjs.com/"}),"GatsbyJS")),": JS frontend framework to provide a web interface to our customers."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.postgresql.org/"}),"PostgreSQL")),": database to store our customers\u2019 data"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://auth0.com/fr"}),"Auth0")),": To manage the auth of our customers."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://stripe.com/fr"}),"Stripe")),": To charge our customers."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},Object(o.b)("a",Object(r.a)({parentName:"strong"},{href:"https://www.courier.com/"}),"Courier")),": To send an email and Slack notifications to our customers.")),Object(o.b)("p",null,"This bunch of technologies combined enable us to build a cloud version for AppWrite. Let\u2019s take a deeper look at how all of them are interconnected."),Object(o.b)("h2",{id:"architecture"},"Architecture"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/oss-cloud-managed/part-1/architecture.svg",alt:"architecture schema"})),Object(o.b)("p",null,"This schema represents the different layers composing the cloud version of AppWrite. From top to bottom, we will give the details of each layer."),Object(o.b)("h3",{id:"user-flow-1-customer-request-an-appwrite-instance"},"User flow 1: Customer request an AppWrite instance"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/oss-cloud-managed/part-1/flow1.png",alt:"customer request an appwrite instance - behind the scene"})),Object(o.b)("p",null,"Here is what happens when the customer requests a cloud AppWrite instance:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"The customer connects on ",Object(o.b)("inlineCode",{parentName:"li"},"cloud.appwrite.com")," (fake domain to represent \u201cAppWrite cloud frontend\u201d)."),Object(o.b)("li",{parentName:"ol"},"The customer requests a new AppWrite instance."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create an ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/environment/"}),"Environment"),"."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create a MariaDB database."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create a Redis database."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to create an AppWrite application."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to bind the AppWrite application to the MariaDB and Redis databases."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to start the Environment."),Object(o.b)("li",{parentName:"ol"},"The Qovery API returns the temporary URL to the AppWrite cloud backend."),Object(o.b)("li",{parentName:"ol"},"The customer receives the URL of his instance via the AppWrite cloud frontend."),Object(o.b)("li",{parentName:"ol"},"The customer can use his AppWrite instance.")),Object(o.b)("h3",{id:"user-flow-2-customer-deletes-an-appwrite-instance"},"User flow 2: customer deletes an AppWrite instance"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/oss-cloud-managed/part-1/flow2.png",alt:"customer deletes an appwrite instance - behind the scene"})),Object(o.b)("p",null,"Let\u2019s say our customer now wants to delete his cloud AppWrite instance; this is what happens:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"The customer connects on ",Object(o.b)("inlineCode",{parentName:"li"},"cloud.appwrite.com")," (fake domain to represent \u201cAppWrite cloud frontend\u201d)."),Object(o.b)("li",{parentName:"ol"},"The customer removes his AppWrite instance."),Object(o.b)("li",{parentName:"ol"},"The AppWrite cloud backend calls the Qovery API to delete the customer ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/environment/"}),"Environment"),"."),Object(o.b)("li",{parentName:"ol"},"Qovery deletes the AppWrite application, MariaDB, and Redis databases.")),Object(o.b)("p",null,"We can add other steps like payment (part 5), notifications (part 6), and everything you want - they are not required to make our cloud version functional. Let\u2019s now take a deeper look at the infrastructure."),Object(o.b)("h3",{id:"appwrite-cloud-frontend-and-backend-control-plane"},"AppWrite cloud frontend and backend (control plane)"),Object(o.b)("p",null,"The AppWrite cloud frontend and backend are the two components that we have to build from scratch. It includes our business logic and customer management system. We will use ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hasura.io/"}),"Hasura")," for the backend and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.gatsbyjs.com/"}),"GatsbyJS")," for the frontend. We will connect the frontend to the backend via a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://graphql.org/"}),"GraphQL")," API. The advantage of using Hasura instead of coding our web backend is that we have access to many features (Auth0, Stripe support...) right away. Saving days of work."),Object(o.b)("p",null,"The goal here is to provide to the customers a web interface to:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Create, update, stop, restart, delete AppWrite instances."),Object(o.b)("li",{parentName:"ul"},"Configure their custom domain."),Object(o.b)("li",{parentName:"ul"},"Charge our customers and let them pay for their subscriptions")),Object(o.b)("h3",{id:"qovery-and-aws"},"Qovery and AWS"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/"}),"Qovery")," is the simplest way to deploy apps and manage your infrastructure on AWS. We will use Qovery as an Infrastructure as Code (IaC) API.")),Object(o.b)("p",null,"Qovery provides a production-ready infrastructure on our AWS account in 30 minutes that we will use to host our customers\u2019 instances. The ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API")," provides a high-level abstraction to create for each customer an isolated ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/environment/"}),"Environment")," including:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"An AppWrite app instance with the possibility to scale it horizontally."),Object(o.b)("li",{parentName:"ol"},"A MariaDB database."),Object(o.b)("li",{parentName:"ol"},"A Redis database."),Object(o.b)("li",{parentName:"ol"},"An HTTPS endpoint."),Object(o.b)("li",{parentName:"ol"},"The option to bind a custom domain with TLS."),Object(o.b)("li",{parentName:"ol"},"A secure API to manage Environment variables and Secrets.")),Object(o.b)("p",null,"Each Environment is isolated and will be accessible for only one customer. And as admin, Qovery provides a web interface to manage all our customers\u2019 instances and troubleshoot any of their issues."),Object(o.b)("p",null,Object(o.b)("em",{parentName:"p"},"Curious to know more about how Qovery works? Take a look at ",Object(o.b)("a",Object(r.a)({parentName:"em"},{href:"https://hub.qovery.com/docs/devops/qovery-for-devops-introduction/"}),"this page"),".")),Object(o.b)("h3",{id:"qovery-and-other-cloud-providers"},"Qovery and other cloud providers"),Object(o.b)("p",null,"Qovery supports ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes/"}),"AWS"),", ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-digital-ocean/"}),"Digital Ocean"),", and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-scaleway/"}),"Scaleway"),". In this guide, we will focus on AWS to make it simpler. But keep in mind that you can use another supported cloud provider. You can even imagine a feature where your customers can choose the cloud provider of their choice. This is exactly what \u201cMongoDB Atlas\u201d and \u201cHasura Cloud\u201d do."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Side note"),": Qovery will support ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-google-cloud-platform/"}),"Google Cloud Platform")," and ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/advanced/guide-microsoft-azure/"}),"Microsoft Azure")," for S1 2022."),Object(o.b)("h3",{id:"mariadb---data-persistence-and-backup"},"MariaDB - Data persistence and backup"),Object(o.b)("p",null,"Our customers expect us to provide a reliable service and manage the database backups by using a cloud version. For AppWrite, MariaDB is the persistent database and needs to be backed up. Four options with pros and cons do exist:"),Object(o.b)("h4",{id:"1st-option-single-tenant-mariadb-container"},"1st option: single-tenant MariaDB container"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Cheap"),Object(o.b)("li",{parentName:"ul"},"Fast to spawn"),Object(o.b)("li",{parentName:"ul"},"Physical isolation per customer"),Object(o.b)("li",{parentName:"ul"},"Decent performance")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have to manage the backups")),Object(o.b)("h4",{id:"2nd-option-multi-tenant-mariadb-container"},"2nd option: multi-tenant MariaDB container"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The cheapest option (1 container divided by the number of customers means higher margins)"),Object(o.b)("li",{parentName:"ul"},"Fast to spawn")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have to manage the backups"),Object(o.b)("li",{parentName:"ul"},"No physical isolation per customer"),Object(o.b)("li",{parentName:"ul"},"The more you have customers, the poorest the performance is."),Object(o.b)("li",{parentName:"ul"},"Potential security breaches as many customers are using the same database instance.")),Object(o.b)("h4",{id:"3rd-option-single-tenant-managed-mariadb-database-aws-rds-mariadb"},"3rd option: single-tenant managed MariaDB database (AWS RDS MariaDB)"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Backup managed by AWS (point-in-time recovery included)"),Object(o.b)("li",{parentName:"ul"},"Physical isolation per customer (security++)"),Object(o.b)("li",{parentName:"ul"},"The most performant"),Object(o.b)("li",{parentName:"ul"},"Scalable (managed by AWS)")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The most expensive option (~$11 per instance for the cheapest one on AWS US-EAST-2)")),Object(o.b)("h4",{id:"4th-option-multi-tenant-managed-mariadb-database-aws-rds-mariadb"},"4th option: multi-tenant managed MariaDB database (AWS RDS MariaDB)"),Object(o.b)("p",null,"Pros:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Backup managed by AWS (point-in-time recovery included)"),Object(o.b)("li",{parentName:"ul"},"Higher performance than container version"),Object(o.b)("li",{parentName:"ul"},"Scalable (managed by AWS)"),Object(o.b)("li",{parentName:"ul"},"Expensive for a few customers, but the more customers you have, the cheaper it is.")),Object(o.b)("p",null,"Cons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The most expensive option (~$11 per instance for the cheapest one on AWS us-east-2)"),Object(o.b)("li",{parentName:"ul"},"Potential security breaches as many customers are using the same database instance.")),Object(o.b)("p",null,"We will pick the third option (single-tenant with managed MariaDB database) to create a state-of-the-art cloud version, but you are free to choose the one you want for your customer. Do not forget your customer expects you to take care of their business."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Side note"),": AppWrite uses Redis as a caching system. Then, we will use a Redis container instance which is the cheapest."),Object(o.b)("h2",{id:"contributors"},"Contributors"),Object(o.b)("p",null,"Here is the list of contributors to this first part:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Ricardo Sueiras - Principal Advocate in OSS at AWS"),Object(o.b)("li",{parentName:"ul"},"Raman Sharma - VP Product Marketing at DigitalOcean"),Object(o.b)("li",{parentName:"ul"},"Anton Babenko - AWS Community Hero and Hashicorp Ambassador"),Object(o.b)("li",{parentName:"ul"},"Javier Viola Villanueva - Simulation Network Lead at Parity"),Object(o.b)("li",{parentName:"ul"},"Ziad Ghalleb - Product Marketing Manager at Gitguardian"),Object(o.b)("li",{parentName:"ul"},"Oliver Juhl - CTO and co-founder at Medusa"),Object(o.b)("li",{parentName:"ul"},"Yann Irbah - SRE at Fewlines"),Object(o.b)("li",{parentName:"ul"},"Laurent Doguin - ex VP Developer Relation at Clever Cloud"),Object(o.b)("li",{parentName:"ul"},"Qovery Team and our community ambassadors (Aggis, Stun3r, Kartik)")),Object(o.b)("p",null,"Thank you to our contributors for their review and suggestions."),Object(o.b)("h2",{id:"whats-next"},"What\u2019s next"),Object(o.b)("p",null,"Thank you all for taking the time to read until the end. We will build our AppWrite cloud backend and integrate it into the Qovery API in the next part."),Object(o.b)(i.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}p.isMDXComponent=!0},423:function(e,t,a){var r;!function(){"use strict";var a={}.hasOwnProperty;function n(){for(var e=[],t=0;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var l=n.a.createContext({}),u=function(e){var t=n.a.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):c({},t,{},e)),a},p=function(e){var t=u(e.components);return n.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(a),d=r,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return a?n.a.createElement(m,c({ref:t},l,{components:a})):n.a.createElement(m,c({ref:t},l))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,a),s=i>2?arguments[2]:void 0,l=void 0===s?a:n(s,a);l>c;)t[c++]=e;return t}},428:function(e,t,a){var r=a(28).f,n=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in n||a(10)&&r(n,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var r=a(0),n=a.n(r),o=a(424);t.a=function(e){var t=e.children,a=e.name;return n.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},430:function(e,t,a){"use strict";var r=a(1),n=a(0),o=a.n(n),i=a(39),c=a(432),s=a(20),l=a.n(s);t.a=function(e){var t,a=e.to,s=e.href,u=a||s,p=Object(c.a)(u),b=Object(n.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(n.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var a,r;d&&e&&p&&(a=e,r=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),r())}))}))).observe(a))},to:u})):o.a.createElement("a",Object(r.a)({},e,{href:u}))}},431:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=a(430),i=a(423),c=a.n(i);a(133);t.a=function(e){var t=e.children,a=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+l,a),d=n.a.createElement("div",{className:"jump-to--inner"},n.a.createElement("div",{className:"jump-to--inner-2"},i&&n.a.createElement("div",{className:"jump-to--left"},n.a.createElement("i",{className:"feather icon-"+i})),n.a.createElement("div",{className:"jump-to--main"},r?n.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),n.a.createElement("div",{className:"jump-to--right"},n.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?n.a.createElement("a",{href:p,target:u,className:b},d):n.a.createElement(o.a,{to:p,className:b},d)}},432:function(e,t,a){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/bdd6d8c6.bce2bc95.js.LICENSE.txt b/bc592dc7.69c0a2c3.js.LICENSE.txt similarity index 100% rename from bdd6d8c6.bce2bc95.js.LICENSE.txt rename to bc592dc7.69c0a2c3.js.LICENSE.txt diff --git a/bd10520b.f65b2c3a.js b/bd10520b.3d6eeb84.js similarity index 88% rename from bd10520b.f65b2c3a.js rename to bd10520b.3d6eeb84.js index 46c01bebb6..5c934d9980 100644 --- a/bd10520b.f65b2c3a.js +++ b/bd10520b.3d6eeb84.js @@ -1,2 +1,2 @@ -/*! For license information please see bd10520b.f65b2c3a.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[194],{345:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return f}));var r=n(1),a=n(9),o=(n(0),n(422)),c=n(421),i=(n(429),n(426)),l={last_modified_on:"2023-04-19",title:"Project",description:"Learn how to configure your Projects on Qovery"},u={id:"using-qovery/configuration/project",title:"Project",description:"Learn how to configure your Projects on Qovery",source:"@site/docs/using-qovery/configuration/project.md",permalink:"/docs/using-qovery/configuration/project",sidebar:"docs",previous:{title:"Cluster Advanced Settings",permalink:"/docs/using-qovery/configuration/cluster-advanced-settings"},next:{title:"Environment",permalink:"/docs/using-qovery/configuration/environment"}},s=[{value:"Create a new project",id:"create-a-new-project",children:[]},{value:"Edit project general information",id:"edit-project-general-information",children:[]},{value:"Delete a project",id:"delete-a-project",children:[]}],p={rightToc:s};function f(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"A project allows you to group together a set of environments with the objective to run the same application (see the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment")," page for more information)."),Object(o.b)("p",null,"When creating a new organization, a project is created by default. You can customize the access to your project thanks to our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/members-rbac/#roles-based-access-control-rbac"}),"RBAC system"),"."),Object(o.b)(i.a,{name:"documentation",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have created an ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization")))),Object(o.b)("h2",{id:"create-a-new-project"},"Create a new project"),Object(o.b)("p",null,"If you need to create an additional project, go into the organization settings and press on the ",Object(o.b)("inlineCode",{parentName:"p"},"NEW")," button."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/project/project_creation.png",alt:"Project Creation"})),Object(o.b)("p",null,"The modal will ask you to provide a name and a description."),Object(o.b)("h2",{id:"edit-project-general-information"},"Edit project general information"),Object(o.b)("p",null,"General information of a project can be updated by:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"opening the settings page"),Object(o.b)("li",{parentName:"ul"},"selecting the project"),Object(o.b)("li",{parentName:"ul"},"opening the ",Object(o.b)("inlineCode",{parentName:"li"},"GENERAL")," section. ")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/project/project_update.png",alt:"Project Update"})),Object(o.b)("h2",{id:"delete-a-project"},"Delete a project"),Object(o.b)(c.a,{type:"danger",mdxType:"Alert"},Object(o.b)("p",null,"This is a non-recoverable operation. By deleting your project, all your running applications and data within the project are deleted.")),Object(o.b)("p",null,"You can delete a project by:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"opening the settings page"),Object(o.b)("li",{parentName:"ul"},"selecting the project"),Object(o.b)("li",{parentName:"ul"},"opening the ",Object(o.b)("inlineCode",{parentName:"li"},"DANGER")," section and pressing the ",Object(o.b)("inlineCode",{parentName:"li"},"Delete Project")," button. ")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/project/project_delete.png",alt:"Project Delete"})))}f.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),b=r,m=p["".concat(c,".").concat(b)]||p[b]||f[b]||o;return n?a.a.createElement(m,i({ref:t},u,{components:n})):a.a.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,c=new Array(o);c[0]=b;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var u=2;u1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>i;)t[i++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),c=n(39),i=n(430),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,p=Object(i.a)(s),f=Object(a.useRef)(!1),b=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!b&&p&&window.docusaurus.prefetch(s),function(){b&&t&&t.disconnect()}}),[s,b,p]),s&&p?o.a.createElement(c.b,Object(r.a)({},e,{onMouseEnter:function(){f.current||(window.docusaurus.preload(s),f.current=!0)},innerRef:function(e){var n,r;b&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:s})):o.a.createElement("a",Object(r.a)({},e,{href:s}))}},429:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(427),c=n(420),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,c=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,p=e.to,f=i()("jump-to","jump-to--"+u,n),b=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},c&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+c})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?a.a.createElement("a",{href:p,target:s,className:f},b):a.a.createElement(o.a,{to:p,className:f},b)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file +/*! For license information please see bd10520b.3d6eeb84.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[197],{348:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return f}));var r=n(1),a=n(9),o=(n(0),n(425)),c=n(424),i=(n(431),n(429)),l={last_modified_on:"2023-04-19",title:"Project",description:"Learn how to configure your Projects on Qovery"},u={id:"using-qovery/configuration/project",title:"Project",description:"Learn how to configure your Projects on Qovery",source:"@site/docs/using-qovery/configuration/project.md",permalink:"/docs/using-qovery/configuration/project",sidebar:"docs",previous:{title:"Cluster Advanced Settings",permalink:"/docs/using-qovery/configuration/cluster-advanced-settings"},next:{title:"Environment",permalink:"/docs/using-qovery/configuration/environment"}},s=[{value:"Create a new project",id:"create-a-new-project",children:[]},{value:"Edit project general information",id:"edit-project-general-information",children:[]},{value:"Delete a project",id:"delete-a-project",children:[]}],p={rightToc:s};function f(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"A project allows you to group together a set of environments with the objective to run the same application (see the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment")," page for more information)."),Object(o.b)("p",null,"When creating a new organization, a project is created by default. You can customize the access to your project thanks to our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/members-rbac/#roles-based-access-control-rbac"}),"RBAC system"),"."),Object(o.b)(i.a,{name:"documentation",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have created an ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization")))),Object(o.b)("h2",{id:"create-a-new-project"},"Create a new project"),Object(o.b)("p",null,"If you need to create an additional project, go into the organization settings and press on the ",Object(o.b)("inlineCode",{parentName:"p"},"NEW")," button."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/project/project_creation.png",alt:"Project Creation"})),Object(o.b)("p",null,"The modal will ask you to provide a name and a description."),Object(o.b)("h2",{id:"edit-project-general-information"},"Edit project general information"),Object(o.b)("p",null,"General information of a project can be updated by:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"opening the settings page"),Object(o.b)("li",{parentName:"ul"},"selecting the project"),Object(o.b)("li",{parentName:"ul"},"opening the ",Object(o.b)("inlineCode",{parentName:"li"},"GENERAL")," section. ")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/project/project_update.png",alt:"Project Update"})),Object(o.b)("h2",{id:"delete-a-project"},"Delete a project"),Object(o.b)(c.a,{type:"danger",mdxType:"Alert"},Object(o.b)("p",null,"This is a non-recoverable operation. By deleting your project, all your running applications and data within the project are deleted.")),Object(o.b)("p",null,"You can delete a project by:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"opening the settings page"),Object(o.b)("li",{parentName:"ul"},"selecting the project"),Object(o.b)("li",{parentName:"ul"},"opening the ",Object(o.b)("inlineCode",{parentName:"li"},"DANGER")," section and pressing the ",Object(o.b)("inlineCode",{parentName:"li"},"Delete Project")," button. ")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/project/project_delete.png",alt:"Project Delete"})))}f.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),b=r,m=p["".concat(c,".").concat(b)]||p[b]||f[b]||o;return n?a.a.createElement(m,i({ref:t},u,{components:n})):a.a.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,c=new Array(o);c[0]=b;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var u=2;u1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>i;)t[i++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),c=n(39),i=n(432),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,p=Object(i.a)(s),f=Object(a.useRef)(!1),b=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!b&&p&&window.docusaurus.prefetch(s),function(){b&&t&&t.disconnect()}}),[s,b,p]),s&&p?o.a.createElement(c.b,Object(r.a)({},e,{onMouseEnter:function(){f.current||(window.docusaurus.preload(s),f.current=!0)},innerRef:function(e){var n,r;b&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:s})):o.a.createElement("a",Object(r.a)({},e,{href:s}))}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(430),c=n(423),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,c=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,p=e.to,f=i()("jump-to","jump-to--"+u,n),b=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},c&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+c})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?a.a.createElement("a",{href:p,target:s,className:f},b):a.a.createElement(o.a,{to:p,className:f},b)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/c0594016.772afbdc.js.LICENSE.txt b/bd10520b.3d6eeb84.js.LICENSE.txt similarity index 100% rename from c0594016.772afbdc.js.LICENSE.txt rename to bd10520b.3d6eeb84.js.LICENSE.txt diff --git a/e4768112.e546d594.js b/bdd6d8c6.5950578c.js similarity index 77% rename from e4768112.e546d594.js rename to bdd6d8c6.5950578c.js index cc526e6d97..f35eff5973 100644 --- a/e4768112.e546d594.js +++ b/bdd6d8c6.5950578c.js @@ -1,2 +1,2 @@ -/*! For license information please see e4768112.e546d594.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[241],{393:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),o=(n(0),n(422)),c=n(431),i=(n(421),n(426)),s=(n(429),{last_modified_on:"2022-01-27",$schema:"/.meta/.schemas/guides.json",title:"How to create an RDS instance through the AWS console",description:"How to create an RDS instance through the AWS console.",author_github:"https://github.com/l0ck3",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to create an RDS instance through the AWS console",description:"How to create an RDS instance through the AWS console.",permalink:"/guides/tutorial/how-to-create-an-rds-instance-through-aws-console",readingTime:"4 min read",source:"@site/guides/tutorial/how-to-create-an-rds-instance-through-aws-console.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to create an RDS instance through the AWS console",truncated:!1,prevItem:{title:"How to connect to your EKS cluster with kubectl",permalink:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl"},nextItem:{title:"How to deploy a Rust REST API application on AWS with ease",permalink:"/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease"}},u=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],b={rightToc:u};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery make it easy to create an RDS database on AWS with a few clicks. You might however want to create your own RDS instance in a separate VPC. For example in case you want to use the same instance with several Qovery clusters."),Object(o.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have an AWS account."))),Object(o.b)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"This tutorial will show you how to create an production-ready RDS PostgreSQL instance on AWS. "),Object(o.b)("p",null,"To connect your Qovery cluster(s) to the created RDS database, refer to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"this tutorial")),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"create-rds-database"},"Create RDS database"),Object(o.b)("p",null,"Go to the AWS RDS console and click ",Object(o.b)("inlineCode",{parentName:"p"},"Create database")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/1.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"select-your-database-type"},"Select your database type"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"We will need to create a dedicated VPC, so select ",Object(o.b)("inlineCode",{parentName:"li"},"Standard create"),"."),Object(o.b)("li",{parentName:"ul"},"Then chose your database type (we'll use PostgreSQL for our example) and the version."),Object(o.b)("li",{parentName:"ul"},"Since we're creating a production database, we'll select the ",Object(o.b)("inlineCode",{parentName:"li"},"Production")," template. You can pick ",Object(o.b)("inlineCode",{parentName:"li"},"Dev/Test")," template for non-production environments.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/2.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"settings"},"Settings"),Object(o.b)("p",null,"Select a name for your RDS instance, here ",Object(o.b)("inlineCode",{parentName:"p"},"my-production-database"),", master username and password."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/3.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"instance-class"},"Instance class"),Object(o.b)("p",null,"Pick an instance class that works for your needs.\nYou can refer to this document for more information about the different options: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html"}),"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/4.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"storage"},"Storage"),Object(o.b)("p",null,Object(o.b)("inlineCode",{parentName:"p"},"General Purpose SSD")," should be the right option for most cases.\nChose the allocated storage that fits the needs of your application. We also advise you to ",Object(o.b)("inlineCode",{parentName:"p"},"Enable storage autoscaling")," in case you need more storage over time. "),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/5.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"availability--durability"},"Availability & durability"),Object(o.b)("p",null,"For a production setup you should ",Object(o.b)("inlineCode",{parentName:"p"},"Create a standby instance"),". For non-production usecase you can avoid it to reduce costs."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/6.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"connectivity"},"Connectivity"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Since we want the database to live in it's own VPC, make sure to select the ",Object(o.b)("inlineCode",{parentName:"li"},"Create new VPC")," option."),Object(o.b)("li",{parentName:"ul"},"Also select ",Object(o.b)("inlineCode",{parentName:"li"},"Create new DB Subnet Group"),"."),Object(o.b)("li",{parentName:"ul"},"We advise you to disable ",Object(o.b)("inlineCode",{parentName:"li"},"Public access")," for security reason. We'll setup VPC peering in the next guide to allow access from your Qovery clusters through private networking."),Object(o.b)("li",{parentName:"ul"},"Finally chose ",Object(o.b)("inlineCode",{parentName:"li"},"Create new")," security group and give it a name.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/7.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"database-authentication-and-estimated-costs"},"Database authentication and estimated costs"),Object(o.b)("p",null,"Chose ",Object(o.b)("inlineCode",{parentName:"p"},"Password authentication"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/8.png",alt:"AWS RDS console"})),Object(o.b)("p",null,"You can then click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create database"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"database-creation"},"Database creation"),Object(o.b)("p",null,"You should see your new RDS instance in the list of databases, with the ",Object(o.b)("inlineCode",{parentName:"p"},"Creating")," status."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/9.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"name-your-rds-vpc"},"Name your RDS VPC"),Object(o.b)("p",null,"The VPC created for the new RDS database will be named ",Object(o.b)("inlineCode",{parentName:"p"},"-"),". For convenience you should rename it."),Object(o.b)("p",null,"Click on your database in the list, then on the VPC id. "),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/10.png",alt:"AWS RDS console"})),Object(o.b)("p",null,"You will be redirected to the VPCs list, filtered on the VPC id. Click on the edit icon in the ",Object(o.b)("inlineCode",{parentName:"p"},"Name")," column, and give it a meaningful name."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/11.png",alt:"AWS RDS console"})),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/12.png",alt:"AWS RDS console"}))))),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"Your RDS database is ready. Now in order to access it from your Qovery cluster, we will need to setup VPC peering. You can find the procedure in ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"this tutorial")))}p.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),u=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=u(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),b=u(n),d=a,m=b["".concat(c,".").concat(d)]||b[d]||p[d]||o;return n?r.a.createElement(m,i({ref:t},l,{components:n})):r.a.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,c=new Array(o);c[0]=d;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:a,c[1]=i;for(var l=2;l1?arguments[1]:void 0,n),s=c>2?arguments[2]:void 0,l=void 0===s?n:r(s,n);l>i;)t[i++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),c=n(39),i=n(430),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,b=Object(i.a)(u),p=Object(r.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,b]),u&&b?o.a.createElement(c.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,a;d&&e&&b&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},428:function(e,t,n){"use strict";var a=n(432),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var c=[];return r.slice().forEach((function(e){void 0!==e&&c.push(n(a,e,c.length))})),c.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),c=n(420),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,c=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,b=e.to,p=i()("jump-to","jump-to--"+l,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:b,target:u,className:p},d):r.a.createElement(o.a,{to:b,className:p},d)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(420),n(428)),c=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(s),u=Object(a.useState)(null),b=u[0],p=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see bdd6d8c6.5950578c.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[198],{349:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),o=(n(0),n(425)),c=n(434),i=(n(424),n(429)),s=(n(431),{last_modified_on:"2022-01-27",$schema:"/.meta/.schemas/guides.json",title:"How to create an RDS instance through the AWS console",description:"How to create an RDS instance through the AWS console.",author_github:"https://github.com/l0ck3",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to create an RDS instance through the AWS console",description:"How to create an RDS instance through the AWS console.",permalink:"/guides/tutorial/how-to-create-an-rds-instance-through-aws-console",readingTime:"4 min read",source:"@site/guides/tutorial/how-to-create-an-rds-instance-through-aws-console.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to create an RDS instance through the AWS console",truncated:!1,prevItem:{title:"How to connect to your EKS cluster with kubectl",permalink:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl"},nextItem:{title:"How to deploy a Rust REST API application on AWS with ease",permalink:"/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease"}},u=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],b={rightToc:u};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery make it easy to create an RDS database on AWS with a few clicks. You might however want to create your own RDS instance in a separate VPC. For example in case you want to use the same instance with several Qovery clusters."),Object(o.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have an AWS account."))),Object(o.b)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"This tutorial will show you how to create an production-ready RDS PostgreSQL instance on AWS. "),Object(o.b)("p",null,"To connect your Qovery cluster(s) to the created RDS database, refer to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"this tutorial")),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"create-rds-database"},"Create RDS database"),Object(o.b)("p",null,"Go to the AWS RDS console and click ",Object(o.b)("inlineCode",{parentName:"p"},"Create database")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/1.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"select-your-database-type"},"Select your database type"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"We will need to create a dedicated VPC, so select ",Object(o.b)("inlineCode",{parentName:"li"},"Standard create"),"."),Object(o.b)("li",{parentName:"ul"},"Then chose your database type (we'll use PostgreSQL for our example) and the version."),Object(o.b)("li",{parentName:"ul"},"Since we're creating a production database, we'll select the ",Object(o.b)("inlineCode",{parentName:"li"},"Production")," template. You can pick ",Object(o.b)("inlineCode",{parentName:"li"},"Dev/Test")," template for non-production environments.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/2.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"settings"},"Settings"),Object(o.b)("p",null,"Select a name for your RDS instance, here ",Object(o.b)("inlineCode",{parentName:"p"},"my-production-database"),", master username and password."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/3.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"instance-class"},"Instance class"),Object(o.b)("p",null,"Pick an instance class that works for your needs.\nYou can refer to this document for more information about the different options: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html"}),"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/4.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"storage"},"Storage"),Object(o.b)("p",null,Object(o.b)("inlineCode",{parentName:"p"},"General Purpose SSD")," should be the right option for most cases.\nChose the allocated storage that fits the needs of your application. We also advise you to ",Object(o.b)("inlineCode",{parentName:"p"},"Enable storage autoscaling")," in case you need more storage over time. "),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/5.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"availability--durability"},"Availability & durability"),Object(o.b)("p",null,"For a production setup you should ",Object(o.b)("inlineCode",{parentName:"p"},"Create a standby instance"),". For non-production usecase you can avoid it to reduce costs."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/6.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"connectivity"},"Connectivity"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Since we want the database to live in it's own VPC, make sure to select the ",Object(o.b)("inlineCode",{parentName:"li"},"Create new VPC")," option."),Object(o.b)("li",{parentName:"ul"},"Also select ",Object(o.b)("inlineCode",{parentName:"li"},"Create new DB Subnet Group"),"."),Object(o.b)("li",{parentName:"ul"},"We advise you to disable ",Object(o.b)("inlineCode",{parentName:"li"},"Public access")," for security reason. We'll setup VPC peering in the next guide to allow access from your Qovery clusters through private networking."),Object(o.b)("li",{parentName:"ul"},"Finally chose ",Object(o.b)("inlineCode",{parentName:"li"},"Create new")," security group and give it a name.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/7.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"database-authentication-and-estimated-costs"},"Database authentication and estimated costs"),Object(o.b)("p",null,"Chose ",Object(o.b)("inlineCode",{parentName:"p"},"Password authentication"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/8.png",alt:"AWS RDS console"})),Object(o.b)("p",null,"You can then click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create database"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"database-creation"},"Database creation"),Object(o.b)("p",null,"You should see your new RDS instance in the list of databases, with the ",Object(o.b)("inlineCode",{parentName:"p"},"Creating")," status."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/9.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"name-your-rds-vpc"},"Name your RDS VPC"),Object(o.b)("p",null,"The VPC created for the new RDS database will be named ",Object(o.b)("inlineCode",{parentName:"p"},"-"),". For convenience you should rename it."),Object(o.b)("p",null,"Click on your database in the list, then on the VPC id. "),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/10.png",alt:"AWS RDS console"})),Object(o.b)("p",null,"You will be redirected to the VPCs list, filtered on the VPC id. Click on the edit icon in the ",Object(o.b)("inlineCode",{parentName:"p"},"Name")," column, and give it a meaningful name."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/11.png",alt:"AWS RDS console"})),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/12.png",alt:"AWS RDS console"}))))),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"Your RDS database is ready. Now in order to access it from your Qovery cluster, we will need to setup VPC peering. You can find the procedure in ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"this tutorial")))}p.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),u=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=u(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),b=u(n),d=a,m=b["".concat(c,".").concat(d)]||b[d]||p[d]||o;return n?r.a.createElement(m,i({ref:t},l,{components:n})):r.a.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,c=new Array(o);c[0]=d;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:a,c[1]=i;for(var l=2;l1?arguments[1]:void 0,n),s=c>2?arguments[2]:void 0,l=void 0===s?n:r(s,n);l>i;)t[i++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),c=n(39),i=n(432),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,b=Object(i.a)(u),p=Object(r.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,b]),u&&b?o.a.createElement(c.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,a;d&&e&&b&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),c=n(423),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,c=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,b=e.to,p=i()("jump-to","jump-to--"+l,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:b,target:u,className:p},d):r.a.createElement(o.a,{to:b,className:p},d)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},433:function(e,t,n){"use strict";var a=n(435),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var c=[];return r.slice().forEach((function(e){void 0!==e&&c.push(n(a,e,c.length))})),c.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(423),n(433)),c=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(s),u=Object(a.useState)(null),b=u[0],p=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/c0ab55e0.0f325bb8.js.LICENSE.txt b/bdd6d8c6.5950578c.js.LICENSE.txt similarity index 100% rename from c0ab55e0.0f325bb8.js.LICENSE.txt rename to bdd6d8c6.5950578c.js.LICENSE.txt diff --git a/bf22200e.f1fb9bc5.js b/bf22200e.da52379d.js similarity index 72% rename from bf22200e.f1fb9bc5.js rename to bf22200e.da52379d.js index 4d0ab7405f..b97764698c 100644 --- a/bf22200e.f1fb9bc5.js +++ b/bf22200e.da52379d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[196],{347:function(t){t.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"type-tutorial","name":"type: tutorial","count":40,"permalink":"/guides/tags/type-tutorial"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[199],{350:function(t){t.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"type-tutorial","name":"type: tutorial","count":40,"permalink":"/guides/tags/type-tutorial"}')}}]); \ No newline at end of file diff --git a/e4310ee0.27f4cee2.js b/c0594016.1f6b92f8.js similarity index 90% rename from e4310ee0.27f4cee2.js rename to c0594016.1f6b92f8.js index feeca6c7eb..6dd02016d8 100644 --- a/e4310ee0.27f4cee2.js +++ b/c0594016.1f6b92f8.js @@ -1,2 +1,2 @@ -/*! For license information please see e4310ee0.27f4cee2.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[240],{392:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),a=(n(0),n(422)),i=n(431),c=n(426),u=(n(421),{last_modified_on:"2023-07-07",$schema:"/.meta/.schemas/guides.json",title:"Custom domain",description:"How to set and use your own domain",series_position:3,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),l={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Custom domain",description:"How to set and use your own domain",permalink:"/guides/getting-started/setting-custom-domain",readingTime:"2 min read",seriesPosition:3,source:"@site/guides/getting-started/setting-custom-domain.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Custom domain",truncated:!1,prevItem:{title:"Create a database",permalink:"/guides/getting-started/create-a-database"},nextItem:{title:"Environment variables",permalink:"/guides/getting-started/managing-environment-variables"}},s=[{value:"Tutorial",id:"tutorial",children:[{value:"Add the domain to your app",id:"add-the-domain-to-your-app",children:[]},{value:"Configure your DNS",id:"configure-your-dns",children:[]},{value:"Your domain is ready",id:"your-domain-is-ready",children:[]}]}],d={rightToc:s};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"On Qovery, every application exposed publicly automatically gets a temporary ",Object(a.b)("inlineCode",{parentName:"p"},"qovery.io")," domain. You can also bring your domains to Qovery\nquickly. We handle TLS/SSL certificate creation and renewal, as well as automatic HTTP to HTTPS redirects for all your custom domains. Let\u2019s\nlearn how to set up your domains on Qovery!"),Object(a.b)(c.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have a domain"),Object(a.b)("li",{parentName:"ul"},"You have the permission to add a ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://en.wikipedia.org/wiki/CNAME_record"}),"CNAME")," record to your domain"))),Object(a.b)("h2",{id:"tutorial"},"Tutorial"),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h3",{id:"add-the-domain-to-your-app"},"Add the domain to your app"),Object(a.b)("div",{class:"video-container"},Object(a.b)("p",{align:"center"},Object(a.b)("iframe",{src:"https://www.loom.com/embed/cd9c56a133164005bfeb7db23d2b6ed1",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0})))),Object(a.b)("li",null,Object(a.b)("h3",{id:"configure-your-dns"},"Configure your DNS"),Object(a.b)("p",null,"Configure your DNS by adding a CNAME record pointing to the domain provided by Qovery in the previous step"),Object(a.b)("p",null,"If you have multiple public ports (or you want to have them in the future), make sure you add a CNAME for both yourdomain.com and *.yourdomain.com. "),Object(a.b)("p",null,"In this way:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"your application default port will be accessible via the domain ",Object(a.b)("inlineCode",{parentName:"li"},"yourdomain.com")," or by a subdomain equal to the port name (portNameA.yourdomain.com). "),Object(a.b)("li",{parentName:"ul"},"the other application public port will be accessible via a subdomain equal to the portName (portNameB.yourdomain.com). ")),Object(a.b)("p",null,"See the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#ports"}),"port setup of your application")," for more information on the port name setup.")),Object(a.b)("li",null,Object(a.b)("h3",{id:"your-domain-is-ready"},"Your domain is ready"),Object(a.b)("p",null,"You need to ",Object(a.b)("strong",{parentName:"p"},"restart")," your app to use your custom domain on your application.")))),Object(a.b)("p",null,"If you run into any trouble, ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discord.qovery.com"}),"find us on Discord"),". Our team and the community will be glad to help out."))}p.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=o.a.createContext({}),s=function(e){var t=o.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},d=function(e){var t=s(e.components);return o.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),d=s(n),m=r,b=d["".concat(i,".").concat(m)]||d[m]||p[m]||a;return n?o.a.createElement(b,c({ref:t},l,{components:n})):o.a.createElement(b,c({ref:t},l))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,l=void 0===u?n:o(u,n);l>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),s=Object(r.useState)(null),d=s[0],p=s[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!d&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==d&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see c0594016.1f6b92f8.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[200],{351:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),a=(n(0),n(425)),i=n(434),c=n(429),u=(n(424),{last_modified_on:"2023-07-07",$schema:"/.meta/.schemas/guides.json",title:"Custom domain",description:"How to set and use your own domain",series_position:3,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),l={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Custom domain",description:"How to set and use your own domain",permalink:"/guides/getting-started/setting-custom-domain",readingTime:"2 min read",seriesPosition:3,source:"@site/guides/getting-started/setting-custom-domain.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Custom domain",truncated:!1,prevItem:{title:"Create a database",permalink:"/guides/getting-started/create-a-database"},nextItem:{title:"Environment variables",permalink:"/guides/getting-started/managing-environment-variables"}},s=[{value:"Tutorial",id:"tutorial",children:[{value:"Add the domain to your app",id:"add-the-domain-to-your-app",children:[]},{value:"Configure your DNS",id:"configure-your-dns",children:[]},{value:"Your domain is ready",id:"your-domain-is-ready",children:[]}]}],d={rightToc:s};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"On Qovery, every application exposed publicly automatically gets a temporary ",Object(a.b)("inlineCode",{parentName:"p"},"qovery.io")," domain. You can also bring your domains to Qovery\nquickly. We handle TLS/SSL certificate creation and renewal, as well as automatic HTTP to HTTPS redirects for all your custom domains. Let\u2019s\nlearn how to set up your domains on Qovery!"),Object(a.b)(c.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have a domain"),Object(a.b)("li",{parentName:"ul"},"You have the permission to add a ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://en.wikipedia.org/wiki/CNAME_record"}),"CNAME")," record to your domain"))),Object(a.b)("h2",{id:"tutorial"},"Tutorial"),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h3",{id:"add-the-domain-to-your-app"},"Add the domain to your app"),Object(a.b)("div",{class:"video-container"},Object(a.b)("p",{align:"center"},Object(a.b)("iframe",{src:"https://www.loom.com/embed/cd9c56a133164005bfeb7db23d2b6ed1",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0})))),Object(a.b)("li",null,Object(a.b)("h3",{id:"configure-your-dns"},"Configure your DNS"),Object(a.b)("p",null,"Configure your DNS by adding a CNAME record pointing to the domain provided by Qovery in the previous step"),Object(a.b)("p",null,"If you have multiple public ports (or you want to have them in the future), make sure you add a CNAME for both yourdomain.com and *.yourdomain.com. "),Object(a.b)("p",null,"In this way:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"your application default port will be accessible via the domain ",Object(a.b)("inlineCode",{parentName:"li"},"yourdomain.com")," or by a subdomain equal to the port name (portNameA.yourdomain.com). "),Object(a.b)("li",{parentName:"ul"},"the other application public port will be accessible via a subdomain equal to the portName (portNameB.yourdomain.com). ")),Object(a.b)("p",null,"See the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#ports"}),"port setup of your application")," for more information on the port name setup.")),Object(a.b)("li",null,Object(a.b)("h3",{id:"your-domain-is-ready"},"Your domain is ready"),Object(a.b)("p",null,"You need to ",Object(a.b)("strong",{parentName:"p"},"restart")," your app to use your custom domain on your application.")))),Object(a.b)("p",null,"If you run into any trouble, ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discord.qovery.com"}),"find us on Discord"),". Our team and the community will be glad to help out."))}p.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=o.a.createContext({}),s=function(e){var t=o.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},d=function(e){var t=s(e.components);return o.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),d=s(n),m=r,b=d["".concat(i,".").concat(m)]||d[m]||p[m]||a;return n?o.a.createElement(b,c({ref:t},l,{components:n})):o.a.createElement(b,c({ref:t},l))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,l=void 0===u?n:o(u,n);l>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),s=Object(r.useState)(null),d=s[0],p=s[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!d&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==d&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/c24a85bb.3cd0e530.js.LICENSE.txt b/c0594016.1f6b92f8.js.LICENSE.txt similarity index 100% rename from c24a85bb.3cd0e530.js.LICENSE.txt rename to c0594016.1f6b92f8.js.LICENSE.txt diff --git a/5b5f8b70.2d5c46c3.js b/c0ab55e0.7b52badc.js similarity index 95% rename from 5b5f8b70.2d5c46c3.js rename to c0ab55e0.7b52badc.js index 2fec0f513a..6dbebc8535 100644 --- a/5b5f8b70.2d5c46c3.js +++ b/c0ab55e0.7b52badc.js @@ -1,2 +1,2 @@ -/*! For license information please see 5b5f8b70.2d5c46c3.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[106],{257:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return u}));var a=n(1),i=n(9),r=(n(0),n(422)),o=(n(429),n(421)),c=(n(426),{last_modified_on:"2023-04-22",$schema:"/.meta/.schemas/guides.json",title:"Use AWS IAM roles with Qovery",description:"Give AWS IAM permissions to your application/container/job with Qovery",author_github:"https://github.com/deimosfr",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Use AWS IAM roles with Qovery",description:"Give AWS IAM permissions to your application/container/job with Qovery",permalink:"/guides/tutorial/use-aws-iam-roles-with-qovery",readingTime:"8 min read",source:"@site/guides/tutorial/use-aws-iam-roles-with-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Use AWS IAM roles with Qovery",truncated:!1,prevItem:{title:"Use an API gateway in front of multiple services",permalink:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services"},nextItem:{title:"Using Amazon SQS and Lambda on Qovery",permalink:"/guides/tutorial/aws-sqs-lambda-with-qovery"}},s=[{value:"Application requiring S3 permissions",id:"application-requiring-s3-permissions",children:[{value:"Create an application",id:"create-an-application",children:[]},{value:"Get Kubernetes namespace name",id:"get-kubernetes-namespace-name",children:[]}]},{value:"Configure OIDC provider",id:"configure-oidc-provider",children:[{value:"Get your Cluster OIDC provider URL",id:"get-your-cluster-oidc-provider-url",children:[]},{value:"Create an Identity provider",id:"create-an-identity-provider",children:[]}]},{value:"Configure AWS IAM roles",id:"configure-aws-iam-roles",children:[{value:"Create a role",id:"create-a-role",children:[]},{value:"Role permissions",id:"role-permissions",children:[]},{value:"Configure trusted entities",id:"configure-trusted-entities",children:[]}]},{value:"Create a service account",id:"create-a-service-account",children:[{value:"Kubernetes authentication",id:"kubernetes-authentication",children:[]},{value:"Create a Lifecycle job",id:"create-a-lifecycle-job",children:[]}]},{value:"Set application service account",id:"set-application-service-account",children:[{value:"Set service account",id:"set-service-account",children:[]},{value:"Validate access",id:"validate-access",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],b={rightToc:s};function u(e){var t=e.components,n=Object(i.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"AWS IAM (Identity & Access Management) service allows AWS services to interact with each other by using roles. Those roles can easily be used to give permissions to your Qovery application, container or job."),Object(r.b)("p",null,"It is a secure way to give your application permissions without having to manage credentials. More than that, it rotates the token automatically."),Object(r.b)("p",null,"This tutorial will show you how to add AWS IAM roles to your Qovery application, container or job."),Object(r.b)("h2",{id:"application-requiring-s3-permissions"},"Application requiring S3 permissions"),Object(r.b)("p",null,"In this first step, we will create a simple application that needs AWS permissions to access s3 buckets."),Object(r.b)("h3",{id:"create-an-application"},"Create an application"),Object(r.b)("p",null,"We are going to will create a simple container, but you can use an existing one if you want (or an application or job). "),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You do not have to deploy it now, just create one container this way.")),Object(r.b)("p",null,"Here is a simple Debian container example:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/debian_app.png",alt:"debian app"})),Object(r.b)("p",null,"Set only 1 instance and 128MB of memory is enough for this example. Then continue until you have the ",Object(r.b)("inlineCode",{parentName:"p"},"Create")," button, there is nothing more to setup."),Object(r.b)("h3",{id:"get-kubernetes-namespace-name"},"Get Kubernetes namespace name"),Object(r.b)("p",null,"Then in this container (or any application in this environment) ",Object(r.b)("inlineCode",{parentName:"p"},"Variables"),", search for the variable called ",Object(r.b)("inlineCode",{parentName:"p"},"QOVERY_KUBERNETES_NAMESPACE_NAME")," and copy its value somewhere."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/debian_namespace.png",alt:"debian app"})),Object(r.b)("p",null,"It is the Kubernetes namespace name where the container is located."),Object(r.b)("h2",{id:"configure-oidc-provider"},"Configure OIDC provider"),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"This step should be done only once per cluster")),Object(r.b)("h3",{id:"get-your-cluster-oidc-provider-url"},"Get your Cluster OIDC provider URL"),Object(r.b)("p",null,"On your AWS console, go to your EKS cluster and ",Object(r.b)("inlineCode",{parentName:"p"},"Overview")," section. Copy the ",Object(r.b)("inlineCode",{parentName:"p"},"OpenID Connect provider URL"),":"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/eks_oidc.png",alt:"EKS OIDC"})),Object(r.b)("h3",{id:"create-an-identity-provider"},"Create an Identity provider"),Object(r.b)("p",null,"On your AWS console, go to ",Object(r.b)("inlineCode",{parentName:"p"},"IAM")," service, then ",Object(r.b)("inlineCode",{parentName:"p"},"Identity providers")," section, and ",Object(r.b)("inlineCode",{parentName:"p"},"Add provider")," button:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Select the ",Object(r.b)("inlineCode",{parentName:"li"},"OpenID Connect")," provider type"),Object(r.b)("li",{parentName:"ol"},"Paste the ",Object(r.b)("inlineCode",{parentName:"li"},"OpenID Connect provider URL")," previously copied to ",Object(r.b)("inlineCode",{parentName:"li"},"Provider URL")),Object(r.b)("li",{parentName:"ol"},"Click on ",Object(r.b)("inlineCode",{parentName:"li"},"Get thumbprint")," button, once done the button will change to ",Object(r.b)("inlineCode",{parentName:"li"},"Edit URL")),Object(r.b)("li",{parentName:"ol"},"Add ",Object(r.b)("inlineCode",{parentName:"li"},"sts.amazonaws.com")," as ",Object(r.b)("inlineCode",{parentName:"li"},"Audience")),Object(r.b)("li",{parentName:"ol"},"Click on ",Object(r.b)("inlineCode",{parentName:"li"},"Add provider")," button")),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/oidc_connect.png",alt:"OIDC Connect"})),Object(r.b)("h2",{id:"configure-aws-iam-roles"},"Configure AWS IAM roles"),Object(r.b)("h3",{id:"create-a-role"},"Create a role"),Object(r.b)("p",null,"Now we can create a role. In the ",Object(r.b)("inlineCode",{parentName:"p"},"IAM")," service, go to ",Object(r.b)("inlineCode",{parentName:"p"},"Roles")," section, and click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create role")," button."),Object(r.b)("p",null,"You have to select the Trusted entity type. For this tutorial, we are going to use the ",Object(r.b)("inlineCode",{parentName:"p"},"Web identity")," type."),Object(r.b)("p",null,"Set the ",Object(r.b)("inlineCode",{parentName:"p"},"Identity provider")," to the one you just created, and the ",Object(r.b)("inlineCode",{parentName:"p"},"Audience")," to ",Object(r.b)("inlineCode",{parentName:"p"},"sts.amazonaws.com"),". Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Next")," button."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/role_create_step1.png",alt:"Role create step 1"})),Object(r.b)("h3",{id:"role-permissions"},"Role permissions"),Object(r.b)("p",null,"Select the policy of your choice. For this example, the policy ",Object(r.b)("inlineCode",{parentName:"p"},"AmazonS3ReadOnlyAccess")," will be used to list S3 buckets. Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Next")," button."),Object(r.b)("p",null,"To finish, set the role name and description of your choice and click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create role")," button."),Object(r.b)("h3",{id:"configure-trusted-entities"},"Configure trusted entities"),Object(r.b)("h4",{id:"qovery-environment-scoped-role"},"Qovery environment scoped role"),Object(r.b)("p",null,"Once created, select your freshly created role, go to the ",Object(r.b)("inlineCode",{parentName:"p"},"Trust relationships")," tab, and click on ",Object(r.b)("inlineCode",{parentName:"p"},"Edit trust policy")," button."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/role_trusted_entities_default.png",alt:"role trusted default"})),Object(r.b)("p",null,"Update the policy line regarding the ",Object(r.b)("inlineCode",{parentName:"p"},"OIDC")," condition from:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{}),'"oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:aud": "sts.amazonaws.com"\n')),Object(r.b)("p",null,"to:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{}),'"oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:sub": "system:serviceaccount:kubernetes_namespace:service_account_name"\n')),Object(r.b)("p",null,"Replace:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"kubernetes_namespace"),": with the namespace name, corresponding to the Qovery environment (",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"#get-kubernetes-namespace-name"}),"previously copied in step 1"),")"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"service_account_name"),": define a service account name which will be re-use later (ex: ",Object(r.b)("inlineCode",{parentName:"li"},"my-s3-role"),")")),Object(r.b)("p",null,"Once done, click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Update policy")," button."),Object(r.b)("p",null,"Last element to copy and save somewhere: is the role ",Object(r.b)("inlineCode",{parentName:"p"},"ARN"),"."),Object(r.b)("p",null,"In the end, you should have something like:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Effect": "Allow",\n "Principal": {\n "Federated": "arn:aws:iam::yyyyyyy:oidc-provider/oidc.eks.us-east-2.amazonaws.com/id/xxxxxxx"\n },\n "Action": "sts:AssumeRoleWithWebIdentity",\n "Condition": {\n "StringEquals": {\n "oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:sub": "system:serviceaccount:kubernetes_namespace:service_account_name"\n }\n }\n }\n ]\n}\n')),Object(r.b)("h4",{id:"cluster-scoped-role"},"Cluster scoped role"),Object(r.b)("p",null,'If you want to be able to keep the Role and permissions with the "On-demand environment" and "Clone" features, then you have to scope the role "cluster side" instead of the "Kubernetes namespace" side.'),Object(r.b)("p",null,"To do so, update the ",Object(r.b)("inlineCode",{parentName:"p"},"Condition")," with ",Object(r.b)("inlineCode",{parentName:"p"},"StringLike")," instead of ",Object(r.b)("inlineCode",{parentName:"p"},"StringEquals"),", and use a wildcard instead of the namespace name:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'"Condition": {\n "StringLike": {\n "oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:sub": "system:serviceaccount:z*:service_account_name"\n }\n}\n')),Object(r.b)("p",null,"Replace:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"service_account_name"),": define a service account name which will be re-use later (ex: ",Object(r.b)("inlineCode",{parentName:"li"},"my-s3-role"),")"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"z*"),": the wildcard to use to match all namespaces deployed with Qovery")),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Do not forget to set the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"#create-a-service-account"}),"Service Account")," as well in those environments.")),Object(r.b)("h2",{id:"create-a-service-account"},"Create a service account"),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"If you already have an existing service account on your Kubernetes cluster and want to use it, you can skip this step.")),Object(r.b)(o.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Kubernetes reminder: ",Object(r.b)("strong",{parentName:"p"},"a deployed service account in a Kubernetes namespace, becomes available by all applications in the same namespace."))),Object(r.b)("p",null,"This step will help you on deploying a service account on your Kubernetes cluster. In case you want to do it manually on the cluster with ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl"),", you just have to push a service account like:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"apiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: $SERVICE_ACCOUNT_NAME\n namespace: $QOVERY_KUBERNETES_NAMESPACE_NAME\n annotations:\n eks.amazonaws.com/role-arn: $AWS_ROLE_ARN\n")),Object(r.b)("h3",{id:"kubernetes-authentication"},"Kubernetes authentication"),Object(r.b)("p",null,"On AWS, there are ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/eks/latest/userguide/cluster-auth.html"}),"several ways to authenticate to Kubernetes"),". To make it simple, we are going to use a dedicated IAM user, but you can select the best method for your need."),Object(r.b)("p",null,"From your AWS Console, create an IAM user account, get ",Object(r.b)("inlineCode",{parentName:"p"},"Access key ID")," and ",Object(r.b)("inlineCode",{parentName:"p"},"Secret access key")," and save them somewhere."),Object(r.b)("p",null,"Qovery helps ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/#add-your-iam-user-to-the-admin-group"}),"IAM users to get quick access to the Kubernetes cluster"),". Simply add this user to the ",Object(r.b)("inlineCode",{parentName:"p"},"Admins")," group."),Object(r.b)("h3",{id:"create-a-lifecycle-job"},"Create a Lifecycle job"),Object(r.b)("p",null,"In the same environment than your application, create a ",Object(r.b)("inlineCode",{parentName:"p"},"Lifecycle job")," which will be used to deploy a service account on the Kubernetes cluster:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step1.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Here a container ",Object(r.b)("inlineCode",{parentName:"p"},"qoveryrd/create-sa:1.0")," available on ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://hub.docker.com/r/qoveryrd/create-sa"}),"DockerHub")," made by Qovery is used, but you can fork ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/create_service_account"}),"this repository")," and update to your needs if you prefer."),Object(r.b)("p",null,"Click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button and select the ",Object(r.b)("inlineCode",{parentName:"p"},"Start")," event because we want to deploy the service account at the environment start and ",Object(r.b)("inlineCode",{parentName:"p"},"Delete")," to delete it if we decide to remove it. Set parameters as well with the according action:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step2.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button, set the resources (128Mb is enough) and click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",null,"Then add the following environment variables to the ",Object(r.b)("inlineCode",{parentName:"p"},"job")," scope:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"KUBERNETES_VERSION"),": the version of your Kubernetes cluster which will be used to download kubectl (ex: 1.23.0)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"SERVICE_ACCOUNT_NAME"),": the name of the service account in Kubernetes (the same name ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"#configure-trusted-entities"}),"you have declared")," for the role in the ",Object(r.b)("inlineCode",{parentName:"li"},"Trusted entities")," policy section)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"AWS_ROLE_ARN"),": the AWS ARN role you have just created"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"AWS_ACCESS_KEY_ID"),": the AWS access key ID of the IAM user you have created (if you decided to use this authentication method)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"AWS_SECRET_ACCESS_KEY"),": the AWS secret access key of the IAM user you have created (if you decided to use this authentication method)")),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step2.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Then ",Object(r.b)("inlineCode",{parentName:"p"},"Create")," the ",Object(r.b)("inlineCode",{parentName:"p"},"Lifecycle job"),". Go into the ",Object(r.b)("inlineCode",{parentName:"p"},"Variables")," tab and create a ",Object(r.b)("inlineCode",{parentName:"p"},"Variable Alias")," on ",Object(r.b)("inlineCode",{parentName:"p"},"QOVERY_CLOUD_PROVIDER_REGION"),", name it ",Object(r.b)("inlineCode",{parentName:"p"},"AWS_DEFAULT_REGION")," and scope it to the ",Object(r.b)("inlineCode",{parentName:"p"},"job"),"."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step3.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"You can now run your job by clicking on the ",Object(r.b)("inlineCode",{parentName:"p"},"Deploy now")," button. You should see the following output in your job logs:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{}),"-> Ensuring required environment variables are present\n-> Downloading kubectl version 1.23.0\n-> Generated service account:\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: my-s3-role\n namespace: xxxxxx\n annotations:\n eks.amazonaws.com/role-arn: arn:aws:iam::xxxxxx:role/my-s3-role\n-> Getting kubeconfig\nAdded new context arn:aws:eks:region:id:cluster/cluster-name to /root/.kube/config\n-> Deploying service account\nserviceaccount/aws-permissions created\n")),Object(r.b)("h2",{id:"set-application-service-account"},"Set application service account"),Object(r.b)("h3",{id:"set-service-account"},"Set service account"),Object(r.b)("p",null,"The final step is to set this service account (pointing to the AWS role) to your application. Go into your application ",Object(r.b)("inlineCode",{parentName:"p"},"Advanced settings")," and set the ",Object(r.b)("inlineCode",{parentName:"p"},"Service account")," to the one you have just created:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/debian_sa.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Deploy your application with the ",Object(r.b)("inlineCode",{parentName:"p"},"Deploy now")," button."),Object(r.b)("p",null,"At this stage, the job should have been executed and the service account should be deployed on your Kubernetes cluster, and the Debian container, running."),Object(r.b)("h3",{id:"validate-access"},"Validate access"),Object(r.b)("p",null,"To validate the AWS role has correctly been deployed, we can connect to the pod, and see if we have the AWS token. We will use the Qovery CLI to connect to our pod:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell\nQovery: Select organization\nOrganization:\n\u2714 Qovery\nQovery: Select project\nProject:\n\u2714 AWS roles tutorial\nQovery: Select environment\nEnvironment:\n\u2714 aws-role\nQovery: Select service\nServices:\n\u2714 debian\n")),Object(r.b)("p",null,"Now we are connected to the pod, we can check the AWS token:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ env | grep AWS\nAWS_DEFAULT_REGION=us-east-2\nAWS_REGION=us-east-2\nAWS_ROLE_ARN=arn:aws:iam::xxxxxx:role/my-s3-role\nAWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token\nAWS_STS_REGIONAL_ENDPOINTS=regional\n")),Object(r.b)("p",null,"Token is here! Let's install the AWS CLI and validate the role access. We should be able to list S3 buckets:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ apt-get update && apt-get -y install awscli\n$ aws s3 ls\n2022-09-23 06:56:38 aws-cloudtrail-logs-qovery\n...\n")),Object(r.b)("p",null,"It works! We have access to S3 buckets using the AWS role."),Object(r.b)("h2",{id:"conclusion"},"Conclusion"),Object(r.b)("p",null,"The first setup phase can be time-consuming. However, once done, applying roles to your applications is very easy and fast. You can now use roles to access any AWS service!"))}u.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function i(){for(var e=[],t=0;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=i.a.createContext({}),b=function(e){var t=i.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=b(e.components);return i.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=b(n),d=a,m=u["".concat(o,".").concat(d)]||u[d]||p[d]||r;return n?i.a.createElement(m,c({ref:t},s,{components:n})):i.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,o[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=o>2?arguments[2]:void 0,s=void 0===l?n:i(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var a=n(28).f,i=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in i||n(10)&&a(i,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),i=n.n(a),r=n(421);t.a=function(e){var t=e.children,n=e.name;return i.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},i.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),i=n(0),r=n.n(i),o=n(39),c=n(430),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,u=Object(c.a)(b),p=Object(i.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?r.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var n,a;d&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:b})):r.a.createElement("a",Object(a.a)({},e,{href:b}))}},429:function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=n(427),o=n(420),c=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,o=e.leftIcon,l=e.rightIcon,s=e.size,b=e.target,u=e.to,p=c()("jump-to","jump-to--"+s,n),d=i.a.createElement("div",{className:"jump-to--inner"},i.a.createElement("div",{className:"jump-to--inner-2"},o&&i.a.createElement("div",{className:"jump-to--left"},i.a.createElement("i",{className:"feather icon-"+o})),i.a.createElement("div",{className:"jump-to--main"},a?i.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),i.a.createElement("div",{className:"jump-to--right"},i.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return b?i.a.createElement("a",{href:u,target:b,className:p},d):i.a.createElement(r.a,{to:u,className:p},d)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see c0ab55e0.7b52badc.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[201],{352:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return u}));var a=n(1),i=n(9),r=(n(0),n(425)),o=(n(431),n(424)),c=(n(429),{last_modified_on:"2023-04-22",$schema:"/.meta/.schemas/guides.json",title:"Use AWS IAM roles with Qovery",description:"Give AWS IAM permissions to your application/container/job with Qovery",author_github:"https://github.com/deimosfr",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Use AWS IAM roles with Qovery",description:"Give AWS IAM permissions to your application/container/job with Qovery",permalink:"/guides/tutorial/use-aws-iam-roles-with-qovery",readingTime:"8 min read",source:"@site/guides/tutorial/use-aws-iam-roles-with-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Use AWS IAM roles with Qovery",truncated:!1,prevItem:{title:"Use an API gateway in front of multiple services",permalink:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services"},nextItem:{title:"Using Amazon SQS and Lambda on Qovery",permalink:"/guides/tutorial/aws-sqs-lambda-with-qovery"}},s=[{value:"Application requiring S3 permissions",id:"application-requiring-s3-permissions",children:[{value:"Create an application",id:"create-an-application",children:[]},{value:"Get Kubernetes namespace name",id:"get-kubernetes-namespace-name",children:[]}]},{value:"Configure OIDC provider",id:"configure-oidc-provider",children:[{value:"Get your Cluster OIDC provider URL",id:"get-your-cluster-oidc-provider-url",children:[]},{value:"Create an Identity provider",id:"create-an-identity-provider",children:[]}]},{value:"Configure AWS IAM roles",id:"configure-aws-iam-roles",children:[{value:"Create a role",id:"create-a-role",children:[]},{value:"Role permissions",id:"role-permissions",children:[]},{value:"Configure trusted entities",id:"configure-trusted-entities",children:[]}]},{value:"Create a service account",id:"create-a-service-account",children:[{value:"Kubernetes authentication",id:"kubernetes-authentication",children:[]},{value:"Create a Lifecycle job",id:"create-a-lifecycle-job",children:[]}]},{value:"Set application service account",id:"set-application-service-account",children:[{value:"Set service account",id:"set-service-account",children:[]},{value:"Validate access",id:"validate-access",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],b={rightToc:s};function u(e){var t=e.components,n=Object(i.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"AWS IAM (Identity & Access Management) service allows AWS services to interact with each other by using roles. Those roles can easily be used to give permissions to your Qovery application, container or job."),Object(r.b)("p",null,"It is a secure way to give your application permissions without having to manage credentials. More than that, it rotates the token automatically."),Object(r.b)("p",null,"This tutorial will show you how to add AWS IAM roles to your Qovery application, container or job."),Object(r.b)("h2",{id:"application-requiring-s3-permissions"},"Application requiring S3 permissions"),Object(r.b)("p",null,"In this first step, we will create a simple application that needs AWS permissions to access s3 buckets."),Object(r.b)("h3",{id:"create-an-application"},"Create an application"),Object(r.b)("p",null,"We are going to will create a simple container, but you can use an existing one if you want (or an application or job). "),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You do not have to deploy it now, just create one container this way.")),Object(r.b)("p",null,"Here is a simple Debian container example:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/debian_app.png",alt:"debian app"})),Object(r.b)("p",null,"Set only 1 instance and 128MB of memory is enough for this example. Then continue until you have the ",Object(r.b)("inlineCode",{parentName:"p"},"Create")," button, there is nothing more to setup."),Object(r.b)("h3",{id:"get-kubernetes-namespace-name"},"Get Kubernetes namespace name"),Object(r.b)("p",null,"Then in this container (or any application in this environment) ",Object(r.b)("inlineCode",{parentName:"p"},"Variables"),", search for the variable called ",Object(r.b)("inlineCode",{parentName:"p"},"QOVERY_KUBERNETES_NAMESPACE_NAME")," and copy its value somewhere."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/debian_namespace.png",alt:"debian app"})),Object(r.b)("p",null,"It is the Kubernetes namespace name where the container is located."),Object(r.b)("h2",{id:"configure-oidc-provider"},"Configure OIDC provider"),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"This step should be done only once per cluster")),Object(r.b)("h3",{id:"get-your-cluster-oidc-provider-url"},"Get your Cluster OIDC provider URL"),Object(r.b)("p",null,"On your AWS console, go to your EKS cluster and ",Object(r.b)("inlineCode",{parentName:"p"},"Overview")," section. Copy the ",Object(r.b)("inlineCode",{parentName:"p"},"OpenID Connect provider URL"),":"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/eks_oidc.png",alt:"EKS OIDC"})),Object(r.b)("h3",{id:"create-an-identity-provider"},"Create an Identity provider"),Object(r.b)("p",null,"On your AWS console, go to ",Object(r.b)("inlineCode",{parentName:"p"},"IAM")," service, then ",Object(r.b)("inlineCode",{parentName:"p"},"Identity providers")," section, and ",Object(r.b)("inlineCode",{parentName:"p"},"Add provider")," button:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Select the ",Object(r.b)("inlineCode",{parentName:"li"},"OpenID Connect")," provider type"),Object(r.b)("li",{parentName:"ol"},"Paste the ",Object(r.b)("inlineCode",{parentName:"li"},"OpenID Connect provider URL")," previously copied to ",Object(r.b)("inlineCode",{parentName:"li"},"Provider URL")),Object(r.b)("li",{parentName:"ol"},"Click on ",Object(r.b)("inlineCode",{parentName:"li"},"Get thumbprint")," button, once done the button will change to ",Object(r.b)("inlineCode",{parentName:"li"},"Edit URL")),Object(r.b)("li",{parentName:"ol"},"Add ",Object(r.b)("inlineCode",{parentName:"li"},"sts.amazonaws.com")," as ",Object(r.b)("inlineCode",{parentName:"li"},"Audience")),Object(r.b)("li",{parentName:"ol"},"Click on ",Object(r.b)("inlineCode",{parentName:"li"},"Add provider")," button")),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/oidc_connect.png",alt:"OIDC Connect"})),Object(r.b)("h2",{id:"configure-aws-iam-roles"},"Configure AWS IAM roles"),Object(r.b)("h3",{id:"create-a-role"},"Create a role"),Object(r.b)("p",null,"Now we can create a role. In the ",Object(r.b)("inlineCode",{parentName:"p"},"IAM")," service, go to ",Object(r.b)("inlineCode",{parentName:"p"},"Roles")," section, and click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create role")," button."),Object(r.b)("p",null,"You have to select the Trusted entity type. For this tutorial, we are going to use the ",Object(r.b)("inlineCode",{parentName:"p"},"Web identity")," type."),Object(r.b)("p",null,"Set the ",Object(r.b)("inlineCode",{parentName:"p"},"Identity provider")," to the one you just created, and the ",Object(r.b)("inlineCode",{parentName:"p"},"Audience")," to ",Object(r.b)("inlineCode",{parentName:"p"},"sts.amazonaws.com"),". Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Next")," button."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/role_create_step1.png",alt:"Role create step 1"})),Object(r.b)("h3",{id:"role-permissions"},"Role permissions"),Object(r.b)("p",null,"Select the policy of your choice. For this example, the policy ",Object(r.b)("inlineCode",{parentName:"p"},"AmazonS3ReadOnlyAccess")," will be used to list S3 buckets. Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Next")," button."),Object(r.b)("p",null,"To finish, set the role name and description of your choice and click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create role")," button."),Object(r.b)("h3",{id:"configure-trusted-entities"},"Configure trusted entities"),Object(r.b)("h4",{id:"qovery-environment-scoped-role"},"Qovery environment scoped role"),Object(r.b)("p",null,"Once created, select your freshly created role, go to the ",Object(r.b)("inlineCode",{parentName:"p"},"Trust relationships")," tab, and click on ",Object(r.b)("inlineCode",{parentName:"p"},"Edit trust policy")," button."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/role_trusted_entities_default.png",alt:"role trusted default"})),Object(r.b)("p",null,"Update the policy line regarding the ",Object(r.b)("inlineCode",{parentName:"p"},"OIDC")," condition from:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{}),'"oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:aud": "sts.amazonaws.com"\n')),Object(r.b)("p",null,"to:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{}),'"oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:sub": "system:serviceaccount:kubernetes_namespace:service_account_name"\n')),Object(r.b)("p",null,"Replace:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"kubernetes_namespace"),": with the namespace name, corresponding to the Qovery environment (",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"#get-kubernetes-namespace-name"}),"previously copied in step 1"),")"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"service_account_name"),": define a service account name which will be re-use later (ex: ",Object(r.b)("inlineCode",{parentName:"li"},"my-s3-role"),")")),Object(r.b)("p",null,"Once done, click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Update policy")," button."),Object(r.b)("p",null,"Last element to copy and save somewhere: is the role ",Object(r.b)("inlineCode",{parentName:"p"},"ARN"),"."),Object(r.b)("p",null,"In the end, you should have something like:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Effect": "Allow",\n "Principal": {\n "Federated": "arn:aws:iam::yyyyyyy:oidc-provider/oidc.eks.us-east-2.amazonaws.com/id/xxxxxxx"\n },\n "Action": "sts:AssumeRoleWithWebIdentity",\n "Condition": {\n "StringEquals": {\n "oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:sub": "system:serviceaccount:kubernetes_namespace:service_account_name"\n }\n }\n }\n ]\n}\n')),Object(r.b)("h4",{id:"cluster-scoped-role"},"Cluster scoped role"),Object(r.b)("p",null,'If you want to be able to keep the Role and permissions with the "On-demand environment" and "Clone" features, then you have to scope the role "cluster side" instead of the "Kubernetes namespace" side.'),Object(r.b)("p",null,"To do so, update the ",Object(r.b)("inlineCode",{parentName:"p"},"Condition")," with ",Object(r.b)("inlineCode",{parentName:"p"},"StringLike")," instead of ",Object(r.b)("inlineCode",{parentName:"p"},"StringEquals"),", and use a wildcard instead of the namespace name:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'"Condition": {\n "StringLike": {\n "oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:sub": "system:serviceaccount:z*:service_account_name"\n }\n}\n')),Object(r.b)("p",null,"Replace:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"service_account_name"),": define a service account name which will be re-use later (ex: ",Object(r.b)("inlineCode",{parentName:"li"},"my-s3-role"),")"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"z*"),": the wildcard to use to match all namespaces deployed with Qovery")),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Do not forget to set the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"#create-a-service-account"}),"Service Account")," as well in those environments.")),Object(r.b)("h2",{id:"create-a-service-account"},"Create a service account"),Object(r.b)(o.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"If you already have an existing service account on your Kubernetes cluster and want to use it, you can skip this step.")),Object(r.b)(o.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Kubernetes reminder: ",Object(r.b)("strong",{parentName:"p"},"a deployed service account in a Kubernetes namespace, becomes available by all applications in the same namespace."))),Object(r.b)("p",null,"This step will help you on deploying a service account on your Kubernetes cluster. In case you want to do it manually on the cluster with ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl"),", you just have to push a service account like:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"apiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: $SERVICE_ACCOUNT_NAME\n namespace: $QOVERY_KUBERNETES_NAMESPACE_NAME\n annotations:\n eks.amazonaws.com/role-arn: $AWS_ROLE_ARN\n")),Object(r.b)("h3",{id:"kubernetes-authentication"},"Kubernetes authentication"),Object(r.b)("p",null,"On AWS, there are ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/eks/latest/userguide/cluster-auth.html"}),"several ways to authenticate to Kubernetes"),". To make it simple, we are going to use a dedicated IAM user, but you can select the best method for your need."),Object(r.b)("p",null,"From your AWS Console, create an IAM user account, get ",Object(r.b)("inlineCode",{parentName:"p"},"Access key ID")," and ",Object(r.b)("inlineCode",{parentName:"p"},"Secret access key")," and save them somewhere."),Object(r.b)("p",null,"Qovery helps ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/#add-your-iam-user-to-the-admin-group"}),"IAM users to get quick access to the Kubernetes cluster"),". Simply add this user to the ",Object(r.b)("inlineCode",{parentName:"p"},"Admins")," group."),Object(r.b)("h3",{id:"create-a-lifecycle-job"},"Create a Lifecycle job"),Object(r.b)("p",null,"In the same environment than your application, create a ",Object(r.b)("inlineCode",{parentName:"p"},"Lifecycle job")," which will be used to deploy a service account on the Kubernetes cluster:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step1.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Here a container ",Object(r.b)("inlineCode",{parentName:"p"},"qoveryrd/create-sa:1.0")," available on ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://hub.docker.com/r/qoveryrd/create-sa"}),"DockerHub")," made by Qovery is used, but you can fork ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/create_service_account"}),"this repository")," and update to your needs if you prefer."),Object(r.b)("p",null,"Click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button and select the ",Object(r.b)("inlineCode",{parentName:"p"},"Start")," event because we want to deploy the service account at the environment start and ",Object(r.b)("inlineCode",{parentName:"p"},"Delete")," to delete it if we decide to remove it. Set parameters as well with the according action:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step2.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button, set the resources (128Mb is enough) and click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",null,"Then add the following environment variables to the ",Object(r.b)("inlineCode",{parentName:"p"},"job")," scope:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"KUBERNETES_VERSION"),": the version of your Kubernetes cluster which will be used to download kubectl (ex: 1.23.0)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"SERVICE_ACCOUNT_NAME"),": the name of the service account in Kubernetes (the same name ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"#configure-trusted-entities"}),"you have declared")," for the role in the ",Object(r.b)("inlineCode",{parentName:"li"},"Trusted entities")," policy section)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"AWS_ROLE_ARN"),": the AWS ARN role you have just created"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"AWS_ACCESS_KEY_ID"),": the AWS access key ID of the IAM user you have created (if you decided to use this authentication method)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"AWS_SECRET_ACCESS_KEY"),": the AWS secret access key of the IAM user you have created (if you decided to use this authentication method)")),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step2.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Then ",Object(r.b)("inlineCode",{parentName:"p"},"Create")," the ",Object(r.b)("inlineCode",{parentName:"p"},"Lifecycle job"),". Go into the ",Object(r.b)("inlineCode",{parentName:"p"},"Variables")," tab and create a ",Object(r.b)("inlineCode",{parentName:"p"},"Variable Alias")," on ",Object(r.b)("inlineCode",{parentName:"p"},"QOVERY_CLOUD_PROVIDER_REGION"),", name it ",Object(r.b)("inlineCode",{parentName:"p"},"AWS_DEFAULT_REGION")," and scope it to the ",Object(r.b)("inlineCode",{parentName:"p"},"job"),"."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/lifecycle_step3.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"You can now run your job by clicking on the ",Object(r.b)("inlineCode",{parentName:"p"},"Deploy now")," button. You should see the following output in your job logs:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{}),"-> Ensuring required environment variables are present\n-> Downloading kubectl version 1.23.0\n-> Generated service account:\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: my-s3-role\n namespace: xxxxxx\n annotations:\n eks.amazonaws.com/role-arn: arn:aws:iam::xxxxxx:role/my-s3-role\n-> Getting kubeconfig\nAdded new context arn:aws:eks:region:id:cluster/cluster-name to /root/.kube/config\n-> Deploying service account\nserviceaccount/aws-permissions created\n")),Object(r.b)("h2",{id:"set-application-service-account"},"Set application service account"),Object(r.b)("h3",{id:"set-service-account"},"Set service account"),Object(r.b)("p",null,"The final step is to set this service account (pointing to the AWS role) to your application. Go into your application ",Object(r.b)("inlineCode",{parentName:"p"},"Advanced settings")," and set the ",Object(r.b)("inlineCode",{parentName:"p"},"Service account")," to the one you have just created:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/debian_sa.png",alt:"Lifecycle creation"})),Object(r.b)("p",null,"Deploy your application with the ",Object(r.b)("inlineCode",{parentName:"p"},"Deploy now")," button."),Object(r.b)("p",null,"At this stage, the job should have been executed and the service account should be deployed on your Kubernetes cluster, and the Debian container, running."),Object(r.b)("h3",{id:"validate-access"},"Validate access"),Object(r.b)("p",null,"To validate the AWS role has correctly been deployed, we can connect to the pod, and see if we have the AWS token. We will use the Qovery CLI to connect to our pod:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell\nQovery: Select organization\nOrganization:\n\u2714 Qovery\nQovery: Select project\nProject:\n\u2714 AWS roles tutorial\nQovery: Select environment\nEnvironment:\n\u2714 aws-role\nQovery: Select service\nServices:\n\u2714 debian\n")),Object(r.b)("p",null,"Now we are connected to the pod, we can check the AWS token:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ env | grep AWS\nAWS_DEFAULT_REGION=us-east-2\nAWS_REGION=us-east-2\nAWS_ROLE_ARN=arn:aws:iam::xxxxxx:role/my-s3-role\nAWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token\nAWS_STS_REGIONAL_ENDPOINTS=regional\n")),Object(r.b)("p",null,"Token is here! Let's install the AWS CLI and validate the role access. We should be able to list S3 buckets:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ apt-get update && apt-get -y install awscli\n$ aws s3 ls\n2022-09-23 06:56:38 aws-cloudtrail-logs-qovery\n...\n")),Object(r.b)("p",null,"It works! We have access to S3 buckets using the AWS role."),Object(r.b)("h2",{id:"conclusion"},"Conclusion"),Object(r.b)("p",null,"The first setup phase can be time-consuming. However, once done, applying roles to your applications is very easy and fast. You can now use roles to access any AWS service!"))}u.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function i(){for(var e=[],t=0;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=i.a.createContext({}),b=function(e){var t=i.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=b(e.components);return i.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=b(n),d=a,m=u["".concat(o,".").concat(d)]||u[d]||p[d]||r;return n?i.a.createElement(m,c({ref:t},s,{components:n})):i.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,o[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=o>2?arguments[2]:void 0,s=void 0===l?n:i(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var a=n(28).f,i=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in i||n(10)&&a(i,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),i=n.n(a),r=n(424);t.a=function(e){var t=e.children,n=e.name;return i.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},i.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),i=n(0),r=n.n(i),o=n(39),c=n(432),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,u=Object(c.a)(b),p=Object(i.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?r.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var n,a;d&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:b})):r.a.createElement("a",Object(a.a)({},e,{href:b}))}},431:function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=n(430),o=n(423),c=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,o=e.leftIcon,l=e.rightIcon,s=e.size,b=e.target,u=e.to,p=c()("jump-to","jump-to--"+s,n),d=i.a.createElement("div",{className:"jump-to--inner"},i.a.createElement("div",{className:"jump-to--inner-2"},o&&i.a.createElement("div",{className:"jump-to--left"},i.a.createElement("i",{className:"feather icon-"+o})),i.a.createElement("div",{className:"jump-to--main"},a?i.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),i.a.createElement("div",{className:"jump-to--right"},i.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return b?i.a.createElement("a",{href:u,target:b,className:p},d):i.a.createElement(r.a,{to:u,className:p},d)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/c3f02c14.1ac9f45c.js.LICENSE.txt b/c0ab55e0.7b52badc.js.LICENSE.txt similarity index 100% rename from c3f02c14.1ac9f45c.js.LICENSE.txt rename to c0ab55e0.7b52badc.js.LICENSE.txt diff --git a/c24a85bb.3cd0e530.js b/c24a85bb.97905c5d.js similarity index 90% rename from c24a85bb.3cd0e530.js rename to c24a85bb.97905c5d.js index b6c9a0cdb3..27b4be4205 100644 --- a/c24a85bb.3cd0e530.js +++ b/c24a85bb.97905c5d.js @@ -1,2 +1,2 @@ -/*! For license information please see c24a85bb.3cd0e530.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[199],{350:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return l})),r.d(t,"rightToc",(function(){return u})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),o=(r(0),r(422)),c=(r(431),r(426),r(421)),i={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Helm Charts",description:"Learn how to deploy Helm charts with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: helm"]},l={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Helm Charts",description:"Learn how to deploy Helm charts with Qovery",permalink:"/guides/advanced/helm-chart",readingTime:"1 min read",source:"@site/guides/advanced/helm-chart.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: helm",permalink:"/guides/tags/technology-helm"}],title:"Helm Charts",truncated:!1,prevItem:{title:"Grafana setup with Qovery",permalink:"/guides/tutorial/grafana-install"},nextItem:{title:"How to activate SSO to connect to your EKS cluster",permalink:"/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster"}},u=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:u};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery runs on top of Kubernetes and allows you to deploy any Helm chart on your cluster. To learn more about Helm, please visit the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://helm.sh"}),"official website"),"."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to deploy your Helm Charts with Qovery."),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Helm Charts is an advanced way to deploy your applications on Qovery. If you are new to Qovery, we recommend you to start with the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"Getting Started guide"),".")),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Official"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-deploy-helm-charts/"}),"Deploy your Helm Charts")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-deploy-helm-charts/"}),"How to deploy your Helm Charts (example with Kubecost)")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Yes")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=helm%20charts"}),"Forum")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=helm%20charts"}),'List "Helm Charts" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},420:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,b=p["".concat(c,".").concat(d)]||p[d]||m[d]||o;return r?a.a.createElement(b,i({ref:t},u,{components:r})):a.a.createElement(b,i({ref:t},u))}));function b(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,c=new Array(o);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var u=2;u1?arguments[1]:void 0,r),l=c>2?arguments[2]:void 0,u=void 0===l?r:a(l,r);u>i;)t[i++]=e;return t}},425:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,r){"use strict";r(425);var n=r(0),a=r.n(n),o=r(421);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},428:function(e,t,r){"use strict";var n=r(432),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var c=[];return a.slice().forEach((function(e){void 0!==e&&c.push(r(n,e,c.length))})),c.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(420),r(428)),c=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(n.useState)(null),p=s[0],m=s[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return m("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see c24a85bb.97905c5d.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[202],{353:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return l})),r.d(t,"rightToc",(function(){return u})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),o=(r(0),r(425)),c=(r(434),r(429),r(424)),i={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Helm Charts",description:"Learn how to deploy Helm charts with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: helm"]},l={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Helm Charts",description:"Learn how to deploy Helm charts with Qovery",permalink:"/guides/advanced/helm-chart",readingTime:"1 min read",source:"@site/guides/advanced/helm-chart.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: helm",permalink:"/guides/tags/technology-helm"}],title:"Helm Charts",truncated:!1,prevItem:{title:"Grafana setup with Qovery",permalink:"/guides/tutorial/grafana-install"},nextItem:{title:"How to activate SSO to connect to your EKS cluster",permalink:"/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster"}},u=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],s={rightToc:u};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery runs on top of Kubernetes and allows you to deploy any Helm chart on your cluster. To learn more about Helm, please visit the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://helm.sh"}),"official website"),"."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to deploy your Helm Charts with Qovery."),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Helm Charts is an advanced way to deploy your applications on Qovery. If you are new to Qovery, we recommend you to start with the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"Getting Started guide"),".")),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Official"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-deploy-helm-charts/"}),"Deploy your Helm Charts")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/how-to-deploy-helm-charts/"}),"How to deploy your Helm Charts (example with Kubecost)")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Yes")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=helm%20charts"}),"Forum")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=helm%20charts"}),'List "Helm Charts" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"no")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,b=p["".concat(c,".").concat(d)]||p[d]||m[d]||o;return r?a.a.createElement(b,i({ref:t},u,{components:r})):a.a.createElement(b,i({ref:t},u))}));function b(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,c=new Array(o);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var u=2;u1?arguments[1]:void 0,r),l=c>2?arguments[2]:void 0,u=void 0===l?r:a(l,r);u>i;)t[i++]=e;return t}},428:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,r){"use strict";r(428);var n=r(0),a=r.n(n),o=r(424);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},433:function(e,t,r){"use strict";var n=r(435),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var c=[];return a.slice().forEach((function(e){void 0!==e&&c.push(r(n,e,c.length))})),c.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(423),r(433)),c=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(n.useState)(null),p=s[0],m=s[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return m("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/c4f5d8e4.2c02b003.js.LICENSE.txt b/c24a85bb.97905c5d.js.LICENSE.txt similarity index 100% rename from c4f5d8e4.2c02b003.js.LICENSE.txt rename to c24a85bb.97905c5d.js.LICENSE.txt diff --git a/c3f02c14.1ac9f45c.js b/c3f02c14.09ad982a.js similarity index 92% rename from c3f02c14.1ac9f45c.js rename to c3f02c14.09ad982a.js index ebca5442e2..6674542352 100644 --- a/c3f02c14.1ac9f45c.js +++ b/c3f02c14.09ad982a.js @@ -1,2 +1,2 @@ -/*! For license information please see c3f02c14.1ac9f45c.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[200],{351:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return l})),r.d(t,"rightToc",(function(){return b})),r.d(t,"default",(function(){return u}));var n=r(1),a=r(9),o=(r(0),r(422)),c=r(421),i={last_modified_on:"2023-05-20",title:"REST API",description:"How to use REST API to manage Qovery resources"},l={id:"using-qovery/interface/rest-api",title:"REST API",description:"How to use REST API to manage Qovery resources",source:"@site/docs/using-qovery/interface/rest-api.md",permalink:"/docs/using-qovery/interface/rest-api",sidebar:"docs",previous:{title:"CLI",permalink:"/docs/using-qovery/interface/cli"},next:{title:"Terraform",permalink:"/docs/using-qovery/interface/terraform-interface"}},b=[{value:"API clients",id:"api-clients",children:[{value:"Generate an API token",id:"generate-an-api-token",children:[]}]},{value:"API Documentation",id:"api-documentation",children:[]}],p={rightToc:b};function u(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},p,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Use the Qovery REST API to programmatically create infrastructure and deploy your applications. The only limit is your imagination. Find the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://api-doc.qovery.com"}),"Qovery API documentation")," and the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"blob:https://api-doc.qovery.com/1d5bb570-c5ce-7e4a-adfb-eb149616e5e9"}),"OpenAPI spec")," to generate your own Qovery client with your favorite programming language."),Object(o.b)("h2",{id:"api-clients"},"API clients"),Object(o.b)("p",null,"Here is the list of clients available to use the Qovery Web API."),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Language"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Link"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Golang"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://github.com/Qovery/qovery-client-go"}),"source"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Python"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://github.com/Qovery/qovery-client-python"}),"source"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Typescript"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://github.com/Qovery/qovery-client-typescript-axios"}),"source"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Javascript"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://github.com/Qovery/qovery-client-javascript"}),"source"))))),Object(o.b)(c.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"You can generate a Qovery client for any language. ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/generate-qovery-api-client/"}),"Read this post"))),Object(o.b)("h3",{id:"generate-an-api-token"},"Generate an API token"),Object(o.b)("p",null,"You can generate an API token from the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#generate-api-token"}),"Qovery CLI")," or via the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/api-token/"}),"Qovery Web Console"),"."),Object(o.b)("h2",{id:"api-documentation"},"API Documentation"),Object(o.b)("p",null,"The API documentation is available ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://api-doc.qovery.com"}),"here")))}u.isMDXComponent=!0},420:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var b=a.a.createContext({}),p=function(e){var t=a.a.useContext(b),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},u=function(e){var t=p(e.components);return a.a.createElement(b.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},f=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,b=l(e,["components","mdxType","originalType","parentName"]),u=p(r),f=n,m=u["".concat(c,".").concat(f)]||u[f]||s[f]||o;return r?a.a.createElement(m,i({ref:t},b,{components:r})):a.a.createElement(m,i({ref:t},b))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,c=new Array(o);c[0]=f;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var b=2;b1?arguments[1]:void 0,r),l=c>2?arguments[2]:void 0,b=void 0===l?r:a(l,r);b>i;)t[i++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see c3f02c14.09ad982a.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[203],{354:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return l})),r.d(t,"rightToc",(function(){return b})),r.d(t,"default",(function(){return u}));var n=r(1),a=r(9),o=(r(0),r(425)),c=r(424),i={last_modified_on:"2023-05-20",title:"REST API",description:"How to use REST API to manage Qovery resources"},l={id:"using-qovery/interface/rest-api",title:"REST API",description:"How to use REST API to manage Qovery resources",source:"@site/docs/using-qovery/interface/rest-api.md",permalink:"/docs/using-qovery/interface/rest-api",sidebar:"docs",previous:{title:"CLI",permalink:"/docs/using-qovery/interface/cli"},next:{title:"Terraform",permalink:"/docs/using-qovery/interface/terraform-interface"}},b=[{value:"API clients",id:"api-clients",children:[{value:"Generate an API token",id:"generate-an-api-token",children:[]}]},{value:"API Documentation",id:"api-documentation",children:[]}],p={rightToc:b};function u(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},p,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Use the Qovery REST API to programmatically create infrastructure and deploy your applications. The only limit is your imagination. Find the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://api-doc.qovery.com"}),"Qovery API documentation")," and the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"blob:https://api-doc.qovery.com/1d5bb570-c5ce-7e4a-adfb-eb149616e5e9"}),"OpenAPI spec")," to generate your own Qovery client with your favorite programming language."),Object(o.b)("h2",{id:"api-clients"},"API clients"),Object(o.b)("p",null,"Here is the list of clients available to use the Qovery Web API."),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Language"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Link"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Golang"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://github.com/Qovery/qovery-client-go"}),"source"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Python"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://github.com/Qovery/qovery-client-python"}),"source"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Typescript"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://github.com/Qovery/qovery-client-typescript-axios"}),"source"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Javascript"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://github.com/Qovery/qovery-client-javascript"}),"source"))))),Object(o.b)(c.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"You can generate a Qovery client for any language. ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/generate-qovery-api-client/"}),"Read this post"))),Object(o.b)("h3",{id:"generate-an-api-token"},"Generate an API token"),Object(o.b)("p",null,"You can generate an API token from the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#generate-api-token"}),"Qovery CLI")," or via the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/api-token/"}),"Qovery Web Console"),"."),Object(o.b)("h2",{id:"api-documentation"},"API Documentation"),Object(o.b)("p",null,"The API documentation is available ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://api-doc.qovery.com"}),"here")))}u.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var b=a.a.createContext({}),p=function(e){var t=a.a.useContext(b),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},u=function(e){var t=p(e.components);return a.a.createElement(b.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},f=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,b=l(e,["components","mdxType","originalType","parentName"]),u=p(r),f=n,m=u["".concat(c,".").concat(f)]||u[f]||s[f]||o;return r?a.a.createElement(m,i({ref:t},b,{components:r})):a.a.createElement(m,i({ref:t},b))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,c=new Array(o);c[0]=f;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var b=2;b1?arguments[1]:void 0,r),l=c>2?arguments[2]:void 0,b=void 0===l?r:a(l,r);b>i;)t[i++]=e;return t}}}]); \ No newline at end of file diff --git a/c7bfb1d3.89f9ed6b.js.LICENSE.txt b/c3f02c14.09ad982a.js.LICENSE.txt similarity index 100% rename from c7bfb1d3.89f9ed6b.js.LICENSE.txt rename to c3f02c14.09ad982a.js.LICENSE.txt diff --git a/c4f5d8e4.2c02b003.js b/c4f5d8e4.7311bd1c.js similarity index 93% rename from c4f5d8e4.2c02b003.js rename to c4f5d8e4.7311bd1c.js index 6100bf71c7..e9c2e4485e 100644 --- a/c4f5d8e4.2c02b003.js +++ b/c4f5d8e4.7311bd1c.js @@ -1,2 +1,2 @@ -/*! For license information please see c4f5d8e4.2c02b003.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[201],{352:function(e,t,a){"use strict";a.r(t);var n=a(0),r=a.n(n),l=a(447),c=a(442),o=a(559);Object(l.a)("h2");t.default=function(){return r.a.createElement(c.a,{title:"Qovery Hub | Documentation, Guides, Tutorials",description:"Qovery is an Internal Developer Platform Helping Platform Engineers and Developers To Ship Faster."},r.a.createElement("header",{className:"hero"},r.a.createElement("div",{className:"container container--fluid"},r.a.createElement("h1",null,"Qovery Hub Resources"),r.a.createElement(o.a,{buttonClass:"highlight",description:"Qovery is an Internal Developer Platform Helping Platform Engineers and Developers To Ship Faster.",center:!0,size:"lg"}))),r.a.createElement("main",null,r.a.createElement("section",null,r.a.createElement("div",{className:"container"},r.a.createElement("div",{className:"row"},r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"docs",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-book"})),r.a.createElement("div",{className:"panel--title"},"Documentation"),r.a.createElement("div",{className:"panel--description"},"Read our product documentation"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"guides",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-layers"})),r.a.createElement("div",{className:"panel--title"},"Guides"),r.a.createElement("div",{className:"panel--description"},"Get started using Qovery smoothly"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"guides/tutorial",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-bookmark"})),r.a.createElement("div",{className:"panel--title"},"Tutorials"),r.a.createElement("div",{className:"panel--description"},"Check out our community tutorials"))))),r.a.createElement("div",{className:"container",style:{marginTop:"10px"}},r.a.createElement("div",{className:"row"},r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-message-circle"})),r.a.createElement("div",{className:"panel--title"},"Discord"),r.a.createElement("div",{className:"panel--description"},"Join our community on Discord"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://roadmap.qovery.com",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-flag"})),r.a.createElement("div",{className:"panel--title"},"Roadmap"),r.a.createElement("div",{className:"panel--description"},"Check out our public Roadmap"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://discuss.qovery.com",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-message-circle"})),r.a.createElement("div",{className:"panel--title"},"Forum"),r.a.createElement("div",{className:"panel--description"},"Join our community on Discourse"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://github.com/Qovery",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-github"})),r.a.createElement("div",{className:"panel--title"},"Github"),r.a.createElement("div",{className:"panel--description"},"Issues, code, and development"))))))))}},420:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t0&&r.a.createElement("div",{className:"row footer__links"},r.a.createElement("div",{className:"col col--5 footer__col"},r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement(u.a,{className:"navbar__logo",src:f,alt:"Qovery",width:"150",height:"auto"})),r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),r.a.createElement("div",null,r.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},r.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},r.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},r.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},r.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),i.map((function(e,t){return r.a.createElement("div",{key:t,className:"col footer__col"},null!=e.title?r.a.createElement("h4",{className:"footer__title"},e.title):null,null!=e.items&&Array.isArray(e.items)&&e.items.length>0?r.a.createElement("ul",{className:"footer__items"},e.items.map((function(e,t){return e.html?r.a.createElement("li",{key:t,className:"footer__item",dangerouslySetInnerHTML:{__html:e.html}}):r.a.createElement("li",{key:e.href||e.to,className:"footer__item"},r.a.createElement(z,e))}))):null)}))),(m||c)&&r.a.createElement("div",{className:"text--center"},m&&m.src&&r.a.createElement("div",{className:"margin-bottom--sm"},m.href?r.a.createElement("a",{href:m.href,target:"_blank",rel:"noopener noreferrer",className:M.a.footerLogoLink},r.a.createElement(P,{alt:m.alt,url:d})):r.a.createElement(P,{alt:m.alt,url:d})),r.a.createElement("small",null,c),r.a.createElement("br",null))))},q=a(459),R=a(460),F=a(3);a(138);t.a=function(e){var t=Object(p.a)().siteConfig,a=void 0===t?{}:t,n=a.favicon,o=(a.tagline,a.title),i=a.themeConfig.image,s=a.url,m=e.children,u=e.title,d=e.noFooter,f=e.description,h=e.image,g=e.keywords,v=(e.permalink,e.version),b=u?u+" | "+o:o,E=h||i,y=s+Object(_.a)(E),N=Object(_.a)(n),w=Object(F.h)(),k=w?"https://docs.qovery.com"+(w.pathname.endsWith("/")?w.pathname:w.pathname+"/"):null;return r.a.createElement(R.a,null,r.a.createElement(q.a,null,r.a.createElement(c.a,null,r.a.createElement("html",{lang:"en"}),r.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),b&&r.a.createElement("title",null,b),b&&r.a.createElement("meta",{property:"og:title",content:b}),n&&r.a.createElement("link",{rel:"shortcut icon",href:N}),f&&r.a.createElement("meta",{name:"description",content:f}),f&&r.a.createElement("meta",{property:"og:description",content:f}),v&&r.a.createElement("meta",{name:"docsearch:version",content:v}),g&&g.length&&r.a.createElement("meta",{name:"keywords",content:g.join(",")}),E&&r.a.createElement("meta",{property:"og:image",content:y}),E&&r.a.createElement("meta",{property:"twitter:image",content:y}),E&&r.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+b}),k&&r.a.createElement("meta",{property:"og:url",content:k}),r.a.createElement("meta",{name:"twitter:card",content:"summary"}),k&&r.a.createElement("link",{rel:"canonical",href:k})),r.a.createElement(l.a,null),r.a.createElement(S,null),r.a.createElement("div",{className:"main-wrapper"},m),!d&&r.a.createElement(Q,null)))}},447:function(e,t,a){"use strict";var n=a(9),r=a(0),l=a.n(r),c=a(420),o=a.n(c),i=a(433),s=(a(139),a(140)),m=a.n(s);t.a=function(e){return function(t){var a,r=t.id,c=Object(n.a)(t,["id"]),s=Object(i.a)().siteConfig,u=(s=void 0===s?{}:s).themeConfig,d=(u=void 0===u?{}:u).navbar,f=(d=void 0===d?{}:d).hideOnScroll,p=void 0!==f&&f;return r?l.a.createElement(e,c,l.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:o()("anchor",(a={},a[m.a.enhancedAnchor]=!p,a)),id:r}),l.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+r,title:"Direct link to heading"},"#"),c.children):l.a.createElement(e,c)}}},451:function(e,t,a){"use strict";var n=a(0),r=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=r},476:function(e,t){var a,n,r=e.exports={};function l(){throw new Error("setTimeout has not been defined")}function c(){throw new Error("clearTimeout has not been defined")}function o(e){if(a===setTimeout)return setTimeout(e,0);if((a===l||!a)&&setTimeout)return a=setTimeout,setTimeout(e,0);try{return a(e,0)}catch(t){try{return a.call(null,e,0)}catch(t){return a.call(this,e,0)}}}!function(){try{a="function"==typeof setTimeout?setTimeout:l}catch(e){a=l}try{n="function"==typeof clearTimeout?clearTimeout:c}catch(e){n=c}}();var i,s=[],m=!1,u=-1;function d(){m&&i&&(m=!1,i.length?s=i.concat(s):u=-1,s.length&&f())}function f(){if(!m){var e=o(d);m=!0;for(var t=s.length;t;){for(i=s,s=[];++u1)for(var a=1;a=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},t.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:function(){try{return window.localStorage}catch(e){}}(),t.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],t.formatters.j=function(e){try{return JSON.stringify(e)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}},t.enable(r())}).call(this,a(476))},553:function(e,t,a){var n;function r(e){function a(){if(a.enabled){var e=a,r=+new Date,l=r-(n||r);e.diff=l,e.prev=n,e.curr=r,n=r;for(var c=new Array(arguments.length),o=0;o0)return function(e){if((e=String(e)).length>100)return;var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(!t)return;var c=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*c;case"days":case"day":case"d":return c*l;case"hours":case"hour":case"hrs":case"hr":case"h":return c*r;case"minutes":case"minute":case"mins":case"min":case"m":return c*n;case"seconds":case"second":case"secs":case"sec":case"s":return c*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return c;default:return}}(e);if("number"===i&&!1===isNaN(e))return t.long?c(o=e,l,"day")||c(o,r,"hour")||c(o,n,"minute")||c(o,a,"second")||o+" ms":function(e){if(e>=l)return Math.round(e/l)+"d";if(e>=r)return Math.round(e/r)+"h";if(e>=n)return Math.round(e/n)+"m";if(e>=a)return Math.round(e/a)+"s";return e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},555:function(e,t,a){"use strict";var n=/^[-!#$%&'*+\/0-9=?A-Z^_a-z{|}~](\.?[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\.?[a-zA-Z0-9])*\.[a-zA-Z](-?[a-zA-Z0-9])+$/;t.validate=function(e){if(!e)return!1;if(e.length>254)return!1;if(!n.test(e))return!1;var t=e.split("@");return!(t[0].length>64)&&!t[1].split(".").some((function(e){return e.length>63}))}},559:function(e,t,a){"use strict";a(443),a(444);var n=a(0),r=a.n(n),l=a(420),c=a.n(l),o=(a(58),a(21),a(551)),i=a.n(o),s=a(555),m=function(e){return new Promise((function(t,a){return i()(e,{param:"c",timeout:3500},(function(e,n){e&&a(e),n&&t(n)}))}))},u=function(e){var t="";for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a)){var n="group["===a.substring(0,6)?a:a.toUpperCase();t=t.concat("&"+n+"="+e[a])}return t},d=function(e,t,a){var n=Object(s.validate)(e),r=encodeURIComponent(e);if(!n)return Promise.resolve({result:"error",msg:"The email you entered is not valid."});var l="https://qovery.us4.list-manage.com/subscribe/post-json?u=3c76e7a2087d5bc4020348c46&id=63bd993879";arguments.length<3&&"string"==typeof t?l=t:"string"==typeof a&&(l=a);var c="&EMAIL="+r+u(t),o=""+l+c;return m(o)};a(152),t.a=function(e){var t,a=e.block,l=e.buttonClass,o=e.center,i=e.description,s=e.subscriptionEnabled,m=e.size,u=e.width,f=Object(n.useState)(""),p=f[0],h=f[1],g=Object(n.useState)(!1),v=g[0],b=g[1],E=Object(n.useState)(!1),y=E[0],N=E[1],w=Object(n.useState)("Could not subscribe :("),k=w[0],_=w[1];return r.a.createElement("div",{className:c()("mailing-list",(t={"mailing-list--block":a,"mailing-list--center":o},t["mailing-list--"+m]=m,t))},!1!==i&&r.a.createElement("div",{className:"mailing-list--description"},i),s&&!v&&r.a.createElement("form",{onSubmit:function(e){return function(e){e.preventDefault(),d(p).then((function(e){"success"===e.result?(b(!0),y&&N(!1)):(N(!0),e.msg.includes(p+" is already subscribed")?_("This email is already subscribed to the newsletter"):_("Could not subscribe :("))})).catch((function(e){N(!0)}))}(e)},className:c()("mailing-list--form")},r.a.createElement("input",{onChange:function(e){return h(e.target.value)},className:c()("input","input--"+m),name:"email",placeholder:"you@email.com",type:"email",style:{width:u}}),r.a.createElement("button",{className:c()("button","button--"+(l||"primary"),"button--"+m),type:"submit"},"Subscribe")),y&&r.a.createElement("span",{className:"badge badge--secondary"},k),r.a.createElement("div",{style:{textAlign:"center"}},s&&v&&r.a.createElement("span",{className:"badge badge--primary"},"Subscribed!")))}}}]); \ No newline at end of file +/*! For license information please see c4f5d8e4.7311bd1c.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[204],{355:function(e,t,a){"use strict";a.r(t);var n=a(0),r=a.n(n),l=a(450),c=a(445),o=a(562);Object(l.a)("h2");t.default=function(){return r.a.createElement(c.a,{title:"Qovery Hub | Documentation, Guides, Tutorials",description:"Qovery is an Internal Developer Platform Helping Platform Engineers and Developers To Ship Faster."},r.a.createElement("header",{className:"hero"},r.a.createElement("div",{className:"container container--fluid"},r.a.createElement("h1",null,"Qovery Hub Resources"),r.a.createElement(o.a,{buttonClass:"highlight",description:"Qovery is an Internal Developer Platform Helping Platform Engineers and Developers To Ship Faster.",center:!0,size:"lg"}))),r.a.createElement("main",null,r.a.createElement("section",null,r.a.createElement("div",{className:"container"},r.a.createElement("div",{className:"row"},r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"docs",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-book"})),r.a.createElement("div",{className:"panel--title"},"Documentation"),r.a.createElement("div",{className:"panel--description"},"Read our product documentation"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"guides",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-layers"})),r.a.createElement("div",{className:"panel--title"},"Guides"),r.a.createElement("div",{className:"panel--description"},"Get started using Qovery smoothly"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"guides/tutorial",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-bookmark"})),r.a.createElement("div",{className:"panel--title"},"Tutorials"),r.a.createElement("div",{className:"panel--description"},"Check out our community tutorials"))))),r.a.createElement("div",{className:"container",style:{marginTop:"10px"}},r.a.createElement("div",{className:"row"},r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-message-circle"})),r.a.createElement("div",{className:"panel--title"},"Discord"),r.a.createElement("div",{className:"panel--description"},"Join our community on Discord"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://roadmap.qovery.com",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-flag"})),r.a.createElement("div",{className:"panel--title"},"Roadmap"),r.a.createElement("div",{className:"panel--description"},"Check out our public Roadmap"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://discuss.qovery.com",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-message-circle"})),r.a.createElement("div",{className:"panel--title"},"Forum"),r.a.createElement("div",{className:"panel--description"},"Join our community on Discourse"))),r.a.createElement("div",{className:"col"},r.a.createElement("a",{href:"https://github.com/Qovery",target:"_blank",className:"panel panel--link text--center"},r.a.createElement("div",{className:"panel--icon"},r.a.createElement("i",{className:"feather icon-github"})),r.a.createElement("div",{className:"panel--title"},"Github"),r.a.createElement("div",{className:"panel--description"},"Issues, code, and development"))))))))}},423:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t0&&r.a.createElement("div",{className:"row footer__links"},r.a.createElement("div",{className:"col col--5 footer__col"},r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement(u.a,{className:"navbar__logo",src:f,alt:"Qovery",width:"150",height:"auto"})),r.a.createElement("div",{className:"margin-bottom--md"},r.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),r.a.createElement("div",null,r.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},r.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},r.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},r.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",r.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},r.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),i.map((function(e,t){return r.a.createElement("div",{key:t,className:"col footer__col"},null!=e.title?r.a.createElement("h4",{className:"footer__title"},e.title):null,null!=e.items&&Array.isArray(e.items)&&e.items.length>0?r.a.createElement("ul",{className:"footer__items"},e.items.map((function(e,t){return e.html?r.a.createElement("li",{key:t,className:"footer__item",dangerouslySetInnerHTML:{__html:e.html}}):r.a.createElement("li",{key:e.href||e.to,className:"footer__item"},r.a.createElement(z,e))}))):null)}))),(m||c)&&r.a.createElement("div",{className:"text--center"},m&&m.src&&r.a.createElement("div",{className:"margin-bottom--sm"},m.href?r.a.createElement("a",{href:m.href,target:"_blank",rel:"noopener noreferrer",className:M.a.footerLogoLink},r.a.createElement(P,{alt:m.alt,url:d})):r.a.createElement(P,{alt:m.alt,url:d})),r.a.createElement("small",null,c),r.a.createElement("br",null))))},q=a(462),R=a(463),F=a(3);a(138);t.a=function(e){var t=Object(p.a)().siteConfig,a=void 0===t?{}:t,n=a.favicon,o=(a.tagline,a.title),i=a.themeConfig.image,s=a.url,m=e.children,u=e.title,d=e.noFooter,f=e.description,h=e.image,g=e.keywords,v=(e.permalink,e.version),b=u?u+" | "+o:o,E=h||i,y=s+Object(_.a)(E),N=Object(_.a)(n),w=Object(F.h)(),k=w?"https://docs.qovery.com"+(w.pathname.endsWith("/")?w.pathname:w.pathname+"/"):null;return r.a.createElement(R.a,null,r.a.createElement(q.a,null,r.a.createElement(c.a,null,r.a.createElement("html",{lang:"en"}),r.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),b&&r.a.createElement("title",null,b),b&&r.a.createElement("meta",{property:"og:title",content:b}),n&&r.a.createElement("link",{rel:"shortcut icon",href:N}),f&&r.a.createElement("meta",{name:"description",content:f}),f&&r.a.createElement("meta",{property:"og:description",content:f}),v&&r.a.createElement("meta",{name:"docsearch:version",content:v}),g&&g.length&&r.a.createElement("meta",{name:"keywords",content:g.join(",")}),E&&r.a.createElement("meta",{property:"og:image",content:y}),E&&r.a.createElement("meta",{property:"twitter:image",content:y}),E&&r.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+b}),k&&r.a.createElement("meta",{property:"og:url",content:k}),r.a.createElement("meta",{name:"twitter:card",content:"summary"}),k&&r.a.createElement("link",{rel:"canonical",href:k})),r.a.createElement(l.a,null),r.a.createElement(S,null),r.a.createElement("div",{className:"main-wrapper"},m),!d&&r.a.createElement(Q,null)))}},450:function(e,t,a){"use strict";var n=a(9),r=a(0),l=a.n(r),c=a(423),o=a.n(c),i=a(436),s=(a(139),a(140)),m=a.n(s);t.a=function(e){return function(t){var a,r=t.id,c=Object(n.a)(t,["id"]),s=Object(i.a)().siteConfig,u=(s=void 0===s?{}:s).themeConfig,d=(u=void 0===u?{}:u).navbar,f=(d=void 0===d?{}:d).hideOnScroll,p=void 0!==f&&f;return r?l.a.createElement(e,c,l.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:o()("anchor",(a={},a[m.a.enhancedAnchor]=!p,a)),id:r}),l.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+r,title:"Direct link to heading"},"#"),c.children):l.a.createElement(e,c)}}},454:function(e,t,a){"use strict";var n=a(0),r=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=r},479:function(e,t){var a,n,r=e.exports={};function l(){throw new Error("setTimeout has not been defined")}function c(){throw new Error("clearTimeout has not been defined")}function o(e){if(a===setTimeout)return setTimeout(e,0);if((a===l||!a)&&setTimeout)return a=setTimeout,setTimeout(e,0);try{return a(e,0)}catch(t){try{return a.call(null,e,0)}catch(t){return a.call(this,e,0)}}}!function(){try{a="function"==typeof setTimeout?setTimeout:l}catch(e){a=l}try{n="function"==typeof clearTimeout?clearTimeout:c}catch(e){n=c}}();var i,s=[],m=!1,u=-1;function d(){m&&i&&(m=!1,i.length?s=i.concat(s):u=-1,s.length&&f())}function f(){if(!m){var e=o(d);m=!0;for(var t=s.length;t;){for(i=s,s=[];++u1)for(var a=1;a=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},t.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:function(){try{return window.localStorage}catch(e){}}(),t.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],t.formatters.j=function(e){try{return JSON.stringify(e)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}},t.enable(r())}).call(this,a(479))},556:function(e,t,a){var n;function r(e){function a(){if(a.enabled){var e=a,r=+new Date,l=r-(n||r);e.diff=l,e.prev=n,e.curr=r,n=r;for(var c=new Array(arguments.length),o=0;o0)return function(e){if((e=String(e)).length>100)return;var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(!t)return;var c=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*c;case"days":case"day":case"d":return c*l;case"hours":case"hour":case"hrs":case"hr":case"h":return c*r;case"minutes":case"minute":case"mins":case"min":case"m":return c*n;case"seconds":case"second":case"secs":case"sec":case"s":return c*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return c;default:return}}(e);if("number"===i&&!1===isNaN(e))return t.long?c(o=e,l,"day")||c(o,r,"hour")||c(o,n,"minute")||c(o,a,"second")||o+" ms":function(e){if(e>=l)return Math.round(e/l)+"d";if(e>=r)return Math.round(e/r)+"h";if(e>=n)return Math.round(e/n)+"m";if(e>=a)return Math.round(e/a)+"s";return e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},558:function(e,t,a){"use strict";var n=/^[-!#$%&'*+\/0-9=?A-Z^_a-z{|}~](\.?[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\.?[a-zA-Z0-9])*\.[a-zA-Z](-?[a-zA-Z0-9])+$/;t.validate=function(e){if(!e)return!1;if(e.length>254)return!1;if(!n.test(e))return!1;var t=e.split("@");return!(t[0].length>64)&&!t[1].split(".").some((function(e){return e.length>63}))}},562:function(e,t,a){"use strict";a(446),a(447);var n=a(0),r=a.n(n),l=a(423),c=a.n(l),o=(a(58),a(21),a(554)),i=a.n(o),s=a(558),m=function(e){return new Promise((function(t,a){return i()(e,{param:"c",timeout:3500},(function(e,n){e&&a(e),n&&t(n)}))}))},u=function(e){var t="";for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a)){var n="group["===a.substring(0,6)?a:a.toUpperCase();t=t.concat("&"+n+"="+e[a])}return t},d=function(e,t,a){var n=Object(s.validate)(e),r=encodeURIComponent(e);if(!n)return Promise.resolve({result:"error",msg:"The email you entered is not valid."});var l="https://qovery.us4.list-manage.com/subscribe/post-json?u=3c76e7a2087d5bc4020348c46&id=63bd993879";arguments.length<3&&"string"==typeof t?l=t:"string"==typeof a&&(l=a);var c="&EMAIL="+r+u(t),o=""+l+c;return m(o)};a(152),t.a=function(e){var t,a=e.block,l=e.buttonClass,o=e.center,i=e.description,s=e.subscriptionEnabled,m=e.size,u=e.width,f=Object(n.useState)(""),p=f[0],h=f[1],g=Object(n.useState)(!1),v=g[0],b=g[1],E=Object(n.useState)(!1),y=E[0],N=E[1],w=Object(n.useState)("Could not subscribe :("),k=w[0],_=w[1];return r.a.createElement("div",{className:c()("mailing-list",(t={"mailing-list--block":a,"mailing-list--center":o},t["mailing-list--"+m]=m,t))},!1!==i&&r.a.createElement("div",{className:"mailing-list--description"},i),s&&!v&&r.a.createElement("form",{onSubmit:function(e){return function(e){e.preventDefault(),d(p).then((function(e){"success"===e.result?(b(!0),y&&N(!1)):(N(!0),e.msg.includes(p+" is already subscribed")?_("This email is already subscribed to the newsletter"):_("Could not subscribe :("))})).catch((function(e){N(!0)}))}(e)},className:c()("mailing-list--form")},r.a.createElement("input",{onChange:function(e){return h(e.target.value)},className:c()("input","input--"+m),name:"email",placeholder:"you@email.com",type:"email",style:{width:u}}),r.a.createElement("button",{className:c()("button","button--"+(l||"primary"),"button--"+m),type:"submit"},"Subscribe")),y&&r.a.createElement("span",{className:"badge badge--secondary"},k),r.a.createElement("div",{style:{textAlign:"center"}},s&&v&&r.a.createElement("span",{className:"badge badge--primary"},"Subscribed!")))}}}]); \ No newline at end of file diff --git a/c8223350.ab418736.js.LICENSE.txt b/c4f5d8e4.7311bd1c.js.LICENSE.txt similarity index 100% rename from c8223350.ab418736.js.LICENSE.txt rename to c4f5d8e4.7311bd1c.js.LICENSE.txt diff --git a/c536ba8c.5daa387b.js b/c536ba8c.ba684a1d.js similarity index 96% rename from c536ba8c.5daa387b.js rename to c536ba8c.ba684a1d.js index 56f57b3801..f03d65bc31 100644 --- a/c536ba8c.5daa387b.js +++ b/c536ba8c.ba684a1d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[202],{353:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return c})),r.d(t,"rightToc",(function(){return s})),r.d(t,"default",(function(){return l}));var n=r(1),a=r(9),o=(r(0),r(422)),i={last_modified_on:"2023-04-04",title:"Redis",description:"How to set up and use a Redis database"},c={id:"using-qovery/configuration/database/redis",title:"Redis",description:"How to set up and use a Redis database",source:"@site/docs/using-qovery/configuration/database/redis.md",permalink:"/docs/using-qovery/configuration/database/redis",sidebar:"docs",previous:{title:"MongoDB",permalink:"/docs/using-qovery/configuration/database/mongodb"},next:{title:"Cronjob",permalink:"/docs/using-qovery/configuration/cronjob"}},s=[{value:"Supported Versions and Cloud Providers",id:"supported-versions-and-cloud-providers",children:[]}],u={rightToc:s};function l(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},u,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams."),Object(o.b)("h2",{id:"supported-versions-and-cloud-providers"},"Supported Versions and Cloud Providers"),Object(o.b)("p",null,"You can find the supported versions directly within the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),"."),Object(o.b)("p",null,"Availability of the Container version or Cloud Provider Managed versions depends on the chosen Cloud Provider "),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Cloud provider"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Container supported"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Managed supported"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"AWS"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Yes"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Yes")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Scaleway"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Yes"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"No")))),Object(o.b)("p",null,"Have a look at the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/"}),"Database page")," to know more about the database creation and setup."))}l.isMDXComponent=!0},422:function(e,t,r){"use strict";r.d(t,"a",(function(){return d})),r.d(t,"b",(function(){return O}));var n=r(0),a=r.n(n);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=a.a.createContext({}),l=function(e){var t=a.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},d=function(e){var t=l(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(r),b=n,O=d["".concat(i,".").concat(b)]||d[b]||p[b]||o;return r?a.a.createElement(O,c({ref:t},u,{components:r})):a.a.createElement(O,c({ref:t},u))}));function O(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=b;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var u=2;u=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=a.a.createContext({}),l=function(e){var t=a.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},d=function(e){var t=l(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(r),b=n,O=d["".concat(i,".").concat(b)]||d[b]||p[b]||o;return r?a.a.createElement(O,c({ref:t},u,{components:r})):a.a.createElement(O,c({ref:t},u))}));function O(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=b;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var u=2;u1?arguments[1]:void 0)}}),r(74)("find")},439:function(t,e,r){"use strict";var n=r(8),o=r(483),i=r(55);r(56)("search",1,(function(t,e,r,u){return[function(r){var n=t(this),o=null==r?void 0:r[e];return void 0!==o?o.call(r,n):new RegExp(r)[e](String(n))},function(t){var e=u(r,t,this);if(e.done)return e.value;var a=n(t),c=String(this),l=a.lastIndex;o(l,0)||(a.lastIndex=0);var f=i(a,c);return o(a.lastIndex,l)||(a.lastIndex=l),null===f?-1:f.index}]}))},442:function(t,e,r){"use strict";r(454);var n=r(0),o=r.n(n),i=r(455),u=r(440),a=r(1),c=(r(443),r(444),r(456),r(427)),l=r(457),f=r(437),s=r.n(f),p=r(458),v=r.n(p),d=r(433),h=r(420),y=r.n(h),g=r(135),m=r.n(g),D=function(){return o.a.createElement("span",{className:y()(m.a.toggle,m.a.moon)})},_=function(){return o.a.createElement("span",{className:y()(m.a.toggle,m.a.sun)})},b=function(t){var e=Object(d.a)().isClient;return o.a.createElement(v.a,Object(a.a)({disabled:!e,icons:{checked:o.a.createElement(D,null),unchecked:o.a.createElement(_,null)}},t))};function E(){var t=Object(d.a)().siteConfig,e=(void 0===t?{}:t).customFields.metadata.latest_post,r=Date.parse(e.date),n=new Date,o=Math.abs(n-r),i=Math.ceil(o/864e5),u=null;return"undefined"!=typeof window&&(u=new Date(parseInt(window.localStorage.getItem("blogViewedAt")||"0"))),i<30&&(!u||u0&&o.a.createElement("div",{className:"row footer__links"},o.a.createElement("div",{className:"col col--5 footer__col"},o.a.createElement("div",{className:"margin-bottom--md"},o.a.createElement(s.a,{className:"navbar__logo",src:v,alt:"Qovery",width:"150",height:"auto"})),o.a.createElement("div",{className:"margin-bottom--md"},o.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),o.a.createElement("div",null,o.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},o.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",o.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},o.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",o.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},o.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",o.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},o.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),c.map((function(t,e){return o.a.createElement("div",{key:e,className:"col footer__col"},null!=t.title?o.a.createElement("h4",{className:"footer__title"},t.title):null,null!=t.items&&Array.isArray(t.items)&&t.items.length>0?o.a.createElement("ul",{className:"footer__items"},t.items.map((function(t,e){return t.html?o.a.createElement("li",{key:e,className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):o.a.createElement("li",{key:t.href||t.to,className:"footer__item"},o.a.createElement(B,t))}))):null)}))),(f||u)&&o.a.createElement("div",{className:"text--center"},f&&f.src&&o.a.createElement("div",{className:"margin-bottom--sm"},f.href?o.a.createElement("a",{href:f.href,target:"_blank",rel:"noopener noreferrer",className:R.a.footerLogoLink},o.a.createElement(L,{alt:f.alt,url:p})):o.a.createElement(L,{alt:f.alt,url:p})),o.a.createElement("small",null,u),o.a.createElement("br",null))))},M=r(459),W=r(460),U=r(3);r(138);e.a=function(t){var e=Object(d.a)().siteConfig,r=void 0===e?{}:e,n=r.favicon,a=(r.tagline,r.title),c=r.themeConfig.image,l=r.url,f=t.children,s=t.title,p=t.noFooter,v=t.description,h=t.image,y=t.keywords,g=(t.permalink,t.version),m=s?s+" | "+a:a,D=h||c,_=l+Object(F.a)(D),b=Object(F.a)(n),E=Object(U.h)(),w=E?"https://docs.qovery.com"+(E.pathname.endsWith("/")?E.pathname:E.pathname+"/"):null;return o.a.createElement(W.a,null,o.a.createElement(M.a,null,o.a.createElement(u.a,null,o.a.createElement("html",{lang:"en"}),o.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),m&&o.a.createElement("title",null,m),m&&o.a.createElement("meta",{property:"og:title",content:m}),n&&o.a.createElement("link",{rel:"shortcut icon",href:b}),v&&o.a.createElement("meta",{name:"description",content:v}),v&&o.a.createElement("meta",{property:"og:description",content:v}),g&&o.a.createElement("meta",{name:"docsearch:version",content:g}),y&&y.length&&o.a.createElement("meta",{name:"keywords",content:y.join(",")}),D&&o.a.createElement("meta",{property:"og:image",content:_}),D&&o.a.createElement("meta",{property:"twitter:image",content:_}),D&&o.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+m}),w&&o.a.createElement("meta",{property:"og:url",content:w}),o.a.createElement("meta",{name:"twitter:card",content:"summary"}),w&&o.a.createElement("link",{rel:"canonical",href:w})),o.a.createElement(i.a,null),o.a.createElement(N,null),o.a.createElement("div",{className:"main-wrapper"},f),!p&&o.a.createElement(T,null)))}},447:function(t,e,r){"use strict";var n=r(9),o=r(0),i=r.n(o),u=r(420),a=r.n(u),c=r(433),l=(r(139),r(140)),f=r.n(l);e.a=function(t){return function(e){var r,o=e.id,u=Object(n.a)(e,["id"]),l=Object(c.a)().siteConfig,s=(l=void 0===l?{}:l).themeConfig,p=(s=void 0===s?{}:s).navbar,v=(p=void 0===p?{}:p).hideOnScroll,d=void 0!==v&&v;return o?i.a.createElement(t,u,i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:a()("anchor",(r={},r[f.a.enhancedAnchor]=!d,r)),id:o}),i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+o,title:"Direct link to heading"},"#"),u.children):i.a.createElement(t,u)}}},448:function(t,e,r){(function(t,n){var o;(function(){var i="Expected a function",u="__lodash_placeholder__",a=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],c="[object Arguments]",l="[object Array]",f="[object Boolean]",s="[object Date]",p="[object Error]",v="[object Function]",d="[object GeneratorFunction]",h="[object Map]",y="[object Number]",g="[object Object]",m="[object RegExp]",D="[object Set]",_="[object String]",b="[object Symbol]",E="[object WeakMap]",w="[object ArrayBuffer]",F="[object DataView]",j="[object Float32Array]",A="[object Float64Array]",x="[object Int8Array]",O="[object Int16Array]",S="[object Int32Array]",k="[object Uint8Array]",C="[object Uint16Array]",N="[object Uint32Array]",P=/\b__p \+= '';/g,I=/\b(__p \+=) '' \+/g,R=/(__e\(.*?\)|\b__t\)) \+\n'';/g,B=/&(?:amp|lt|gt|quot|#39);/g,L=/[&<>"']/g,T=RegExp(B.source),M=RegExp(L.source),W=/<%-([\s\S]+?)%>/g,U=/<%([\s\S]+?)%>/g,z=/<%=([\s\S]+?)%>/g,$=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,q=/^\w*$/,G=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,V=/[\\^$.*+?()[\]{}|]/g,H=RegExp(V.source),Q=/^\s+|\s+$/g,J=/^\s+/,Z=/\s+$/,K=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Y=/\{\n\/\* \[wrapped with (.+)\] \*/,X=/,? & /,tt=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,et=/\\(\\)?/g,rt=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,nt=/\w*$/,ot=/^[-+]0x[0-9a-f]+$/i,it=/^0b[01]+$/i,ut=/^\[object .+?Constructor\]$/,at=/^0o[0-7]+$/i,ct=/^(?:0|[1-9]\d*)$/,lt=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,ft=/($^)/,st=/['\n\r\u2028\u2029\\]/g,pt="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",vt="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",dt="[\\ud800-\\udfff]",ht="["+vt+"]",yt="["+pt+"]",gt="\\d+",mt="[\\u2700-\\u27bf]",Dt="[a-z\\xdf-\\xf6\\xf8-\\xff]",_t="[^\\ud800-\\udfff"+vt+gt+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",bt="\\ud83c[\\udffb-\\udfff]",Et="[^\\ud800-\\udfff]",wt="(?:\\ud83c[\\udde6-\\uddff]){2}",Ft="[\\ud800-\\udbff][\\udc00-\\udfff]",jt="[A-Z\\xc0-\\xd6\\xd8-\\xde]",At="(?:"+Dt+"|"+_t+")",xt="(?:"+jt+"|"+_t+")",Ot="(?:"+yt+"|"+bt+")"+"?",St="[\\ufe0e\\ufe0f]?"+Ot+("(?:\\u200d(?:"+[Et,wt,Ft].join("|")+")[\\ufe0e\\ufe0f]?"+Ot+")*"),kt="(?:"+[mt,wt,Ft].join("|")+")"+St,Ct="(?:"+[Et+yt+"?",yt,wt,Ft,dt].join("|")+")",Nt=RegExp("['\u2019]","g"),Pt=RegExp(yt,"g"),It=RegExp(bt+"(?="+bt+")|"+Ct+St,"g"),Rt=RegExp([jt+"?"+Dt+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?="+[ht,jt,"$"].join("|")+")",xt+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?="+[ht,jt+At,"$"].join("|")+")",jt+"?"+At+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?",jt+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",gt,kt].join("|"),"g"),Bt=RegExp("[\\u200d\\ud800-\\udfff"+pt+"\\ufe0e\\ufe0f]"),Lt=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Tt=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Mt=-1,Wt={};Wt[j]=Wt[A]=Wt[x]=Wt[O]=Wt[S]=Wt[k]=Wt["[object Uint8ClampedArray]"]=Wt[C]=Wt[N]=!0,Wt[c]=Wt[l]=Wt[w]=Wt[f]=Wt[F]=Wt[s]=Wt[p]=Wt[v]=Wt[h]=Wt[y]=Wt[g]=Wt[m]=Wt[D]=Wt[_]=Wt[E]=!1;var Ut={};Ut[c]=Ut[l]=Ut[w]=Ut[F]=Ut[f]=Ut[s]=Ut[j]=Ut[A]=Ut[x]=Ut[O]=Ut[S]=Ut[h]=Ut[y]=Ut[g]=Ut[m]=Ut[D]=Ut[_]=Ut[b]=Ut[k]=Ut["[object Uint8ClampedArray]"]=Ut[C]=Ut[N]=!0,Ut[p]=Ut[v]=Ut[E]=!1;var zt={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},$t=parseFloat,qt=parseInt,Gt="object"==typeof t&&t&&t.Object===Object&&t,Vt="object"==typeof self&&self&&self.Object===Object&&self,Ht=Gt||Vt||Function("return this")(),Qt=e&&!e.nodeType&&e,Jt=Qt&&"object"==typeof n&&n&&!n.nodeType&&n,Zt=Jt&&Jt.exports===Qt,Kt=Zt&&Gt.process,Yt=function(){try{var t=Jt&&Jt.require&&Jt.require("util").types;return t||Kt&&Kt.binding&&Kt.binding("util")}catch(e){}}(),Xt=Yt&&Yt.isArrayBuffer,te=Yt&&Yt.isDate,ee=Yt&&Yt.isMap,re=Yt&&Yt.isRegExp,ne=Yt&&Yt.isSet,oe=Yt&&Yt.isTypedArray;function ie(t,e,r){switch(r.length){case 0:return t.call(e);case 1:return t.call(e,r[0]);case 2:return t.call(e,r[0],r[1]);case 3:return t.call(e,r[0],r[1],r[2])}return t.apply(e,r)}function ue(t,e,r,n){for(var o=-1,i=null==t?0:t.length;++o-1}function pe(t,e,r){for(var n=-1,o=null==t?0:t.length;++n-1;);return r}function Ie(t,e){for(var r=t.length;r--&&be(e,t[r],0)>-1;);return r}function Re(t,e){for(var r=t.length,n=0;r--;)t[r]===e&&++n;return n}var Be=Ae({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),Le=Ae({"&":"&","<":"<",">":">",'"':""","'":"'"});function Te(t){return"\\"+zt[t]}function Me(t){return Bt.test(t)}function We(t){var e=-1,r=Array(t.size);return t.forEach((function(t,n){r[++e]=[n,t]})),r}function Ue(t,e){return function(r){return t(e(r))}}function ze(t,e){for(var r=-1,n=t.length,o=0,i=[];++r",""":'"',"'":"'"});var Qe=function t(e){var r,n=(e=null==e?Ht:Qe.defaults(Ht.Object(),e,Qe.pick(Ht,Tt))).Array,o=e.Date,pt=e.Error,vt=e.Function,dt=e.Math,ht=e.Object,yt=e.RegExp,gt=e.String,mt=e.TypeError,Dt=n.prototype,_t=vt.prototype,bt=ht.prototype,Et=e["__core-js_shared__"],wt=_t.toString,Ft=bt.hasOwnProperty,jt=0,At=(r=/[^.]+$/.exec(Et&&Et.keys&&Et.keys.IE_PROTO||""))?"Symbol(src)_1."+r:"",xt=bt.toString,Ot=wt.call(ht),St=Ht._,kt=yt("^"+wt.call(Ft).replace(V,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Ct=Zt?e.Buffer:void 0,It=e.Symbol,Bt=e.Uint8Array,zt=Ct?Ct.allocUnsafe:void 0,Gt=Ue(ht.getPrototypeOf,ht),Vt=ht.create,Qt=bt.propertyIsEnumerable,Jt=Dt.splice,Kt=It?It.isConcatSpreadable:void 0,Yt=It?It.iterator:void 0,me=It?It.toStringTag:void 0,Ae=function(){try{var t=ti(ht,"defineProperty");return t({},"",{}),t}catch(e){}}(),Je=e.clearTimeout!==Ht.clearTimeout&&e.clearTimeout,Ze=o&&o.now!==Ht.Date.now&&o.now,Ke=e.setTimeout!==Ht.setTimeout&&e.setTimeout,Ye=dt.ceil,Xe=dt.floor,tr=ht.getOwnPropertySymbols,er=Ct?Ct.isBuffer:void 0,rr=e.isFinite,nr=Dt.join,or=Ue(ht.keys,ht),ir=dt.max,ur=dt.min,ar=o.now,cr=e.parseInt,lr=dt.random,fr=Dt.reverse,sr=ti(e,"DataView"),pr=ti(e,"Map"),vr=ti(e,"Promise"),dr=ti(e,"Set"),hr=ti(e,"WeakMap"),yr=ti(ht,"create"),gr=hr&&new hr,mr={},Dr=xi(sr),_r=xi(pr),br=xi(vr),Er=xi(dr),wr=xi(hr),Fr=It?It.prototype:void 0,jr=Fr?Fr.valueOf:void 0,Ar=Fr?Fr.toString:void 0;function xr(t){if(qu(t)&&!Pu(t)&&!(t instanceof Cr)){if(t instanceof kr)return t;if(Ft.call(t,"__wrapped__"))return Oi(t)}return new kr(t)}var Or=function(){function t(){}return function(e){if(!$u(e))return{};if(Vt)return Vt(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}();function Sr(){}function kr(t,e){this.__wrapped__=t,this.__actions__=[],this.__chain__=!!e,this.__index__=0,this.__values__=void 0}function Cr(t){this.__wrapped__=t,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Nr(t){var e=-1,r=null==t?0:t.length;for(this.clear();++e=e?t:e)),t}function Jr(t,e,r,n,o,i){var u,a=1&e,l=2&e,p=4&e;if(r&&(u=o?r(t,n,o,i):r(t)),void 0!==u)return u;if(!$u(t))return t;var E=Pu(t);if(E){if(u=function(t){var e=t.length,r=new t.constructor(e);e&&"string"==typeof t[0]&&Ft.call(t,"index")&&(r.index=t.index,r.input=t.input);return r}(t),!a)return mo(t,u)}else{var P=ni(t),I=P==v||P==d;if(Lu(t))return so(t,a);if(P==g||P==c||I&&!o){if(u=l||I?{}:ii(t),!a)return l?function(t,e){return Do(t,ri(t),e)}(t,function(t,e){return t&&Do(e,ba(e),t)}(u,t)):function(t,e){return Do(t,ei(t),e)}(t,Gr(u,t))}else{if(!Ut[P])return o?t:{};u=function(t,e,r){var n=t.constructor;switch(e){case w:return po(t);case f:case s:return new n(+t);case F:return function(t,e){var r=e?po(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.byteLength)}(t,r);case j:case A:case x:case O:case S:case k:case"[object Uint8ClampedArray]":case C:case N:return vo(t,r);case h:return new n;case y:case _:return new n(t);case m:return function(t){var e=new t.constructor(t.source,nt.exec(t));return e.lastIndex=t.lastIndex,e}(t);case D:return new n;case b:return o=t,jr?ht(jr.call(o)):{}}var o}(t,P,a)}}i||(i=new Br);var R=i.get(t);if(R)return R;i.set(t,u),Ju(t)?t.forEach((function(n){u.add(Jr(n,e,r,n,t,i))})):Gu(t)&&t.forEach((function(n,o){u.set(o,Jr(n,e,r,o,t,i))}));var B=E?void 0:(p?l?Ho:Vo:l?ba:_a)(t);return ae(B||t,(function(n,o){B&&(n=t[o=n]),zr(u,o,Jr(n,e,r,o,t,i))})),u}function Zr(t,e,r){var n=r.length;if(null==t)return!n;for(t=ht(t);n--;){var o=r[n],i=e[o],u=t[o];if(void 0===u&&!(o in t)||!i(u))return!1}return!0}function Kr(t,e,r){if("function"!=typeof t)throw new mt(i);return _i((function(){t.apply(void 0,r)}),e)}function Yr(t,e,r,n){var o=-1,i=se,u=!0,a=t.length,c=[],l=e.length;if(!a)return c;r&&(e=ve(e,ke(r))),n?(i=pe,u=!1):e.length>=200&&(i=Ne,u=!1,e=new Rr(e));t:for(;++o-1},Pr.prototype.set=function(t,e){var r=this.__data__,n=$r(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this},Ir.prototype.clear=function(){this.size=0,this.__data__={hash:new Nr,map:new(pr||Pr),string:new Nr}},Ir.prototype.delete=function(t){var e=Yo(this,t).delete(t);return this.size-=e?1:0,e},Ir.prototype.get=function(t){return Yo(this,t).get(t)},Ir.prototype.has=function(t){return Yo(this,t).has(t)},Ir.prototype.set=function(t,e){var r=Yo(this,t),n=r.size;return r.set(t,e),this.size+=r.size==n?0:1,this},Rr.prototype.add=Rr.prototype.push=function(t){return this.__data__.set(t,"__lodash_hash_undefined__"),this},Rr.prototype.has=function(t){return this.__data__.has(t)},Br.prototype.clear=function(){this.__data__=new Pr,this.size=0},Br.prototype.delete=function(t){var e=this.__data__,r=e.delete(t);return this.size=e.size,r},Br.prototype.get=function(t){return this.__data__.get(t)},Br.prototype.has=function(t){return this.__data__.has(t)},Br.prototype.set=function(t,e){var r=this.__data__;if(r instanceof Pr){var n=r.__data__;if(!pr||n.length<199)return n.push([t,e]),this.size=++r.size,this;r=this.__data__=new Ir(n)}return r.set(t,e),this.size=r.size,this};var Xr=Eo(cn),tn=Eo(ln,!0);function en(t,e){var r=!0;return Xr(t,(function(t,n,o){return r=!!e(t,n,o)})),r}function rn(t,e,r){for(var n=-1,o=t.length;++n0&&r(a)?e>1?on(a,e-1,r,n,o):de(o,a):n||(o[o.length]=a)}return o}var un=wo(),an=wo(!0);function cn(t,e){return t&&un(t,e,_a)}function ln(t,e){return t&&an(t,e,_a)}function fn(t,e){return fe(e,(function(e){return Wu(t[e])}))}function sn(t,e){for(var r=0,n=(e=ao(e,t)).length;null!=t&&re}function hn(t,e){return null!=t&&Ft.call(t,e)}function yn(t,e){return null!=t&&e in ht(t)}function gn(t,e,r){for(var o=r?pe:se,i=t[0].length,u=t.length,a=u,c=n(u),l=1/0,f=[];a--;){var s=t[a];a&&e&&(s=ve(s,ke(e))),l=ur(s.length,l),c[a]=!r&&(e||i>=120&&s.length>=120)?new Rr(a&&s):void 0}s=t[0];var p=-1,v=c[0];t:for(;++p=a)return c;var l=r[n];return c*("desc"==l?-1:1)}}return t.index-e.index}(t,e,r)}))}function Pn(t,e,r){for(var n=-1,o=e.length,i={};++n-1;)a!==t&&Jt.call(a,c,1),Jt.call(t,c,1);return t}function Rn(t,e){for(var r=t?e.length:0,n=r-1;r--;){var o=e[r];if(r==n||o!==i){var i=o;ai(o)?Jt.call(t,o,1):Xn(t,o)}}return t}function Bn(t,e){return t+Xe(lr()*(e-t+1))}function Ln(t,e){var r="";if(!t||e<1||e>9007199254740991)return r;do{e%2&&(r+=t),(e=Xe(e/2))&&(t+=t)}while(e);return r}function Tn(t,e){return bi(hi(t,e,Va),t+"")}function Mn(t){return Tr(Sa(t))}function Wn(t,e){var r=Sa(t);return Fi(r,Qr(e,0,r.length))}function Un(t,e,r,n){if(!$u(t))return t;for(var o=-1,i=(e=ao(e,t)).length,u=i-1,a=t;null!=a&&++oi?0:i+e),(r=r>i?i:r)<0&&(r+=i),i=e>r?0:r-e>>>0,e>>>=0;for(var u=n(i);++o>>1,u=t[i];null!==u&&!Ku(u)&&(r?u<=e:u=200){var l=e?null:To(t);if(l)return $e(l);u=!1,o=Ne,c=new Rr}else c=e?[]:a;t:for(;++n=n?t:Gn(t,e,r)}var fo=Je||function(t){return Ht.clearTimeout(t)};function so(t,e){if(e)return t.slice();var r=t.length,n=zt?zt(r):new t.constructor(r);return t.copy(n),n}function po(t){var e=new t.constructor(t.byteLength);return new Bt(e).set(new Bt(t)),e}function vo(t,e){var r=e?po(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.length)}function ho(t,e){if(t!==e){var r=void 0!==t,n=null===t,o=t==t,i=Ku(t),u=void 0!==e,a=null===e,c=e==e,l=Ku(e);if(!a&&!l&&!i&&t>e||i&&u&&c&&!a&&!l||n&&u&&c||!r&&c||!o)return 1;if(!n&&!i&&!l&&t1?r[o-1]:void 0,u=o>2?r[2]:void 0;for(i=t.length>3&&"function"==typeof i?(o--,i):void 0,u&&ci(r[0],r[1],u)&&(i=o<3?void 0:i,o=1),e=ht(e);++n-1?o[i?e[u]:u]:void 0}}function Oo(t){return Go((function(e){var r=e.length,n=r,o=kr.prototype.thru;for(t&&e.reverse();n--;){var u=e[n];if("function"!=typeof u)throw new mt(i);if(o&&!a&&"wrapper"==Jo(u))var a=new kr([],!0)}for(n=a?n:r;++n1&&D.reverse(),s&&la))return!1;var l=i.get(t);if(l&&i.get(e))return l==e;var f=-1,s=!0,p=2&r?new Rr:void 0;for(i.set(t,e),i.set(e,t);++f-1&&t%1==0&&t1?"& ":"")+e[n],e=e.join(r>2?", ":" "),t.replace(K,"{\n/* [wrapped with "+e+"] */\n")}(n,function(t,e){return ae(a,(function(r){var n="_."+r[0];e&r[1]&&!se(t,n)&&t.push(n)})),t.sort()}(function(t){var e=t.match(Y);return e?e[1].split(X):[]}(n),r)))}function wi(t){var e=0,r=0;return function(){var n=ar(),o=16-(n-r);if(r=n,o>0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}function Fi(t,e){var r=-1,n=t.length,o=n-1;for(e=void 0===e?n:e;++r1?t[e-1]:void 0;return r="function"==typeof r?(t.pop(),r):void 0,Qi(t,r)}));function eu(t){var e=xr(t);return e.__chain__=!0,e}function ru(t,e){return e(t)}var nu=Go((function(t){var e=t.length,r=e?t[0]:0,n=this.__wrapped__,o=function(e){return Hr(e,t)};return!(e>1||this.__actions__.length)&&n instanceof Cr&&ai(r)?((n=n.slice(r,+r+(e?1:0))).__actions__.push({func:ru,args:[o],thisArg:void 0}),new kr(n,this.__chain__).thru((function(t){return e&&!t.length&&t.push(void 0),t}))):this.thru(o)}));var ou=_o((function(t,e,r){Ft.call(t,r)?++t[r]:Vr(t,r,1)}));var iu=xo(Ni),uu=xo(Pi);function au(t,e){return(Pu(t)?ae:Xr)(t,Ko(e,3))}function cu(t,e){return(Pu(t)?ce:tn)(t,Ko(e,3))}var lu=_o((function(t,e,r){Ft.call(t,r)?t[r].push(e):Vr(t,r,[e])}));var fu=Tn((function(t,e,r){var o=-1,i="function"==typeof e,u=Ru(t)?n(t.length):[];return Xr(t,(function(t){u[++o]=i?ie(e,t,r):mn(t,e,r)})),u})),su=_o((function(t,e,r){Vr(t,r,e)}));function pu(t,e){return(Pu(t)?ve:xn)(t,Ko(e,3))}var vu=_o((function(t,e,r){t[r?0:1].push(e)}),(function(){return[[],[]]}));var du=Tn((function(t,e){if(null==t)return[];var r=e.length;return r>1&&ci(t,e[0],e[1])?e=[]:r>2&&ci(e[0],e[1],e[2])&&(e=[e[0]]),Nn(t,on(e,1),[])})),hu=Ze||function(){return Ht.Date.now()};function yu(t,e,r){return e=r?void 0:e,Wo(t,128,void 0,void 0,void 0,void 0,e=t&&null==e?t.length:e)}function gu(t,e){var r;if("function"!=typeof e)throw new mt(i);return t=na(t),function(){return--t>0&&(r=e.apply(this,arguments)),t<=1&&(e=void 0),r}}var mu=Tn((function(t,e,r){var n=1;if(r.length){var o=ze(r,Zo(mu));n|=32}return Wo(t,n,e,r,o)})),Du=Tn((function(t,e,r){var n=3;if(r.length){var o=ze(r,Zo(Du));n|=32}return Wo(e,n,t,r,o)}));function _u(t,e,r){var n,o,u,a,c,l,f=0,s=!1,p=!1,v=!0;if("function"!=typeof t)throw new mt(i);function d(e){var r=n,i=o;return n=o=void 0,f=e,a=t.apply(i,r)}function h(t){return f=t,c=_i(g,e),s?d(t):a}function y(t){var r=t-l;return void 0===l||r>=e||r<0||p&&t-f>=u}function g(){var t=hu();if(y(t))return m(t);c=_i(g,function(t){var r=e-(t-l);return p?ur(r,u-(t-f)):r}(t))}function m(t){return c=void 0,v&&n?d(t):(n=o=void 0,a)}function D(){var t=hu(),r=y(t);if(n=arguments,o=this,l=t,r){if(void 0===c)return h(l);if(p)return fo(c),c=_i(g,e),d(l)}return void 0===c&&(c=_i(g,e)),a}return e=ia(e)||0,$u(r)&&(s=!!r.leading,u=(p="maxWait"in r)?ir(ia(r.maxWait)||0,e):u,v="trailing"in r?!!r.trailing:v),D.cancel=function(){void 0!==c&&fo(c),f=0,n=l=o=c=void 0},D.flush=function(){return void 0===c?a:m(hu())},D}var bu=Tn((function(t,e){return Kr(t,1,e)})),Eu=Tn((function(t,e,r){return Kr(t,ia(e)||0,r)}));function wu(t,e){if("function"!=typeof t||null!=e&&"function"!=typeof e)throw new mt(i);var r=function(){var n=arguments,o=e?e.apply(this,n):n[0],i=r.cache;if(i.has(o))return i.get(o);var u=t.apply(this,n);return r.cache=i.set(o,u)||i,u};return r.cache=new(wu.Cache||Ir),r}function Fu(t){if("function"!=typeof t)throw new mt(i);return function(){var e=arguments;switch(e.length){case 0:return!t.call(this);case 1:return!t.call(this,e[0]);case 2:return!t.call(this,e[0],e[1]);case 3:return!t.call(this,e[0],e[1],e[2])}return!t.apply(this,e)}}wu.Cache=Ir;var ju=co((function(t,e){var r=(e=1==e.length&&Pu(e[0])?ve(e[0],ke(Ko())):ve(on(e,1),ke(Ko()))).length;return Tn((function(n){for(var o=-1,i=ur(n.length,r);++o=e})),Nu=Dn(function(){return arguments}())?Dn:function(t){return qu(t)&&Ft.call(t,"callee")&&!Qt.call(t,"callee")},Pu=n.isArray,Iu=Xt?ke(Xt):function(t){return qu(t)&&vn(t)==w};function Ru(t){return null!=t&&zu(t.length)&&!Wu(t)}function Bu(t){return qu(t)&&Ru(t)}var Lu=er||ic,Tu=te?ke(te):function(t){return qu(t)&&vn(t)==s};function Mu(t){if(!qu(t))return!1;var e=vn(t);return e==p||"[object DOMException]"==e||"string"==typeof t.message&&"string"==typeof t.name&&!Hu(t)}function Wu(t){if(!$u(t))return!1;var e=vn(t);return e==v||e==d||"[object AsyncFunction]"==e||"[object Proxy]"==e}function Uu(t){return"number"==typeof t&&t==na(t)}function zu(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=9007199254740991}function $u(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)}function qu(t){return null!=t&&"object"==typeof t}var Gu=ee?ke(ee):function(t){return qu(t)&&ni(t)==h};function Vu(t){return"number"==typeof t||qu(t)&&vn(t)==y}function Hu(t){if(!qu(t)||vn(t)!=g)return!1;var e=Gt(t);if(null===e)return!0;var r=Ft.call(e,"constructor")&&e.constructor;return"function"==typeof r&&r instanceof r&&wt.call(r)==Ot}var Qu=re?ke(re):function(t){return qu(t)&&vn(t)==m};var Ju=ne?ke(ne):function(t){return qu(t)&&ni(t)==D};function Zu(t){return"string"==typeof t||!Pu(t)&&qu(t)&&vn(t)==_}function Ku(t){return"symbol"==typeof t||qu(t)&&vn(t)==b}var Yu=oe?ke(oe):function(t){return qu(t)&&zu(t.length)&&!!Wt[vn(t)]};var Xu=Ro(An),ta=Ro((function(t,e){return t<=e}));function ea(t){if(!t)return[];if(Ru(t))return Zu(t)?Ve(t):mo(t);if(Yt&&t[Yt])return function(t){for(var e,r=[];!(e=t.next()).done;)r.push(e.value);return r}(t[Yt]());var e=ni(t);return(e==h?We:e==D?$e:Sa)(t)}function ra(t){return t?(t=ia(t))===1/0||t===-1/0?17976931348623157e292*(t<0?-1:1):t==t?t:0:0===t?t:0}function na(t){var e=ra(t),r=e%1;return e==e?r?e-r:e:0}function oa(t){return t?Qr(na(t),0,4294967295):0}function ia(t){if("number"==typeof t)return t;if(Ku(t))return NaN;if($u(t)){var e="function"==typeof t.valueOf?t.valueOf():t;t=$u(e)?e+"":e}if("string"!=typeof t)return 0===t?t:+t;t=t.replace(Q,"");var r=it.test(t);return r||at.test(t)?qt(t.slice(2),r?2:8):ot.test(t)?NaN:+t}function ua(t){return Do(t,ba(t))}function aa(t){return null==t?"":Kn(t)}var ca=bo((function(t,e){if(pi(e)||Ru(e))Do(e,_a(e),t);else for(var r in e)Ft.call(e,r)&&zr(t,r,e[r])})),la=bo((function(t,e){Do(e,ba(e),t)})),fa=bo((function(t,e,r,n){Do(e,ba(e),t,n)})),sa=bo((function(t,e,r,n){Do(e,_a(e),t,n)})),pa=Go(Hr);var va=Tn((function(t,e){t=ht(t);var r=-1,n=e.length,o=n>2?e[2]:void 0;for(o&&ci(e[0],e[1],o)&&(n=1);++r1),e})),Do(t,Ho(t),r),n&&(r=Jr(r,7,$o));for(var o=e.length;o--;)Xn(r,e[o]);return r}));var ja=Go((function(t,e){return null==t?{}:function(t,e){return Pn(t,e,(function(e,r){return ya(t,r)}))}(t,e)}));function Aa(t,e){if(null==t)return{};var r=ve(Ho(t),(function(t){return[t]}));return e=Ko(e),Pn(t,r,(function(t,r){return e(t,r[0])}))}var xa=Mo(_a),Oa=Mo(ba);function Sa(t){return null==t?[]:Ce(t,_a(t))}var ka=jo((function(t,e,r){return e=e.toLowerCase(),t+(r?Ca(e):e)}));function Ca(t){return Ma(aa(t).toLowerCase())}function Na(t){return(t=aa(t))&&t.replace(lt,Be).replace(Pt,"")}var Pa=jo((function(t,e,r){return t+(r?"-":"")+e.toLowerCase()})),Ia=jo((function(t,e,r){return t+(r?" ":"")+e.toLowerCase()})),Ra=Fo("toLowerCase");var Ba=jo((function(t,e,r){return t+(r?"_":"")+e.toLowerCase()}));var La=jo((function(t,e,r){return t+(r?" ":"")+Ma(e)}));var Ta=jo((function(t,e,r){return t+(r?" ":"")+e.toUpperCase()})),Ma=Fo("toUpperCase");function Wa(t,e,r){return t=aa(t),void 0===(e=r?void 0:e)?function(t){return Lt.test(t)}(t)?function(t){return t.match(Rt)||[]}(t):function(t){return t.match(tt)||[]}(t):t.match(e)||[]}var Ua=Tn((function(t,e){try{return ie(t,void 0,e)}catch(r){return Mu(r)?r:new pt(r)}})),za=Go((function(t,e){return ae(e,(function(e){e=Ai(e),Vr(t,e,mu(t[e],t))})),t}));function $a(t){return function(){return t}}var qa=Oo(),Ga=Oo(!0);function Va(t){return t}function Ha(t){return wn("function"==typeof t?t:Jr(t,1))}var Qa=Tn((function(t,e){return function(r){return mn(r,t,e)}})),Ja=Tn((function(t,e){return function(r){return mn(t,r,e)}}));function Za(t,e,r){var n=_a(e),o=fn(e,n);null!=r||$u(e)&&(o.length||!n.length)||(r=e,e=t,t=this,o=fn(e,_a(e)));var i=!($u(r)&&"chain"in r&&!r.chain),u=Wu(t);return ae(o,(function(r){var n=e[r];t[r]=n,u&&(t.prototype[r]=function(){var e=this.__chain__;if(i||e){var r=t(this.__wrapped__),o=r.__actions__=mo(this.__actions__);return o.push({func:n,args:arguments,thisArg:t}),r.__chain__=e,r}return n.apply(t,de([this.value()],arguments))})})),t}function Ka(){}var Ya=No(ve),Xa=No(le),tc=No(ge);function ec(t){return li(t)?je(Ai(t)):function(t){return function(e){return sn(e,t)}}(t)}var rc=Io(),nc=Io(!0);function oc(){return[]}function ic(){return!1}var uc=Co((function(t,e){return t+e}),0),ac=Lo("ceil"),cc=Co((function(t,e){return t/e}),1),lc=Lo("floor");var fc,sc=Co((function(t,e){return t*e}),1),pc=Lo("round"),vc=Co((function(t,e){return t-e}),0);return xr.after=function(t,e){if("function"!=typeof e)throw new mt(i);return t=na(t),function(){if(--t<1)return e.apply(this,arguments)}},xr.ary=yu,xr.assign=ca,xr.assignIn=la,xr.assignInWith=fa,xr.assignWith=sa,xr.at=pa,xr.before=gu,xr.bind=mu,xr.bindAll=za,xr.bindKey=Du,xr.castArray=function(){if(!arguments.length)return[];var t=arguments[0];return Pu(t)?t:[t]},xr.chain=eu,xr.chunk=function(t,e,r){e=(r?ci(t,e,r):void 0===e)?1:ir(na(e),0);var o=null==t?0:t.length;if(!o||e<1)return[];for(var i=0,u=0,a=n(Ye(o/e));io?0:o+r),(n=void 0===n||n>o?o:na(n))<0&&(n+=o),n=r>n?0:oa(n);r>>0)?(t=aa(t))&&("string"==typeof e||null!=e&&!Qu(e))&&!(e=Kn(e))&&Me(t)?lo(Ve(t),0,r):t.split(e,r):[]},xr.spread=function(t,e){if("function"!=typeof t)throw new mt(i);return e=null==e?0:ir(na(e),0),Tn((function(r){var n=r[e],o=lo(r,0,e);return n&&de(o,n),ie(t,this,o)}))},xr.tail=function(t){var e=null==t?0:t.length;return e?Gn(t,1,e):[]},xr.take=function(t,e,r){return t&&t.length?Gn(t,0,(e=r||void 0===e?1:na(e))<0?0:e):[]},xr.takeRight=function(t,e,r){var n=null==t?0:t.length;return n?Gn(t,(e=n-(e=r||void 0===e?1:na(e)))<0?0:e,n):[]},xr.takeRightWhile=function(t,e){return t&&t.length?eo(t,Ko(e,3),!1,!0):[]},xr.takeWhile=function(t,e){return t&&t.length?eo(t,Ko(e,3)):[]},xr.tap=function(t,e){return e(t),t},xr.throttle=function(t,e,r){var n=!0,o=!0;if("function"!=typeof t)throw new mt(i);return $u(r)&&(n="leading"in r?!!r.leading:n,o="trailing"in r?!!r.trailing:o),_u(t,e,{leading:n,maxWait:e,trailing:o})},xr.thru=ru,xr.toArray=ea,xr.toPairs=xa,xr.toPairsIn=Oa,xr.toPath=function(t){return Pu(t)?ve(t,Ai):Ku(t)?[t]:mo(ji(aa(t)))},xr.toPlainObject=ua,xr.transform=function(t,e,r){var n=Pu(t),o=n||Lu(t)||Yu(t);if(e=Ko(e,4),null==r){var i=t&&t.constructor;r=o?n?new i:[]:$u(t)&&Wu(i)?Or(Gt(t)):{}}return(o?ae:cn)(t,(function(t,n,o){return e(r,t,n,o)})),r},xr.unary=function(t){return yu(t,1)},xr.union=qi,xr.unionBy=Gi,xr.unionWith=Vi,xr.uniq=function(t){return t&&t.length?Yn(t):[]},xr.uniqBy=function(t,e){return t&&t.length?Yn(t,Ko(e,2)):[]},xr.uniqWith=function(t,e){return e="function"==typeof e?e:void 0,t&&t.length?Yn(t,void 0,e):[]},xr.unset=function(t,e){return null==t||Xn(t,e)},xr.unzip=Hi,xr.unzipWith=Qi,xr.update=function(t,e,r){return null==t?t:to(t,e,uo(r))},xr.updateWith=function(t,e,r,n){return n="function"==typeof n?n:void 0,null==t?t:to(t,e,uo(r),n)},xr.values=Sa,xr.valuesIn=function(t){return null==t?[]:Ce(t,ba(t))},xr.without=Ji,xr.words=Wa,xr.wrap=function(t,e){return Au(uo(e),t)},xr.xor=Zi,xr.xorBy=Ki,xr.xorWith=Yi,xr.zip=Xi,xr.zipObject=function(t,e){return oo(t||[],e||[],zr)},xr.zipObjectDeep=function(t,e){return oo(t||[],e||[],Un)},xr.zipWith=tu,xr.entries=xa,xr.entriesIn=Oa,xr.extend=la,xr.extendWith=fa,Za(xr,xr),xr.add=uc,xr.attempt=Ua,xr.camelCase=ka,xr.capitalize=Ca,xr.ceil=ac,xr.clamp=function(t,e,r){return void 0===r&&(r=e,e=void 0),void 0!==r&&(r=(r=ia(r))==r?r:0),void 0!==e&&(e=(e=ia(e))==e?e:0),Qr(ia(t),e,r)},xr.clone=function(t){return Jr(t,4)},xr.cloneDeep=function(t){return Jr(t,5)},xr.cloneDeepWith=function(t,e){return Jr(t,5,e="function"==typeof e?e:void 0)},xr.cloneWith=function(t,e){return Jr(t,4,e="function"==typeof e?e:void 0)},xr.conformsTo=function(t,e){return null==e||Zr(t,e,_a(e))},xr.deburr=Na,xr.defaultTo=function(t,e){return null==t||t!=t?e:t},xr.divide=cc,xr.endsWith=function(t,e,r){t=aa(t),e=Kn(e);var n=t.length,o=r=void 0===r?n:Qr(na(r),0,n);return(r-=e.length)>=0&&t.slice(r,o)==e},xr.eq=Su,xr.escape=function(t){return(t=aa(t))&&M.test(t)?t.replace(L,Le):t},xr.escapeRegExp=function(t){return(t=aa(t))&&H.test(t)?t.replace(V,"\\$&"):t},xr.every=function(t,e,r){var n=Pu(t)?le:en;return r&&ci(t,e,r)&&(e=void 0),n(t,Ko(e,3))},xr.find=iu,xr.findIndex=Ni,xr.findKey=function(t,e){return De(t,Ko(e,3),cn)},xr.findLast=uu,xr.findLastIndex=Pi,xr.findLastKey=function(t,e){return De(t,Ko(e,3),ln)},xr.floor=lc,xr.forEach=au,xr.forEachRight=cu,xr.forIn=function(t,e){return null==t?t:un(t,Ko(e,3),ba)},xr.forInRight=function(t,e){return null==t?t:an(t,Ko(e,3),ba)},xr.forOwn=function(t,e){return t&&cn(t,Ko(e,3))},xr.forOwnRight=function(t,e){return t&&ln(t,Ko(e,3))},xr.get=ha,xr.gt=ku,xr.gte=Cu,xr.has=function(t,e){return null!=t&&oi(t,e,hn)},xr.hasIn=ya,xr.head=Ri,xr.identity=Va,xr.includes=function(t,e,r,n){t=Ru(t)?t:Sa(t),r=r&&!n?na(r):0;var o=t.length;return r<0&&(r=ir(o+r,0)),Zu(t)?r<=o&&t.indexOf(e,r)>-1:!!o&&be(t,e,r)>-1},xr.indexOf=function(t,e,r){var n=null==t?0:t.length;if(!n)return-1;var o=null==r?0:na(r);return o<0&&(o=ir(n+o,0)),be(t,e,o)},xr.inRange=function(t,e,r){return e=ra(e),void 0===r?(r=e,e=0):r=ra(r),function(t,e,r){return t>=ur(e,r)&&t=-9007199254740991&&t<=9007199254740991},xr.isSet=Ju,xr.isString=Zu,xr.isSymbol=Ku,xr.isTypedArray=Yu,xr.isUndefined=function(t){return void 0===t},xr.isWeakMap=function(t){return qu(t)&&ni(t)==E},xr.isWeakSet=function(t){return qu(t)&&"[object WeakSet]"==vn(t)},xr.join=function(t,e){return null==t?"":nr.call(t,e)},xr.kebabCase=Pa,xr.last=Mi,xr.lastIndexOf=function(t,e,r){var n=null==t?0:t.length;if(!n)return-1;var o=n;return void 0!==r&&(o=(o=na(r))<0?ir(n+o,0):ur(o,n-1)),e==e?function(t,e,r){for(var n=r+1;n--;)if(t[n]===e)return n;return n}(t,e,o):_e(t,we,o,!0)},xr.lowerCase=Ia,xr.lowerFirst=Ra,xr.lt=Xu,xr.lte=ta,xr.max=function(t){return t&&t.length?rn(t,Va,dn):void 0},xr.maxBy=function(t,e){return t&&t.length?rn(t,Ko(e,2),dn):void 0},xr.mean=function(t){return Fe(t,Va)},xr.meanBy=function(t,e){return Fe(t,Ko(e,2))},xr.min=function(t){return t&&t.length?rn(t,Va,An):void 0},xr.minBy=function(t,e){return t&&t.length?rn(t,Ko(e,2),An):void 0},xr.stubArray=oc,xr.stubFalse=ic,xr.stubObject=function(){return{}},xr.stubString=function(){return""},xr.stubTrue=function(){return!0},xr.multiply=sc,xr.nth=function(t,e){return t&&t.length?Cn(t,na(e)):void 0},xr.noConflict=function(){return Ht._===this&&(Ht._=St),this},xr.noop=Ka,xr.now=hu,xr.pad=function(t,e,r){t=aa(t);var n=(e=na(e))?Ge(t):0;if(!e||n>=e)return t;var o=(e-n)/2;return Po(Xe(o),r)+t+Po(Ye(o),r)},xr.padEnd=function(t,e,r){t=aa(t);var n=(e=na(e))?Ge(t):0;return e&&ne){var n=t;t=e,e=n}if(r||t%1||e%1){var o=lr();return ur(t+o*(e-t+$t("1e-"+((o+"").length-1))),e)}return Bn(t,e)},xr.reduce=function(t,e,r){var n=Pu(t)?he:xe,o=arguments.length<3;return n(t,Ko(e,4),r,o,Xr)},xr.reduceRight=function(t,e,r){var n=Pu(t)?ye:xe,o=arguments.length<3;return n(t,Ko(e,4),r,o,tn)},xr.repeat=function(t,e,r){return e=(r?ci(t,e,r):void 0===e)?1:na(e),Ln(aa(t),e)},xr.replace=function(){var t=arguments,e=aa(t[0]);return t.length<3?e:e.replace(t[1],t[2])},xr.result=function(t,e,r){var n=-1,o=(e=ao(e,t)).length;for(o||(o=1,t=void 0);++n9007199254740991)return[];var r=4294967295,n=ur(t,4294967295);t-=4294967295;for(var o=Se(n,e=Ko(e));++r=i)return t;var a=r-Ge(n);if(a<1)return n;var c=u?lo(u,0,a).join(""):t.slice(0,a);if(void 0===o)return c+n;if(u&&(a+=c.length-a),Qu(o)){if(t.slice(a).search(o)){var l,f=c;for(o.global||(o=yt(o.source,aa(nt.exec(o))+"g")),o.lastIndex=0;l=o.exec(f);)var s=l.index;c=c.slice(0,void 0===s?a:s)}}else if(t.indexOf(Kn(o),a)!=a){var p=c.lastIndexOf(o);p>-1&&(c=c.slice(0,p))}return c+n},xr.unescape=function(t){return(t=aa(t))&&T.test(t)?t.replace(B,He):t},xr.uniqueId=function(t){var e=++jt;return aa(t)+e},xr.upperCase=Ta,xr.upperFirst=Ma,xr.each=au,xr.eachRight=cu,xr.first=Ri,Za(xr,(fc={},cn(xr,(function(t,e){Ft.call(xr.prototype,e)||(fc[e]=t)})),fc),{chain:!1}),xr.VERSION="4.17.15",ae(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(t){xr[t].placeholder=xr})),ae(["drop","take"],(function(t,e){Cr.prototype[t]=function(r){r=void 0===r?1:ir(na(r),0);var n=this.__filtered__&&!e?new Cr(this):this.clone();return n.__filtered__?n.__takeCount__=ur(r,n.__takeCount__):n.__views__.push({size:ur(r,4294967295),type:t+(n.__dir__<0?"Right":"")}),n},Cr.prototype[t+"Right"]=function(e){return this.reverse()[t](e).reverse()}})),ae(["filter","map","takeWhile"],(function(t,e){var r=e+1,n=1==r||3==r;Cr.prototype[t]=function(t){var e=this.clone();return e.__iteratees__.push({iteratee:Ko(t,3),type:r}),e.__filtered__=e.__filtered__||n,e}})),ae(["head","last"],(function(t,e){var r="take"+(e?"Right":"");Cr.prototype[t]=function(){return this[r](1).value()[0]}})),ae(["initial","tail"],(function(t,e){var r="drop"+(e?"":"Right");Cr.prototype[t]=function(){return this.__filtered__?new Cr(this):this[r](1)}})),Cr.prototype.compact=function(){return this.filter(Va)},Cr.prototype.find=function(t){return this.filter(t).head()},Cr.prototype.findLast=function(t){return this.reverse().find(t)},Cr.prototype.invokeMap=Tn((function(t,e){return"function"==typeof t?new Cr(this):this.map((function(r){return mn(r,t,e)}))})),Cr.prototype.reject=function(t){return this.filter(Fu(Ko(t)))},Cr.prototype.slice=function(t,e){t=na(t);var r=this;return r.__filtered__&&(t>0||e<0)?new Cr(r):(t<0?r=r.takeRight(-t):t&&(r=r.drop(t)),void 0!==e&&(r=(e=na(e))<0?r.dropRight(-e):r.take(e-t)),r)},Cr.prototype.takeRightWhile=function(t){return this.reverse().takeWhile(t).reverse()},Cr.prototype.toArray=function(){return this.take(4294967295)},cn(Cr.prototype,(function(t,e){var r=/^(?:filter|find|map|reject)|While$/.test(e),n=/^(?:head|last)$/.test(e),o=xr[n?"take"+("last"==e?"Right":""):e],i=n||/^find/.test(e);o&&(xr.prototype[e]=function(){var e=this.__wrapped__,u=n?[1]:arguments,a=e instanceof Cr,c=u[0],l=a||Pu(e),f=function(t){var e=o.apply(xr,de([t],u));return n&&s?e[0]:e};l&&r&&"function"==typeof c&&1!=c.length&&(a=l=!1);var s=this.__chain__,p=!!this.__actions__.length,v=i&&!s,d=a&&!p;if(!i&&l){e=d?e:new Cr(this);var h=t.apply(e,u);return h.__actions__.push({func:ru,args:[f],thisArg:void 0}),new kr(h,s)}return v&&d?t.apply(this,u):(h=this.thru(f),v?n?h.value()[0]:h.value():h)})})),ae(["pop","push","shift","sort","splice","unshift"],(function(t){var e=Dt[t],r=/^(?:push|sort|unshift)$/.test(t)?"tap":"thru",n=/^(?:pop|shift)$/.test(t);xr.prototype[t]=function(){var t=arguments;if(n&&!this.__chain__){var o=this.value();return e.apply(Pu(o)?o:[],t)}return this[r]((function(r){return e.apply(Pu(r)?r:[],t)}))}})),cn(Cr.prototype,(function(t,e){var r=xr[e];if(r){var n=r.name+"";Ft.call(mr,n)||(mr[n]=[]),mr[n].push({name:e,func:r})}})),mr[So(void 0,2).name]=[{name:"wrapper",func:void 0}],Cr.prototype.clone=function(){var t=new Cr(this.__wrapped__);return t.__actions__=mo(this.__actions__),t.__dir__=this.__dir__,t.__filtered__=this.__filtered__,t.__iteratees__=mo(this.__iteratees__),t.__takeCount__=this.__takeCount__,t.__views__=mo(this.__views__),t},Cr.prototype.reverse=function(){if(this.__filtered__){var t=new Cr(this);t.__dir__=-1,t.__filtered__=!0}else(t=this.clone()).__dir__*=-1;return t},Cr.prototype.value=function(){var t=this.__wrapped__.value(),e=this.__dir__,r=Pu(t),n=e<0,o=r?t.length:0,i=function(t,e,r){var n=-1,o=r.length;for(;++n=this.__values__.length;return{done:t,value:t?void 0:this.__values__[this.__index__++]}},xr.prototype.plant=function(t){for(var e,r=this;r instanceof Sr;){var n=Oi(r);n.__index__=0,n.__values__=void 0,e?o.__wrapped__=n:e=n;var o=n;r=r.__wrapped__}return o.__wrapped__=t,e},xr.prototype.reverse=function(){var t=this.__wrapped__;if(t instanceof Cr){var e=t;return this.__actions__.length&&(e=new Cr(this)),(e=e.reverse()).__actions__.push({func:ru,args:[$i],thisArg:void 0}),new kr(e,this.__chain__)}return this.thru($i)},xr.prototype.toJSON=xr.prototype.valueOf=xr.prototype.value=function(){return ro(this.__wrapped__,this.__actions__)},xr.prototype.first=xr.prototype.head,Yt&&(xr.prototype[Yt]=function(){return this}),xr}();Ht._=Qe,void 0===(o=function(){return Qe}.call(e,r,e,n))||(n.exports=o)}).call(this)}).call(this,r(76),r(453)(t))},451:function(t,e,r){"use strict";var n=r(0),o=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});e.a=o},452:function(t,e,r){"use strict";r.d(e,"a",(function(){return i}));r(77),r(470),r(436),r(78);var n=r(472),o=r.n(n);function i(t,e){var r=new o.a;return t.map((function(t){var n=t;return"string"==typeof t&&(n={label:t,permalink:"/blog/tags/"+r.slug(t)}),function(t,e){var r=t.label.split(": ",2),n=r[0],o=r[1],i="primary";switch(e){case"blog":case"guides":i=function(t){switch(t){case"domain":return"blue";case"type":return"pink";default:return"primary"}}(n)}return{category:n,count:t.count,label:t.label,permalink:t.permalink,style:i,value:o}}(n,e)}))}},453:function(t,e){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},462:function(t,e,r){var n=r(30),o=r(54),i=r(27),u=r(26),a=r(463);t.exports=function(t,e){var r=1==t,c=2==t,l=3==t,f=4==t,s=6==t,p=5==t||s,v=e||a;return function(e,a,d){for(var h,y,g=i(e),m=o(g),D=n(a,d,3),_=u(m.length),b=0,E=r?v(e,_):c?v(e,0):void 0;_>b;b++)if((p||b in m)&&(y=D(h=m[b],b,g),t))if(r)E[b]=y;else if(y)switch(t){case 3:return!0;case 5:return h;case 6:return b;case 2:E.push(h)}else if(f)return!1;return s?-1:l||f?f:E}}},463:function(t,e,r){var n=r(464);t.exports=function(t,e){return new(n(t))(e)}},464:function(t,e,r){var n=r(13),o=r(465),i=r(2)("species");t.exports=function(t){var e;return o(t)&&("function"!=typeof(e=t.constructor)||e!==Array&&!o(e.prototype)||(e=void 0),n(e)&&null===(e=e[i])&&(e=void 0)),void 0===e?Array:e}},465:function(t,e,r){var n=r(23);t.exports=Array.isArray||function(t){return"Array"==n(t)}},466:function(t,e,r){"use strict";var n=SyntaxError,o=Function,i=TypeError,u=function(t){try{return o('"use strict"; return ('+t+").constructor;")()}catch(e){}},a=Object.getOwnPropertyDescriptor;if(a)try{a({},"")}catch(x){a=null}var c=function(){throw new i},l=a?function(){try{return c}catch(t){try{return a(arguments,"callee").get}catch(e){return c}}}():c,f=r(504)(),s=Object.getPrototypeOf||function(t){return t.__proto__},p={},v="undefined"==typeof Uint8Array?void 0:s(Uint8Array),d={"%AggregateError%":"undefined"==typeof AggregateError?void 0:AggregateError,"%Array%":Array,"%ArrayBuffer%":"undefined"==typeof ArrayBuffer?void 0:ArrayBuffer,"%ArrayIteratorPrototype%":f?s([][Symbol.iterator]()):void 0,"%AsyncFromSyncIteratorPrototype%":void 0,"%AsyncFunction%":p,"%AsyncGenerator%":p,"%AsyncGeneratorFunction%":p,"%AsyncIteratorPrototype%":p,"%Atomics%":"undefined"==typeof Atomics?void 0:Atomics,"%BigInt%":"undefined"==typeof BigInt?void 0:BigInt,"%Boolean%":Boolean,"%DataView%":"undefined"==typeof DataView?void 0:DataView,"%Date%":Date,"%decodeURI%":decodeURI,"%decodeURIComponent%":decodeURIComponent,"%encodeURI%":encodeURI,"%encodeURIComponent%":encodeURIComponent,"%Error%":Error,"%eval%":eval,"%EvalError%":EvalError,"%Float32Array%":"undefined"==typeof Float32Array?void 0:Float32Array,"%Float64Array%":"undefined"==typeof Float64Array?void 0:Float64Array,"%FinalizationRegistry%":"undefined"==typeof FinalizationRegistry?void 0:FinalizationRegistry,"%Function%":o,"%GeneratorFunction%":p,"%Int8Array%":"undefined"==typeof Int8Array?void 0:Int8Array,"%Int16Array%":"undefined"==typeof Int16Array?void 0:Int16Array,"%Int32Array%":"undefined"==typeof Int32Array?void 0:Int32Array,"%isFinite%":isFinite,"%isNaN%":isNaN,"%IteratorPrototype%":f?s(s([][Symbol.iterator]())):void 0,"%JSON%":"object"==typeof JSON?JSON:void 0,"%Map%":"undefined"==typeof Map?void 0:Map,"%MapIteratorPrototype%":"undefined"!=typeof Map&&f?s((new Map)[Symbol.iterator]()):void 0,"%Math%":Math,"%Number%":Number,"%Object%":Object,"%parseFloat%":parseFloat,"%parseInt%":parseInt,"%Promise%":"undefined"==typeof Promise?void 0:Promise,"%Proxy%":"undefined"==typeof Proxy?void 0:Proxy,"%RangeError%":RangeError,"%ReferenceError%":ReferenceError,"%Reflect%":"undefined"==typeof Reflect?void 0:Reflect,"%RegExp%":RegExp,"%Set%":"undefined"==typeof Set?void 0:Set,"%SetIteratorPrototype%":"undefined"!=typeof Set&&f?s((new Set)[Symbol.iterator]()):void 0,"%SharedArrayBuffer%":"undefined"==typeof SharedArrayBuffer?void 0:SharedArrayBuffer,"%String%":String,"%StringIteratorPrototype%":f?s(""[Symbol.iterator]()):void 0,"%Symbol%":f?Symbol:void 0,"%SyntaxError%":n,"%ThrowTypeError%":l,"%TypedArray%":v,"%TypeError%":i,"%Uint8Array%":"undefined"==typeof Uint8Array?void 0:Uint8Array,"%Uint8ClampedArray%":"undefined"==typeof Uint8ClampedArray?void 0:Uint8ClampedArray,"%Uint16Array%":"undefined"==typeof Uint16Array?void 0:Uint16Array,"%Uint32Array%":"undefined"==typeof Uint32Array?void 0:Uint32Array,"%URIError%":URIError,"%WeakMap%":"undefined"==typeof WeakMap?void 0:WeakMap,"%WeakRef%":"undefined"==typeof WeakRef?void 0:WeakRef,"%WeakSet%":"undefined"==typeof WeakSet?void 0:WeakSet},h={"%ArrayBufferPrototype%":["ArrayBuffer","prototype"],"%ArrayPrototype%":["Array","prototype"],"%ArrayProto_entries%":["Array","prototype","entries"],"%ArrayProto_forEach%":["Array","prototype","forEach"],"%ArrayProto_keys%":["Array","prototype","keys"],"%ArrayProto_values%":["Array","prototype","values"],"%AsyncFunctionPrototype%":["AsyncFunction","prototype"],"%AsyncGenerator%":["AsyncGeneratorFunction","prototype"],"%AsyncGeneratorPrototype%":["AsyncGeneratorFunction","prototype","prototype"],"%BooleanPrototype%":["Boolean","prototype"],"%DataViewPrototype%":["DataView","prototype"],"%DatePrototype%":["Date","prototype"],"%ErrorPrototype%":["Error","prototype"],"%EvalErrorPrototype%":["EvalError","prototype"],"%Float32ArrayPrototype%":["Float32Array","prototype"],"%Float64ArrayPrototype%":["Float64Array","prototype"],"%FunctionPrototype%":["Function","prototype"],"%Generator%":["GeneratorFunction","prototype"],"%GeneratorPrototype%":["GeneratorFunction","prototype","prototype"],"%Int8ArrayPrototype%":["Int8Array","prototype"],"%Int16ArrayPrototype%":["Int16Array","prototype"],"%Int32ArrayPrototype%":["Int32Array","prototype"],"%JSONParse%":["JSON","parse"],"%JSONStringify%":["JSON","stringify"],"%MapPrototype%":["Map","prototype"],"%NumberPrototype%":["Number","prototype"],"%ObjectPrototype%":["Object","prototype"],"%ObjProto_toString%":["Object","prototype","toString"],"%ObjProto_valueOf%":["Object","prototype","valueOf"],"%PromisePrototype%":["Promise","prototype"],"%PromiseProto_then%":["Promise","prototype","then"],"%Promise_all%":["Promise","all"],"%Promise_reject%":["Promise","reject"],"%Promise_resolve%":["Promise","resolve"],"%RangeErrorPrototype%":["RangeError","prototype"],"%ReferenceErrorPrototype%":["ReferenceError","prototype"],"%RegExpPrototype%":["RegExp","prototype"],"%SetPrototype%":["Set","prototype"],"%SharedArrayBufferPrototype%":["SharedArrayBuffer","prototype"],"%StringPrototype%":["String","prototype"],"%SymbolPrototype%":["Symbol","prototype"],"%SyntaxErrorPrototype%":["SyntaxError","prototype"],"%TypedArrayPrototype%":["TypedArray","prototype"],"%TypeErrorPrototype%":["TypeError","prototype"],"%Uint8ArrayPrototype%":["Uint8Array","prototype"],"%Uint8ClampedArrayPrototype%":["Uint8ClampedArray","prototype"],"%Uint16ArrayPrototype%":["Uint16Array","prototype"],"%Uint32ArrayPrototype%":["Uint32Array","prototype"],"%URIErrorPrototype%":["URIError","prototype"],"%WeakMapPrototype%":["WeakMap","prototype"],"%WeakSetPrototype%":["WeakSet","prototype"]},y=r(467),g=r(507),m=y.call(Function.call,Array.prototype.concat),D=y.call(Function.apply,Array.prototype.splice),_=y.call(Function.call,String.prototype.replace),b=y.call(Function.call,String.prototype.slice),E=y.call(Function.call,RegExp.prototype.exec),w=/[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g,F=/\\(\\)?/g,j=function(t){var e=b(t,0,1),r=b(t,-1);if("%"===e&&"%"!==r)throw new n("invalid intrinsic syntax, expected closing `%`");if("%"===r&&"%"!==e)throw new n("invalid intrinsic syntax, expected opening `%`");var o=[];return _(t,w,(function(t,e,r,n){o[o.length]=r?_(n,F,"$1"):e||t})),o},A=function(t,e){var r,o=t;if(g(h,o)&&(o="%"+(r=h[o])[0]+"%"),g(d,o)){var a=d[o];if(a===p&&(a=function t(e){var r;if("%AsyncFunction%"===e)r=u("async function () {}");else if("%GeneratorFunction%"===e)r=u("function* () {}");else if("%AsyncGeneratorFunction%"===e)r=u("async function* () {}");else if("%AsyncGenerator%"===e){var n=t("%AsyncGeneratorFunction%");n&&(r=n.prototype)}else if("%AsyncIteratorPrototype%"===e){var o=t("%AsyncGenerator%");o&&(r=s(o.prototype))}return d[e]=r,r}(o)),void 0===a&&!e)throw new i("intrinsic "+t+" exists, but is not available. Please file an issue!");return{alias:r,name:o,value:a}}throw new n("intrinsic "+t+" does not exist!")};t.exports=function(t,e){if("string"!=typeof t||0===t.length)throw new i("intrinsic name must be a non-empty string");if(arguments.length>1&&"boolean"!=typeof e)throw new i('"allowMissing" argument must be a boolean');if(null===E(/^%?[^%]*%?$/,t))throw new n("`%` may not be present anywhere but at the beginning and end of the intrinsic name");var r=j(t),o=r.length>0?r[0]:"",u=A("%"+o+"%",e),c=u.name,l=u.value,f=!1,s=u.alias;s&&(o=s[0],D(r,m([0,1],s)));for(var p=1,v=!0;p=r.length){var w=a(l,h);l=(v=!!w)&&"get"in w&&!("originalValue"in w.get)?w.get:l[h]}else v=g(l,h),l=l[h];v&&!f&&(d[c]=l)}}return l}},467:function(t,e,r){"use strict";var n=r(506);t.exports=Function.prototype.bind||n},468:function(t,e,r){"use strict";var n=String.prototype.replace,o=/%20/g,i="RFC1738",u="RFC3986";t.exports={default:u,formatters:{RFC1738:function(t){return n.call(t,o,"+")},RFC3986:function(t){return String(t)}},RFC1738:i,RFC3986:u}},471:function(t,e,r){"use strict";var n=r(0),o=r.n(n),i=r(427),u=r(420),a=r.n(u);e.a=function(t){var e=t.count,r=t.label,n=t.permalink,u=t.style,c=t.value,l=t.valueOnly;return o.a.createElement(i.a,{to:n+"/",className:a()("badge","badge--rounded","badge--"+u)},l?c:r,e&&o.a.createElement(o.a.Fragment,null," (",e,")"))}},472:function(t,e,r){var n=r(473);t.exports=a;var o=Object.hasOwnProperty,i=/\s/g,u=/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~\u2019]/g;function a(){if(!(this instanceof a))return new a;this.reset()}function c(t,e){return"string"!=typeof t?"":(e||(t=t.toLowerCase()),t.trim().replace(u,"").replace(n(),"").replace(i,"-"))}a.prototype.slug=function(t,e){for(var r=c(t,!0===e),n=r;o.call(this.occurrences,r);)this.occurrences[n]++,r=n+"-"+this.occurrences[n];return this.occurrences[r]=0,r},a.prototype.reset=function(){this.occurrences=Object.create(null)},a.slug=c},473:function(t,e){t.exports=function(){return/[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD79\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED0\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3]|\uD83E[\uDD10-\uDD18\uDD80-\uDD84\uDDC0]|\uD83C\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uD83C\uDDFE\uD83C[\uDDEA\uDDF9]|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDFC\uD83C[\uDDEB\uDDF8]|\uD83C\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uD83C\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF8\uDDFE\uDDFF]|\uD83C\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uD83C\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uD83C\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uD83C\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uD83C\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uD83C\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uD83C\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uD83C\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uD83C\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uD83C\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uD83C\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uD83C\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uD83C\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uD83C\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uD83C\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uD83C\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|[#\*0-9]\u20E3/g}},475:function(t,e,r){"use strict";var n=r(468),o=Object.prototype.hasOwnProperty,i=Array.isArray,u=function(){for(var t=[],e=0;e<256;++e)t.push("%"+((e<16?"0":"")+e.toString(16)).toUpperCase());return t}(),a=function(t,e){for(var r=e&&e.plainObjects?Object.create(null):{},n=0;n1;){var e=t.pop(),r=e.obj[e.prop];if(i(r)){for(var n=[],o=0;o=48&&f<=57||f>=65&&f<=90||f>=97&&f<=122||i===n.RFC1738&&(40===f||41===f)?c+=a.charAt(l):f<128?c+=u[f]:f<2048?c+=u[192|f>>6]+u[128|63&f]:f<55296||f>=57344?c+=u[224|f>>12]+u[128|f>>6&63]+u[128|63&f]:(l+=1,f=65536+((1023&f)<<10|1023&a.charCodeAt(l)),c+=u[240|f>>18]+u[128|f>>12&63]+u[128|f>>6&63]+u[128|63&f])}return c},isBuffer:function(t){return!(!t||"object"!=typeof t)&&!!(t.constructor&&t.constructor.isBuffer&&t.constructor.isBuffer(t))},isRegExp:function(t){return"[object RegExp]"===Object.prototype.toString.call(t)},maybeMap:function(t,e){if(i(t)){for(var r=[],n=0;n0?j.join(",")||null:void 0}];else if(c(v))I=v;else{var B=Object.keys(j);I=y?B.sort(y):B}for(var L=u&&c(j)&&1===j.length?r+"[]":r,T=0;T0?b+_:""}},503:function(t,e,r){"use strict";var n=r(466),o=r(508),i=r(510),u=n("%TypeError%"),a=n("%WeakMap%",!0),c=n("%Map%",!0),l=o("WeakMap.prototype.get",!0),f=o("WeakMap.prototype.set",!0),s=o("WeakMap.prototype.has",!0),p=o("Map.prototype.get",!0),v=o("Map.prototype.set",!0),d=o("Map.prototype.has",!0),h=function(t,e){for(var r,n=t;null!==(r=n.next);n=r)if(r.key===e)return n.next=r.next,r.next=t.next,t.next=r,r};t.exports=function(){var t,e,r,n={assert:function(t){if(!n.has(t))throw new u("Side channel does not contain "+i(t))},get:function(n){if(a&&n&&("object"==typeof n||"function"==typeof n)){if(t)return l(t,n)}else if(c){if(e)return p(e,n)}else if(r)return function(t,e){var r=h(t,e);return r&&r.value}(r,n)},has:function(n){if(a&&n&&("object"==typeof n||"function"==typeof n)){if(t)return s(t,n)}else if(c){if(e)return d(e,n)}else if(r)return function(t,e){return!!h(t,e)}(r,n);return!1},set:function(n,o){a&&n&&("object"==typeof n||"function"==typeof n)?(t||(t=new a),f(t,n,o)):c?(e||(e=new c),v(e,n,o)):(r||(r={key:{},next:null}),function(t,e,r){var n=h(t,e);n?n.value=r:t.next={key:e,next:t.next,value:r}}(r,n,o))}};return n}},504:function(t,e,r){"use strict";var n="undefined"!=typeof Symbol&&Symbol,o=r(505);t.exports=function(){return"function"==typeof n&&("function"==typeof Symbol&&("symbol"==typeof n("foo")&&("symbol"==typeof Symbol("bar")&&o())))}},505:function(t,e,r){"use strict";t.exports=function(){if("function"!=typeof Symbol||"function"!=typeof Object.getOwnPropertySymbols)return!1;if("symbol"==typeof Symbol.iterator)return!0;var t={},e=Symbol("test"),r=Object(e);if("string"==typeof e)return!1;if("[object Symbol]"!==Object.prototype.toString.call(e))return!1;if("[object Symbol]"!==Object.prototype.toString.call(r))return!1;for(e in t[e]=42,t)return!1;if("function"==typeof Object.keys&&0!==Object.keys(t).length)return!1;if("function"==typeof Object.getOwnPropertyNames&&0!==Object.getOwnPropertyNames(t).length)return!1;var n=Object.getOwnPropertySymbols(t);if(1!==n.length||n[0]!==e)return!1;if(!Object.prototype.propertyIsEnumerable.call(t,e))return!1;if("function"==typeof Object.getOwnPropertyDescriptor){var o=Object.getOwnPropertyDescriptor(t,e);if(42!==o.value||!0!==o.enumerable)return!1}return!0}},506:function(t,e,r){"use strict";var n="Function.prototype.bind called on incompatible ",o=Array.prototype.slice,i=Object.prototype.toString;t.exports=function(t){var e=this;if("function"!=typeof e||"[object Function]"!==i.call(e))throw new TypeError(n+e);for(var r,u=o.call(arguments,1),a=function(){if(this instanceof r){var n=e.apply(this,u.concat(o.call(arguments)));return Object(n)===n?n:this}return e.apply(t,u.concat(o.call(arguments)))},c=Math.max(0,e.length-u.length),l=[],f=0;f-1?o(r):r}},509:function(t,e,r){"use strict";var n=r(467),o=r(466),i=o("%Function.prototype.apply%"),u=o("%Function.prototype.call%"),a=o("%Reflect.apply%",!0)||n.call(u,i),c=o("%Object.getOwnPropertyDescriptor%",!0),l=o("%Object.defineProperty%",!0),f=o("%Math.max%");if(l)try{l({},"a",{value:1})}catch(p){l=null}t.exports=function(t){var e=a(n,u,arguments);if(c&&l){var r=c(e,"length");r.configurable&&l(e,"length",{value:1+f(0,t.length-(arguments.length-1))})}return e};var s=function(){return a(n,i,arguments)};l?l(t.exports,"apply",{value:s}):t.exports.apply=s},510:function(t,e,r){var n="function"==typeof Map&&Map.prototype,o=Object.getOwnPropertyDescriptor&&n?Object.getOwnPropertyDescriptor(Map.prototype,"size"):null,i=n&&o&&"function"==typeof o.get?o.get:null,u=n&&Map.prototype.forEach,a="function"==typeof Set&&Set.prototype,c=Object.getOwnPropertyDescriptor&&a?Object.getOwnPropertyDescriptor(Set.prototype,"size"):null,l=a&&c&&"function"==typeof c.get?c.get:null,f=a&&Set.prototype.forEach,s="function"==typeof WeakMap&&WeakMap.prototype?WeakMap.prototype.has:null,p="function"==typeof WeakSet&&WeakSet.prototype?WeakSet.prototype.has:null,v="function"==typeof WeakRef&&WeakRef.prototype?WeakRef.prototype.deref:null,d=Boolean.prototype.valueOf,h=Object.prototype.toString,y=Function.prototype.toString,g=String.prototype.match,m=String.prototype.slice,D=String.prototype.replace,_=String.prototype.toUpperCase,b=String.prototype.toLowerCase,E=RegExp.prototype.test,w=Array.prototype.concat,F=Array.prototype.join,j=Array.prototype.slice,A=Math.floor,x="function"==typeof BigInt?BigInt.prototype.valueOf:null,O=Object.getOwnPropertySymbols,S="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?Symbol.prototype.toString:null,k="function"==typeof Symbol&&"object"==typeof Symbol.iterator,C="function"==typeof Symbol&&Symbol.toStringTag&&(typeof Symbol.toStringTag===k||"symbol")?Symbol.toStringTag:null,N=Object.prototype.propertyIsEnumerable,P=("function"==typeof Reflect?Reflect.getPrototypeOf:Object.getPrototypeOf)||([].__proto__===Array.prototype?function(t){return t.__proto__}:null);function I(t,e){if(t===1/0||t===-1/0||t!=t||t&&t>-1e3&&t<1e3||E.call(/e/,e))return e;var r=/[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;if("number"==typeof t){var n=t<0?-A(-t):A(t);if(n!==t){var o=String(n),i=m.call(e,o.length+1);return D.call(o,r,"$&_")+"."+D.call(D.call(i,/([0-9]{3})/g,"$&_"),/_$/,"")}}return D.call(e,r,"$&_")}var R=r(511),B=R.custom,L=z(B)?B:null;function T(t,e,r){var n="double"===(r.quoteStyle||e)?'"':"'";return n+t+n}function M(t){return D.call(String(t),/"/g,""")}function W(t){return!("[object Array]"!==G(t)||C&&"object"==typeof t&&C in t)}function U(t){return!("[object RegExp]"!==G(t)||C&&"object"==typeof t&&C in t)}function z(t){if(k)return t&&"object"==typeof t&&t instanceof Symbol;if("symbol"==typeof t)return!0;if(!t||"object"!=typeof t||!S)return!1;try{return S.call(t),!0}catch(e){}return!1}t.exports=function t(e,r,n,o){var a=r||{};if(q(a,"quoteStyle")&&"single"!==a.quoteStyle&&"double"!==a.quoteStyle)throw new TypeError('option "quoteStyle" must be "single" or "double"');if(q(a,"maxStringLength")&&("number"==typeof a.maxStringLength?a.maxStringLength<0&&a.maxStringLength!==1/0:null!==a.maxStringLength))throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`');var c=!q(a,"customInspect")||a.customInspect;if("boolean"!=typeof c&&"symbol"!==c)throw new TypeError("option \"customInspect\", if provided, must be `true`, `false`, or `'symbol'`");if(q(a,"indent")&&null!==a.indent&&"\t"!==a.indent&&!(parseInt(a.indent,10)===a.indent&&a.indent>0))throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`');if(q(a,"numericSeparator")&&"boolean"!=typeof a.numericSeparator)throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`');var h=a.numericSeparator;if(void 0===e)return"undefined";if(null===e)return"null";if("boolean"==typeof e)return e?"true":"false";if("string"==typeof e)return function t(e,r){if(e.length>r.maxStringLength){var n=e.length-r.maxStringLength,o="... "+n+" more character"+(n>1?"s":"");return t(m.call(e,0,r.maxStringLength),r)+o}return T(D.call(D.call(e,/(['\\])/g,"\\$1"),/[\x00-\x1f]/g,H),"single",r)}(e,a);if("number"==typeof e){if(0===e)return 1/0/e>0?"0":"-0";var _=String(e);return h?I(e,_):_}if("bigint"==typeof e){var E=String(e)+"n";return h?I(e,E):E}var A=void 0===a.depth?5:a.depth;if(void 0===n&&(n=0),n>=A&&A>0&&"object"==typeof e)return W(e)?"[Array]":"[Object]";var O=function(t,e){var r;if("\t"===t.indent)r="\t";else{if(!("number"==typeof t.indent&&t.indent>0))return null;r=F.call(Array(t.indent+1)," ")}return{base:r,prev:F.call(Array(e+1),r)}}(a,n);if(void 0===o)o=[];else if(V(o,e)>=0)return"[Circular]";function B(e,r,i){if(r&&(o=j.call(o)).push(r),i){var u={depth:a.depth};return q(a,"quoteStyle")&&(u.quoteStyle=a.quoteStyle),t(e,u,n+1,o)}return t(e,a,n+1,o)}if("function"==typeof e&&!U(e)){var $=function(t){if(t.name)return t.name;var e=g.call(y.call(t),/^function\s*([\w$]+)/);if(e)return e[1];return null}(e),X=Y(e,B);return"[Function"+($?": "+$:" (anonymous)")+"]"+(X.length>0?" { "+F.call(X,", ")+" }":"")}if(z(e)){var tt=k?D.call(String(e),/^(Symbol\(.*\))_[^)]*$/,"$1"):S.call(e);return"object"!=typeof e||k?tt:Q(tt)}if(function(t){if(!t||"object"!=typeof t)return!1;if("undefined"!=typeof HTMLElement&&t instanceof HTMLElement)return!0;return"string"==typeof t.nodeName&&"function"==typeof t.getAttribute}(e)){for(var et="<"+b.call(String(e.nodeName)),rt=e.attributes||[],nt=0;nt"}if(W(e)){if(0===e.length)return"[]";var ot=Y(e,B);return O&&!function(t){for(var e=0;e=0)return!1;return!0}(ot)?"["+K(ot,O)+"]":"[ "+F.call(ot,", ")+" ]"}if(function(t){return!("[object Error]"!==G(t)||C&&"object"==typeof t&&C in t)}(e)){var it=Y(e,B);return"cause"in Error.prototype||!("cause"in e)||N.call(e,"cause")?0===it.length?"["+String(e)+"]":"{ ["+String(e)+"] "+F.call(it,", ")+" }":"{ ["+String(e)+"] "+F.call(w.call("[cause]: "+B(e.cause),it),", ")+" }"}if("object"==typeof e&&c){if(L&&"function"==typeof e[L]&&R)return R(e,{depth:A-n});if("symbol"!==c&&"function"==typeof e.inspect)return e.inspect()}if(function(t){if(!i||!t||"object"!=typeof t)return!1;try{i.call(t);try{l.call(t)}catch(et){return!0}return t instanceof Map}catch(e){}return!1}(e)){var ut=[];return u.call(e,(function(t,r){ut.push(B(r,e,!0)+" => "+B(t,e))})),Z("Map",i.call(e),ut,O)}if(function(t){if(!l||!t||"object"!=typeof t)return!1;try{l.call(t);try{i.call(t)}catch(e){return!0}return t instanceof Set}catch(r){}return!1}(e)){var at=[];return f.call(e,(function(t){at.push(B(t,e))})),Z("Set",l.call(e),at,O)}if(function(t){if(!s||!t||"object"!=typeof t)return!1;try{s.call(t,s);try{p.call(t,p)}catch(et){return!0}return t instanceof WeakMap}catch(e){}return!1}(e))return J("WeakMap");if(function(t){if(!p||!t||"object"!=typeof t)return!1;try{p.call(t,p);try{s.call(t,s)}catch(et){return!0}return t instanceof WeakSet}catch(e){}return!1}(e))return J("WeakSet");if(function(t){if(!v||!t||"object"!=typeof t)return!1;try{return v.call(t),!0}catch(e){}return!1}(e))return J("WeakRef");if(function(t){return!("[object Number]"!==G(t)||C&&"object"==typeof t&&C in t)}(e))return Q(B(Number(e)));if(function(t){if(!t||"object"!=typeof t||!x)return!1;try{return x.call(t),!0}catch(e){}return!1}(e))return Q(B(x.call(e)));if(function(t){return!("[object Boolean]"!==G(t)||C&&"object"==typeof t&&C in t)}(e))return Q(d.call(e));if(function(t){return!("[object String]"!==G(t)||C&&"object"==typeof t&&C in t)}(e))return Q(B(String(e)));if(!function(t){return!("[object Date]"!==G(t)||C&&"object"==typeof t&&C in t)}(e)&&!U(e)){var ct=Y(e,B),lt=P?P(e)===Object.prototype:e instanceof Object||e.constructor===Object,ft=e instanceof Object?"":"null prototype",st=!lt&&C&&Object(e)===e&&C in e?m.call(G(e),8,-1):ft?"Object":"",pt=(lt||"function"!=typeof e.constructor?"":e.constructor.name?e.constructor.name+" ":"")+(st||ft?"["+F.call(w.call([],st||[],ft||[]),": ")+"] ":"");return 0===ct.length?pt+"{}":O?pt+"{"+K(ct,O)+"}":pt+"{ "+F.call(ct,", ")+" }"}return String(e)};var $=Object.prototype.hasOwnProperty||function(t){return t in this};function q(t,e){return $.call(t,e)}function G(t){return h.call(t)}function V(t,e){if(t.indexOf)return t.indexOf(e);for(var r=0,n=t.length;r-1?t.split(","):t},l=function(t,e,r,n){if(t){var i=r.allowDots?t.replace(/\.([^.[]+)/g,"[$1]"):t,u=/(\[[^[\]]*])/g,a=r.depth>0&&/(\[[^[\]]*])/.exec(i),l=a?i.slice(0,a.index):i,f=[];if(l){if(!r.plainObjects&&o.call(Object.prototype,l)&&!r.allowPrototypes)return;f.push(l)}for(var s=0;r.depth>0&&null!==(a=u.exec(i))&&s=0;--i){var u,a=t[i];if("[]"===a&&r.parseArrays)u=[].concat(o);else{u=r.plainObjects?Object.create(null):{};var l="["===a.charAt(0)&&"]"===a.charAt(a.length-1)?a.slice(1,-1):a,f=parseInt(l,10);r.parseArrays||""!==l?!isNaN(f)&&a!==l&&String(f)===l&&f>=0&&r.parseArrays&&f<=r.arrayLimit?(u=[])[f]=o:"__proto__"!==l&&(u[l]=o):u={0:o}}o=u}return o}(f,e,r,n)}};t.exports=function(t,e){var r=function(t){if(!t)return u;if(null!==t.decoder&&void 0!==t.decoder&&"function"!=typeof t.decoder)throw new TypeError("Decoder has to be a function.");if(void 0!==t.charset&&"utf-8"!==t.charset&&"iso-8859-1"!==t.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var e=void 0===t.charset?u.charset:t.charset;return{allowDots:void 0===t.allowDots?u.allowDots:!!t.allowDots,allowPrototypes:"boolean"==typeof t.allowPrototypes?t.allowPrototypes:u.allowPrototypes,allowSparse:"boolean"==typeof t.allowSparse?t.allowSparse:u.allowSparse,arrayLimit:"number"==typeof t.arrayLimit?t.arrayLimit:u.arrayLimit,charset:e,charsetSentinel:"boolean"==typeof t.charsetSentinel?t.charsetSentinel:u.charsetSentinel,comma:"boolean"==typeof t.comma?t.comma:u.comma,decoder:"function"==typeof t.decoder?t.decoder:u.decoder,delimiter:"string"==typeof t.delimiter||n.isRegExp(t.delimiter)?t.delimiter:u.delimiter,depth:"number"==typeof t.depth||!1===t.depth?+t.depth:u.depth,ignoreQueryPrefix:!0===t.ignoreQueryPrefix,interpretNumericEntities:"boolean"==typeof t.interpretNumericEntities?t.interpretNumericEntities:u.interpretNumericEntities,parameterLimit:"number"==typeof t.parameterLimit?t.parameterLimit:u.parameterLimit,parseArrays:!1!==t.parseArrays,plainObjects:"boolean"==typeof t.plainObjects?t.plainObjects:u.plainObjects,strictNullHandling:"boolean"==typeof t.strictNullHandling?t.strictNullHandling:u.strictNullHandling}}(e);if(""===t||null==t)return r.plainObjects?Object.create(null):{};for(var f="string"==typeof t?function(t,e){var r,l={},f=e.ignoreQueryPrefix?t.replace(/^\?/,""):t,s=e.parameterLimit===1/0?void 0:e.parameterLimit,p=f.split(e.delimiter,s),v=-1,d=e.charset;if(e.charsetSentinel)for(r=0;r-1&&(y=i(y)?[y]:y),o.call(l,h)?l[h]=n.combine(l[h],y):l[h]=y}return l}(t,r):t,s=r.plainObjects?Object.create(null):{},p=Object.keys(f),v=0;v1?arguments[1]:void 0)}}),r(74)("find")},442:function(t,e,r){"use strict";var n=r(8),o=r(486),i=r(55);r(56)("search",1,(function(t,e,r,u){return[function(r){var n=t(this),o=null==r?void 0:r[e];return void 0!==o?o.call(r,n):new RegExp(r)[e](String(n))},function(t){var e=u(r,t,this);if(e.done)return e.value;var a=n(t),c=String(this),l=a.lastIndex;o(l,0)||(a.lastIndex=0);var f=i(a,c);return o(a.lastIndex,l)||(a.lastIndex=l),null===f?-1:f.index}]}))},445:function(t,e,r){"use strict";r(457);var n=r(0),o=r.n(n),i=r(458),u=r(443),a=r(1),c=(r(446),r(447),r(459),r(430)),l=r(460),f=r(440),s=r.n(f),p=r(461),v=r.n(p),d=r(436),h=r(423),y=r.n(h),g=r(135),m=r.n(g),D=function(){return o.a.createElement("span",{className:y()(m.a.toggle,m.a.moon)})},_=function(){return o.a.createElement("span",{className:y()(m.a.toggle,m.a.sun)})},b=function(t){var e=Object(d.a)().isClient;return o.a.createElement(v.a,Object(a.a)({disabled:!e,icons:{checked:o.a.createElement(D,null),unchecked:o.a.createElement(_,null)}},t))};function E(){var t=Object(d.a)().siteConfig,e=(void 0===t?{}:t).customFields.metadata.latest_post,r=Date.parse(e.date),n=new Date,o=Math.abs(n-r),i=Math.ceil(o/864e5),u=null;return"undefined"!=typeof window&&(u=new Date(parseInt(window.localStorage.getItem("blogViewedAt")||"0"))),i<30&&(!u||u0&&o.a.createElement("div",{className:"row footer__links"},o.a.createElement("div",{className:"col col--5 footer__col"},o.a.createElement("div",{className:"margin-bottom--md"},o.a.createElement(s.a,{className:"navbar__logo",src:v,alt:"Qovery",width:"150",height:"auto"})),o.a.createElement("div",{className:"margin-bottom--md"},o.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),o.a.createElement("div",null,o.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},o.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",o.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},o.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",o.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},o.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",o.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},o.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),c.map((function(t,e){return o.a.createElement("div",{key:e,className:"col footer__col"},null!=t.title?o.a.createElement("h4",{className:"footer__title"},t.title):null,null!=t.items&&Array.isArray(t.items)&&t.items.length>0?o.a.createElement("ul",{className:"footer__items"},t.items.map((function(t,e){return t.html?o.a.createElement("li",{key:e,className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):o.a.createElement("li",{key:t.href||t.to,className:"footer__item"},o.a.createElement(B,t))}))):null)}))),(f||u)&&o.a.createElement("div",{className:"text--center"},f&&f.src&&o.a.createElement("div",{className:"margin-bottom--sm"},f.href?o.a.createElement("a",{href:f.href,target:"_blank",rel:"noopener noreferrer",className:R.a.footerLogoLink},o.a.createElement(L,{alt:f.alt,url:p})):o.a.createElement(L,{alt:f.alt,url:p})),o.a.createElement("small",null,u),o.a.createElement("br",null))))},M=r(462),W=r(463),U=r(3);r(138);e.a=function(t){var e=Object(d.a)().siteConfig,r=void 0===e?{}:e,n=r.favicon,a=(r.tagline,r.title),c=r.themeConfig.image,l=r.url,f=t.children,s=t.title,p=t.noFooter,v=t.description,h=t.image,y=t.keywords,g=(t.permalink,t.version),m=s?s+" | "+a:a,D=h||c,_=l+Object(F.a)(D),b=Object(F.a)(n),E=Object(U.h)(),w=E?"https://docs.qovery.com"+(E.pathname.endsWith("/")?E.pathname:E.pathname+"/"):null;return o.a.createElement(W.a,null,o.a.createElement(M.a,null,o.a.createElement(u.a,null,o.a.createElement("html",{lang:"en"}),o.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),m&&o.a.createElement("title",null,m),m&&o.a.createElement("meta",{property:"og:title",content:m}),n&&o.a.createElement("link",{rel:"shortcut icon",href:b}),v&&o.a.createElement("meta",{name:"description",content:v}),v&&o.a.createElement("meta",{property:"og:description",content:v}),g&&o.a.createElement("meta",{name:"docsearch:version",content:g}),y&&y.length&&o.a.createElement("meta",{name:"keywords",content:y.join(",")}),D&&o.a.createElement("meta",{property:"og:image",content:_}),D&&o.a.createElement("meta",{property:"twitter:image",content:_}),D&&o.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+m}),w&&o.a.createElement("meta",{property:"og:url",content:w}),o.a.createElement("meta",{name:"twitter:card",content:"summary"}),w&&o.a.createElement("link",{rel:"canonical",href:w})),o.a.createElement(i.a,null),o.a.createElement(N,null),o.a.createElement("div",{className:"main-wrapper"},f),!p&&o.a.createElement(T,null)))}},450:function(t,e,r){"use strict";var n=r(9),o=r(0),i=r.n(o),u=r(423),a=r.n(u),c=r(436),l=(r(139),r(140)),f=r.n(l);e.a=function(t){return function(e){var r,o=e.id,u=Object(n.a)(e,["id"]),l=Object(c.a)().siteConfig,s=(l=void 0===l?{}:l).themeConfig,p=(s=void 0===s?{}:s).navbar,v=(p=void 0===p?{}:p).hideOnScroll,d=void 0!==v&&v;return o?i.a.createElement(t,u,i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:a()("anchor",(r={},r[f.a.enhancedAnchor]=!d,r)),id:o}),i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+o,title:"Direct link to heading"},"#"),u.children):i.a.createElement(t,u)}}},451:function(t,e,r){(function(t,n){var o;(function(){var i="Expected a function",u="__lodash_placeholder__",a=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],c="[object Arguments]",l="[object Array]",f="[object Boolean]",s="[object Date]",p="[object Error]",v="[object Function]",d="[object GeneratorFunction]",h="[object Map]",y="[object Number]",g="[object Object]",m="[object RegExp]",D="[object Set]",_="[object String]",b="[object Symbol]",E="[object WeakMap]",w="[object ArrayBuffer]",F="[object DataView]",j="[object Float32Array]",A="[object Float64Array]",x="[object Int8Array]",O="[object Int16Array]",S="[object Int32Array]",k="[object Uint8Array]",C="[object Uint16Array]",N="[object Uint32Array]",P=/\b__p \+= '';/g,I=/\b(__p \+=) '' \+/g,R=/(__e\(.*?\)|\b__t\)) \+\n'';/g,B=/&(?:amp|lt|gt|quot|#39);/g,L=/[&<>"']/g,T=RegExp(B.source),M=RegExp(L.source),W=/<%-([\s\S]+?)%>/g,U=/<%([\s\S]+?)%>/g,z=/<%=([\s\S]+?)%>/g,$=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,q=/^\w*$/,G=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,V=/[\\^$.*+?()[\]{}|]/g,H=RegExp(V.source),Q=/^\s+|\s+$/g,J=/^\s+/,Z=/\s+$/,K=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Y=/\{\n\/\* \[wrapped with (.+)\] \*/,X=/,? & /,tt=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,et=/\\(\\)?/g,rt=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,nt=/\w*$/,ot=/^[-+]0x[0-9a-f]+$/i,it=/^0b[01]+$/i,ut=/^\[object .+?Constructor\]$/,at=/^0o[0-7]+$/i,ct=/^(?:0|[1-9]\d*)$/,lt=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,ft=/($^)/,st=/['\n\r\u2028\u2029\\]/g,pt="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",vt="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",dt="[\\ud800-\\udfff]",ht="["+vt+"]",yt="["+pt+"]",gt="\\d+",mt="[\\u2700-\\u27bf]",Dt="[a-z\\xdf-\\xf6\\xf8-\\xff]",_t="[^\\ud800-\\udfff"+vt+gt+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",bt="\\ud83c[\\udffb-\\udfff]",Et="[^\\ud800-\\udfff]",wt="(?:\\ud83c[\\udde6-\\uddff]){2}",Ft="[\\ud800-\\udbff][\\udc00-\\udfff]",jt="[A-Z\\xc0-\\xd6\\xd8-\\xde]",At="(?:"+Dt+"|"+_t+")",xt="(?:"+jt+"|"+_t+")",Ot="(?:"+yt+"|"+bt+")"+"?",St="[\\ufe0e\\ufe0f]?"+Ot+("(?:\\u200d(?:"+[Et,wt,Ft].join("|")+")[\\ufe0e\\ufe0f]?"+Ot+")*"),kt="(?:"+[mt,wt,Ft].join("|")+")"+St,Ct="(?:"+[Et+yt+"?",yt,wt,Ft,dt].join("|")+")",Nt=RegExp("['\u2019]","g"),Pt=RegExp(yt,"g"),It=RegExp(bt+"(?="+bt+")|"+Ct+St,"g"),Rt=RegExp([jt+"?"+Dt+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?="+[ht,jt,"$"].join("|")+")",xt+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?="+[ht,jt+At,"$"].join("|")+")",jt+"?"+At+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?",jt+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",gt,kt].join("|"),"g"),Bt=RegExp("[\\u200d\\ud800-\\udfff"+pt+"\\ufe0e\\ufe0f]"),Lt=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Tt=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Mt=-1,Wt={};Wt[j]=Wt[A]=Wt[x]=Wt[O]=Wt[S]=Wt[k]=Wt["[object Uint8ClampedArray]"]=Wt[C]=Wt[N]=!0,Wt[c]=Wt[l]=Wt[w]=Wt[f]=Wt[F]=Wt[s]=Wt[p]=Wt[v]=Wt[h]=Wt[y]=Wt[g]=Wt[m]=Wt[D]=Wt[_]=Wt[E]=!1;var Ut={};Ut[c]=Ut[l]=Ut[w]=Ut[F]=Ut[f]=Ut[s]=Ut[j]=Ut[A]=Ut[x]=Ut[O]=Ut[S]=Ut[h]=Ut[y]=Ut[g]=Ut[m]=Ut[D]=Ut[_]=Ut[b]=Ut[k]=Ut["[object Uint8ClampedArray]"]=Ut[C]=Ut[N]=!0,Ut[p]=Ut[v]=Ut[E]=!1;var zt={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},$t=parseFloat,qt=parseInt,Gt="object"==typeof t&&t&&t.Object===Object&&t,Vt="object"==typeof self&&self&&self.Object===Object&&self,Ht=Gt||Vt||Function("return this")(),Qt=e&&!e.nodeType&&e,Jt=Qt&&"object"==typeof n&&n&&!n.nodeType&&n,Zt=Jt&&Jt.exports===Qt,Kt=Zt&&Gt.process,Yt=function(){try{var t=Jt&&Jt.require&&Jt.require("util").types;return t||Kt&&Kt.binding&&Kt.binding("util")}catch(e){}}(),Xt=Yt&&Yt.isArrayBuffer,te=Yt&&Yt.isDate,ee=Yt&&Yt.isMap,re=Yt&&Yt.isRegExp,ne=Yt&&Yt.isSet,oe=Yt&&Yt.isTypedArray;function ie(t,e,r){switch(r.length){case 0:return t.call(e);case 1:return t.call(e,r[0]);case 2:return t.call(e,r[0],r[1]);case 3:return t.call(e,r[0],r[1],r[2])}return t.apply(e,r)}function ue(t,e,r,n){for(var o=-1,i=null==t?0:t.length;++o-1}function pe(t,e,r){for(var n=-1,o=null==t?0:t.length;++n-1;);return r}function Ie(t,e){for(var r=t.length;r--&&be(e,t[r],0)>-1;);return r}function Re(t,e){for(var r=t.length,n=0;r--;)t[r]===e&&++n;return n}var Be=Ae({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),Le=Ae({"&":"&","<":"<",">":">",'"':""","'":"'"});function Te(t){return"\\"+zt[t]}function Me(t){return Bt.test(t)}function We(t){var e=-1,r=Array(t.size);return t.forEach((function(t,n){r[++e]=[n,t]})),r}function Ue(t,e){return function(r){return t(e(r))}}function ze(t,e){for(var r=-1,n=t.length,o=0,i=[];++r",""":'"',"'":"'"});var Qe=function t(e){var r,n=(e=null==e?Ht:Qe.defaults(Ht.Object(),e,Qe.pick(Ht,Tt))).Array,o=e.Date,pt=e.Error,vt=e.Function,dt=e.Math,ht=e.Object,yt=e.RegExp,gt=e.String,mt=e.TypeError,Dt=n.prototype,_t=vt.prototype,bt=ht.prototype,Et=e["__core-js_shared__"],wt=_t.toString,Ft=bt.hasOwnProperty,jt=0,At=(r=/[^.]+$/.exec(Et&&Et.keys&&Et.keys.IE_PROTO||""))?"Symbol(src)_1."+r:"",xt=bt.toString,Ot=wt.call(ht),St=Ht._,kt=yt("^"+wt.call(Ft).replace(V,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Ct=Zt?e.Buffer:void 0,It=e.Symbol,Bt=e.Uint8Array,zt=Ct?Ct.allocUnsafe:void 0,Gt=Ue(ht.getPrototypeOf,ht),Vt=ht.create,Qt=bt.propertyIsEnumerable,Jt=Dt.splice,Kt=It?It.isConcatSpreadable:void 0,Yt=It?It.iterator:void 0,me=It?It.toStringTag:void 0,Ae=function(){try{var t=ti(ht,"defineProperty");return t({},"",{}),t}catch(e){}}(),Je=e.clearTimeout!==Ht.clearTimeout&&e.clearTimeout,Ze=o&&o.now!==Ht.Date.now&&o.now,Ke=e.setTimeout!==Ht.setTimeout&&e.setTimeout,Ye=dt.ceil,Xe=dt.floor,tr=ht.getOwnPropertySymbols,er=Ct?Ct.isBuffer:void 0,rr=e.isFinite,nr=Dt.join,or=Ue(ht.keys,ht),ir=dt.max,ur=dt.min,ar=o.now,cr=e.parseInt,lr=dt.random,fr=Dt.reverse,sr=ti(e,"DataView"),pr=ti(e,"Map"),vr=ti(e,"Promise"),dr=ti(e,"Set"),hr=ti(e,"WeakMap"),yr=ti(ht,"create"),gr=hr&&new hr,mr={},Dr=xi(sr),_r=xi(pr),br=xi(vr),Er=xi(dr),wr=xi(hr),Fr=It?It.prototype:void 0,jr=Fr?Fr.valueOf:void 0,Ar=Fr?Fr.toString:void 0;function xr(t){if(qu(t)&&!Pu(t)&&!(t instanceof Cr)){if(t instanceof kr)return t;if(Ft.call(t,"__wrapped__"))return Oi(t)}return new kr(t)}var Or=function(){function t(){}return function(e){if(!$u(e))return{};if(Vt)return Vt(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}();function Sr(){}function kr(t,e){this.__wrapped__=t,this.__actions__=[],this.__chain__=!!e,this.__index__=0,this.__values__=void 0}function Cr(t){this.__wrapped__=t,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Nr(t){var e=-1,r=null==t?0:t.length;for(this.clear();++e=e?t:e)),t}function Jr(t,e,r,n,o,i){var u,a=1&e,l=2&e,p=4&e;if(r&&(u=o?r(t,n,o,i):r(t)),void 0!==u)return u;if(!$u(t))return t;var E=Pu(t);if(E){if(u=function(t){var e=t.length,r=new t.constructor(e);e&&"string"==typeof t[0]&&Ft.call(t,"index")&&(r.index=t.index,r.input=t.input);return r}(t),!a)return mo(t,u)}else{var P=ni(t),I=P==v||P==d;if(Lu(t))return so(t,a);if(P==g||P==c||I&&!o){if(u=l||I?{}:ii(t),!a)return l?function(t,e){return Do(t,ri(t),e)}(t,function(t,e){return t&&Do(e,ba(e),t)}(u,t)):function(t,e){return Do(t,ei(t),e)}(t,Gr(u,t))}else{if(!Ut[P])return o?t:{};u=function(t,e,r){var n=t.constructor;switch(e){case w:return po(t);case f:case s:return new n(+t);case F:return function(t,e){var r=e?po(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.byteLength)}(t,r);case j:case A:case x:case O:case S:case k:case"[object Uint8ClampedArray]":case C:case N:return vo(t,r);case h:return new n;case y:case _:return new n(t);case m:return function(t){var e=new t.constructor(t.source,nt.exec(t));return e.lastIndex=t.lastIndex,e}(t);case D:return new n;case b:return o=t,jr?ht(jr.call(o)):{}}var o}(t,P,a)}}i||(i=new Br);var R=i.get(t);if(R)return R;i.set(t,u),Ju(t)?t.forEach((function(n){u.add(Jr(n,e,r,n,t,i))})):Gu(t)&&t.forEach((function(n,o){u.set(o,Jr(n,e,r,o,t,i))}));var B=E?void 0:(p?l?Ho:Vo:l?ba:_a)(t);return ae(B||t,(function(n,o){B&&(n=t[o=n]),zr(u,o,Jr(n,e,r,o,t,i))})),u}function Zr(t,e,r){var n=r.length;if(null==t)return!n;for(t=ht(t);n--;){var o=r[n],i=e[o],u=t[o];if(void 0===u&&!(o in t)||!i(u))return!1}return!0}function Kr(t,e,r){if("function"!=typeof t)throw new mt(i);return _i((function(){t.apply(void 0,r)}),e)}function Yr(t,e,r,n){var o=-1,i=se,u=!0,a=t.length,c=[],l=e.length;if(!a)return c;r&&(e=ve(e,ke(r))),n?(i=pe,u=!1):e.length>=200&&(i=Ne,u=!1,e=new Rr(e));t:for(;++o-1},Pr.prototype.set=function(t,e){var r=this.__data__,n=$r(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this},Ir.prototype.clear=function(){this.size=0,this.__data__={hash:new Nr,map:new(pr||Pr),string:new Nr}},Ir.prototype.delete=function(t){var e=Yo(this,t).delete(t);return this.size-=e?1:0,e},Ir.prototype.get=function(t){return Yo(this,t).get(t)},Ir.prototype.has=function(t){return Yo(this,t).has(t)},Ir.prototype.set=function(t,e){var r=Yo(this,t),n=r.size;return r.set(t,e),this.size+=r.size==n?0:1,this},Rr.prototype.add=Rr.prototype.push=function(t){return this.__data__.set(t,"__lodash_hash_undefined__"),this},Rr.prototype.has=function(t){return this.__data__.has(t)},Br.prototype.clear=function(){this.__data__=new Pr,this.size=0},Br.prototype.delete=function(t){var e=this.__data__,r=e.delete(t);return this.size=e.size,r},Br.prototype.get=function(t){return this.__data__.get(t)},Br.prototype.has=function(t){return this.__data__.has(t)},Br.prototype.set=function(t,e){var r=this.__data__;if(r instanceof Pr){var n=r.__data__;if(!pr||n.length<199)return n.push([t,e]),this.size=++r.size,this;r=this.__data__=new Ir(n)}return r.set(t,e),this.size=r.size,this};var Xr=Eo(cn),tn=Eo(ln,!0);function en(t,e){var r=!0;return Xr(t,(function(t,n,o){return r=!!e(t,n,o)})),r}function rn(t,e,r){for(var n=-1,o=t.length;++n0&&r(a)?e>1?on(a,e-1,r,n,o):de(o,a):n||(o[o.length]=a)}return o}var un=wo(),an=wo(!0);function cn(t,e){return t&&un(t,e,_a)}function ln(t,e){return t&&an(t,e,_a)}function fn(t,e){return fe(e,(function(e){return Wu(t[e])}))}function sn(t,e){for(var r=0,n=(e=ao(e,t)).length;null!=t&&re}function hn(t,e){return null!=t&&Ft.call(t,e)}function yn(t,e){return null!=t&&e in ht(t)}function gn(t,e,r){for(var o=r?pe:se,i=t[0].length,u=t.length,a=u,c=n(u),l=1/0,f=[];a--;){var s=t[a];a&&e&&(s=ve(s,ke(e))),l=ur(s.length,l),c[a]=!r&&(e||i>=120&&s.length>=120)?new Rr(a&&s):void 0}s=t[0];var p=-1,v=c[0];t:for(;++p=a)return c;var l=r[n];return c*("desc"==l?-1:1)}}return t.index-e.index}(t,e,r)}))}function Pn(t,e,r){for(var n=-1,o=e.length,i={};++n-1;)a!==t&&Jt.call(a,c,1),Jt.call(t,c,1);return t}function Rn(t,e){for(var r=t?e.length:0,n=r-1;r--;){var o=e[r];if(r==n||o!==i){var i=o;ai(o)?Jt.call(t,o,1):Xn(t,o)}}return t}function Bn(t,e){return t+Xe(lr()*(e-t+1))}function Ln(t,e){var r="";if(!t||e<1||e>9007199254740991)return r;do{e%2&&(r+=t),(e=Xe(e/2))&&(t+=t)}while(e);return r}function Tn(t,e){return bi(hi(t,e,Va),t+"")}function Mn(t){return Tr(Sa(t))}function Wn(t,e){var r=Sa(t);return Fi(r,Qr(e,0,r.length))}function Un(t,e,r,n){if(!$u(t))return t;for(var o=-1,i=(e=ao(e,t)).length,u=i-1,a=t;null!=a&&++oi?0:i+e),(r=r>i?i:r)<0&&(r+=i),i=e>r?0:r-e>>>0,e>>>=0;for(var u=n(i);++o>>1,u=t[i];null!==u&&!Ku(u)&&(r?u<=e:u=200){var l=e?null:To(t);if(l)return $e(l);u=!1,o=Ne,c=new Rr}else c=e?[]:a;t:for(;++n=n?t:Gn(t,e,r)}var fo=Je||function(t){return Ht.clearTimeout(t)};function so(t,e){if(e)return t.slice();var r=t.length,n=zt?zt(r):new t.constructor(r);return t.copy(n),n}function po(t){var e=new t.constructor(t.byteLength);return new Bt(e).set(new Bt(t)),e}function vo(t,e){var r=e?po(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.length)}function ho(t,e){if(t!==e){var r=void 0!==t,n=null===t,o=t==t,i=Ku(t),u=void 0!==e,a=null===e,c=e==e,l=Ku(e);if(!a&&!l&&!i&&t>e||i&&u&&c&&!a&&!l||n&&u&&c||!r&&c||!o)return 1;if(!n&&!i&&!l&&t1?r[o-1]:void 0,u=o>2?r[2]:void 0;for(i=t.length>3&&"function"==typeof i?(o--,i):void 0,u&&ci(r[0],r[1],u)&&(i=o<3?void 0:i,o=1),e=ht(e);++n-1?o[i?e[u]:u]:void 0}}function Oo(t){return Go((function(e){var r=e.length,n=r,o=kr.prototype.thru;for(t&&e.reverse();n--;){var u=e[n];if("function"!=typeof u)throw new mt(i);if(o&&!a&&"wrapper"==Jo(u))var a=new kr([],!0)}for(n=a?n:r;++n1&&D.reverse(),s&&la))return!1;var l=i.get(t);if(l&&i.get(e))return l==e;var f=-1,s=!0,p=2&r?new Rr:void 0;for(i.set(t,e),i.set(e,t);++f-1&&t%1==0&&t1?"& ":"")+e[n],e=e.join(r>2?", ":" "),t.replace(K,"{\n/* [wrapped with "+e+"] */\n")}(n,function(t,e){return ae(a,(function(r){var n="_."+r[0];e&r[1]&&!se(t,n)&&t.push(n)})),t.sort()}(function(t){var e=t.match(Y);return e?e[1].split(X):[]}(n),r)))}function wi(t){var e=0,r=0;return function(){var n=ar(),o=16-(n-r);if(r=n,o>0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}function Fi(t,e){var r=-1,n=t.length,o=n-1;for(e=void 0===e?n:e;++r1?t[e-1]:void 0;return r="function"==typeof r?(t.pop(),r):void 0,Qi(t,r)}));function eu(t){var e=xr(t);return e.__chain__=!0,e}function ru(t,e){return e(t)}var nu=Go((function(t){var e=t.length,r=e?t[0]:0,n=this.__wrapped__,o=function(e){return Hr(e,t)};return!(e>1||this.__actions__.length)&&n instanceof Cr&&ai(r)?((n=n.slice(r,+r+(e?1:0))).__actions__.push({func:ru,args:[o],thisArg:void 0}),new kr(n,this.__chain__).thru((function(t){return e&&!t.length&&t.push(void 0),t}))):this.thru(o)}));var ou=_o((function(t,e,r){Ft.call(t,r)?++t[r]:Vr(t,r,1)}));var iu=xo(Ni),uu=xo(Pi);function au(t,e){return(Pu(t)?ae:Xr)(t,Ko(e,3))}function cu(t,e){return(Pu(t)?ce:tn)(t,Ko(e,3))}var lu=_o((function(t,e,r){Ft.call(t,r)?t[r].push(e):Vr(t,r,[e])}));var fu=Tn((function(t,e,r){var o=-1,i="function"==typeof e,u=Ru(t)?n(t.length):[];return Xr(t,(function(t){u[++o]=i?ie(e,t,r):mn(t,e,r)})),u})),su=_o((function(t,e,r){Vr(t,r,e)}));function pu(t,e){return(Pu(t)?ve:xn)(t,Ko(e,3))}var vu=_o((function(t,e,r){t[r?0:1].push(e)}),(function(){return[[],[]]}));var du=Tn((function(t,e){if(null==t)return[];var r=e.length;return r>1&&ci(t,e[0],e[1])?e=[]:r>2&&ci(e[0],e[1],e[2])&&(e=[e[0]]),Nn(t,on(e,1),[])})),hu=Ze||function(){return Ht.Date.now()};function yu(t,e,r){return e=r?void 0:e,Wo(t,128,void 0,void 0,void 0,void 0,e=t&&null==e?t.length:e)}function gu(t,e){var r;if("function"!=typeof e)throw new mt(i);return t=na(t),function(){return--t>0&&(r=e.apply(this,arguments)),t<=1&&(e=void 0),r}}var mu=Tn((function(t,e,r){var n=1;if(r.length){var o=ze(r,Zo(mu));n|=32}return Wo(t,n,e,r,o)})),Du=Tn((function(t,e,r){var n=3;if(r.length){var o=ze(r,Zo(Du));n|=32}return Wo(e,n,t,r,o)}));function _u(t,e,r){var n,o,u,a,c,l,f=0,s=!1,p=!1,v=!0;if("function"!=typeof t)throw new mt(i);function d(e){var r=n,i=o;return n=o=void 0,f=e,a=t.apply(i,r)}function h(t){return f=t,c=_i(g,e),s?d(t):a}function y(t){var r=t-l;return void 0===l||r>=e||r<0||p&&t-f>=u}function g(){var t=hu();if(y(t))return m(t);c=_i(g,function(t){var r=e-(t-l);return p?ur(r,u-(t-f)):r}(t))}function m(t){return c=void 0,v&&n?d(t):(n=o=void 0,a)}function D(){var t=hu(),r=y(t);if(n=arguments,o=this,l=t,r){if(void 0===c)return h(l);if(p)return fo(c),c=_i(g,e),d(l)}return void 0===c&&(c=_i(g,e)),a}return e=ia(e)||0,$u(r)&&(s=!!r.leading,u=(p="maxWait"in r)?ir(ia(r.maxWait)||0,e):u,v="trailing"in r?!!r.trailing:v),D.cancel=function(){void 0!==c&&fo(c),f=0,n=l=o=c=void 0},D.flush=function(){return void 0===c?a:m(hu())},D}var bu=Tn((function(t,e){return Kr(t,1,e)})),Eu=Tn((function(t,e,r){return Kr(t,ia(e)||0,r)}));function wu(t,e){if("function"!=typeof t||null!=e&&"function"!=typeof e)throw new mt(i);var r=function(){var n=arguments,o=e?e.apply(this,n):n[0],i=r.cache;if(i.has(o))return i.get(o);var u=t.apply(this,n);return r.cache=i.set(o,u)||i,u};return r.cache=new(wu.Cache||Ir),r}function Fu(t){if("function"!=typeof t)throw new mt(i);return function(){var e=arguments;switch(e.length){case 0:return!t.call(this);case 1:return!t.call(this,e[0]);case 2:return!t.call(this,e[0],e[1]);case 3:return!t.call(this,e[0],e[1],e[2])}return!t.apply(this,e)}}wu.Cache=Ir;var ju=co((function(t,e){var r=(e=1==e.length&&Pu(e[0])?ve(e[0],ke(Ko())):ve(on(e,1),ke(Ko()))).length;return Tn((function(n){for(var o=-1,i=ur(n.length,r);++o=e})),Nu=Dn(function(){return arguments}())?Dn:function(t){return qu(t)&&Ft.call(t,"callee")&&!Qt.call(t,"callee")},Pu=n.isArray,Iu=Xt?ke(Xt):function(t){return qu(t)&&vn(t)==w};function Ru(t){return null!=t&&zu(t.length)&&!Wu(t)}function Bu(t){return qu(t)&&Ru(t)}var Lu=er||ic,Tu=te?ke(te):function(t){return qu(t)&&vn(t)==s};function Mu(t){if(!qu(t))return!1;var e=vn(t);return e==p||"[object DOMException]"==e||"string"==typeof t.message&&"string"==typeof t.name&&!Hu(t)}function Wu(t){if(!$u(t))return!1;var e=vn(t);return e==v||e==d||"[object AsyncFunction]"==e||"[object Proxy]"==e}function Uu(t){return"number"==typeof t&&t==na(t)}function zu(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=9007199254740991}function $u(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)}function qu(t){return null!=t&&"object"==typeof t}var Gu=ee?ke(ee):function(t){return qu(t)&&ni(t)==h};function Vu(t){return"number"==typeof t||qu(t)&&vn(t)==y}function Hu(t){if(!qu(t)||vn(t)!=g)return!1;var e=Gt(t);if(null===e)return!0;var r=Ft.call(e,"constructor")&&e.constructor;return"function"==typeof r&&r instanceof r&&wt.call(r)==Ot}var Qu=re?ke(re):function(t){return qu(t)&&vn(t)==m};var Ju=ne?ke(ne):function(t){return qu(t)&&ni(t)==D};function Zu(t){return"string"==typeof t||!Pu(t)&&qu(t)&&vn(t)==_}function Ku(t){return"symbol"==typeof t||qu(t)&&vn(t)==b}var Yu=oe?ke(oe):function(t){return qu(t)&&zu(t.length)&&!!Wt[vn(t)]};var Xu=Ro(An),ta=Ro((function(t,e){return t<=e}));function ea(t){if(!t)return[];if(Ru(t))return Zu(t)?Ve(t):mo(t);if(Yt&&t[Yt])return function(t){for(var e,r=[];!(e=t.next()).done;)r.push(e.value);return r}(t[Yt]());var e=ni(t);return(e==h?We:e==D?$e:Sa)(t)}function ra(t){return t?(t=ia(t))===1/0||t===-1/0?17976931348623157e292*(t<0?-1:1):t==t?t:0:0===t?t:0}function na(t){var e=ra(t),r=e%1;return e==e?r?e-r:e:0}function oa(t){return t?Qr(na(t),0,4294967295):0}function ia(t){if("number"==typeof t)return t;if(Ku(t))return NaN;if($u(t)){var e="function"==typeof t.valueOf?t.valueOf():t;t=$u(e)?e+"":e}if("string"!=typeof t)return 0===t?t:+t;t=t.replace(Q,"");var r=it.test(t);return r||at.test(t)?qt(t.slice(2),r?2:8):ot.test(t)?NaN:+t}function ua(t){return Do(t,ba(t))}function aa(t){return null==t?"":Kn(t)}var ca=bo((function(t,e){if(pi(e)||Ru(e))Do(e,_a(e),t);else for(var r in e)Ft.call(e,r)&&zr(t,r,e[r])})),la=bo((function(t,e){Do(e,ba(e),t)})),fa=bo((function(t,e,r,n){Do(e,ba(e),t,n)})),sa=bo((function(t,e,r,n){Do(e,_a(e),t,n)})),pa=Go(Hr);var va=Tn((function(t,e){t=ht(t);var r=-1,n=e.length,o=n>2?e[2]:void 0;for(o&&ci(e[0],e[1],o)&&(n=1);++r1),e})),Do(t,Ho(t),r),n&&(r=Jr(r,7,$o));for(var o=e.length;o--;)Xn(r,e[o]);return r}));var ja=Go((function(t,e){return null==t?{}:function(t,e){return Pn(t,e,(function(e,r){return ya(t,r)}))}(t,e)}));function Aa(t,e){if(null==t)return{};var r=ve(Ho(t),(function(t){return[t]}));return e=Ko(e),Pn(t,r,(function(t,r){return e(t,r[0])}))}var xa=Mo(_a),Oa=Mo(ba);function Sa(t){return null==t?[]:Ce(t,_a(t))}var ka=jo((function(t,e,r){return e=e.toLowerCase(),t+(r?Ca(e):e)}));function Ca(t){return Ma(aa(t).toLowerCase())}function Na(t){return(t=aa(t))&&t.replace(lt,Be).replace(Pt,"")}var Pa=jo((function(t,e,r){return t+(r?"-":"")+e.toLowerCase()})),Ia=jo((function(t,e,r){return t+(r?" ":"")+e.toLowerCase()})),Ra=Fo("toLowerCase");var Ba=jo((function(t,e,r){return t+(r?"_":"")+e.toLowerCase()}));var La=jo((function(t,e,r){return t+(r?" ":"")+Ma(e)}));var Ta=jo((function(t,e,r){return t+(r?" ":"")+e.toUpperCase()})),Ma=Fo("toUpperCase");function Wa(t,e,r){return t=aa(t),void 0===(e=r?void 0:e)?function(t){return Lt.test(t)}(t)?function(t){return t.match(Rt)||[]}(t):function(t){return t.match(tt)||[]}(t):t.match(e)||[]}var Ua=Tn((function(t,e){try{return ie(t,void 0,e)}catch(r){return Mu(r)?r:new pt(r)}})),za=Go((function(t,e){return ae(e,(function(e){e=Ai(e),Vr(t,e,mu(t[e],t))})),t}));function $a(t){return function(){return t}}var qa=Oo(),Ga=Oo(!0);function Va(t){return t}function Ha(t){return wn("function"==typeof t?t:Jr(t,1))}var Qa=Tn((function(t,e){return function(r){return mn(r,t,e)}})),Ja=Tn((function(t,e){return function(r){return mn(t,r,e)}}));function Za(t,e,r){var n=_a(e),o=fn(e,n);null!=r||$u(e)&&(o.length||!n.length)||(r=e,e=t,t=this,o=fn(e,_a(e)));var i=!($u(r)&&"chain"in r&&!r.chain),u=Wu(t);return ae(o,(function(r){var n=e[r];t[r]=n,u&&(t.prototype[r]=function(){var e=this.__chain__;if(i||e){var r=t(this.__wrapped__),o=r.__actions__=mo(this.__actions__);return o.push({func:n,args:arguments,thisArg:t}),r.__chain__=e,r}return n.apply(t,de([this.value()],arguments))})})),t}function Ka(){}var Ya=No(ve),Xa=No(le),tc=No(ge);function ec(t){return li(t)?je(Ai(t)):function(t){return function(e){return sn(e,t)}}(t)}var rc=Io(),nc=Io(!0);function oc(){return[]}function ic(){return!1}var uc=Co((function(t,e){return t+e}),0),ac=Lo("ceil"),cc=Co((function(t,e){return t/e}),1),lc=Lo("floor");var fc,sc=Co((function(t,e){return t*e}),1),pc=Lo("round"),vc=Co((function(t,e){return t-e}),0);return xr.after=function(t,e){if("function"!=typeof e)throw new mt(i);return t=na(t),function(){if(--t<1)return e.apply(this,arguments)}},xr.ary=yu,xr.assign=ca,xr.assignIn=la,xr.assignInWith=fa,xr.assignWith=sa,xr.at=pa,xr.before=gu,xr.bind=mu,xr.bindAll=za,xr.bindKey=Du,xr.castArray=function(){if(!arguments.length)return[];var t=arguments[0];return Pu(t)?t:[t]},xr.chain=eu,xr.chunk=function(t,e,r){e=(r?ci(t,e,r):void 0===e)?1:ir(na(e),0);var o=null==t?0:t.length;if(!o||e<1)return[];for(var i=0,u=0,a=n(Ye(o/e));io?0:o+r),(n=void 0===n||n>o?o:na(n))<0&&(n+=o),n=r>n?0:oa(n);r>>0)?(t=aa(t))&&("string"==typeof e||null!=e&&!Qu(e))&&!(e=Kn(e))&&Me(t)?lo(Ve(t),0,r):t.split(e,r):[]},xr.spread=function(t,e){if("function"!=typeof t)throw new mt(i);return e=null==e?0:ir(na(e),0),Tn((function(r){var n=r[e],o=lo(r,0,e);return n&&de(o,n),ie(t,this,o)}))},xr.tail=function(t){var e=null==t?0:t.length;return e?Gn(t,1,e):[]},xr.take=function(t,e,r){return t&&t.length?Gn(t,0,(e=r||void 0===e?1:na(e))<0?0:e):[]},xr.takeRight=function(t,e,r){var n=null==t?0:t.length;return n?Gn(t,(e=n-(e=r||void 0===e?1:na(e)))<0?0:e,n):[]},xr.takeRightWhile=function(t,e){return t&&t.length?eo(t,Ko(e,3),!1,!0):[]},xr.takeWhile=function(t,e){return t&&t.length?eo(t,Ko(e,3)):[]},xr.tap=function(t,e){return e(t),t},xr.throttle=function(t,e,r){var n=!0,o=!0;if("function"!=typeof t)throw new mt(i);return $u(r)&&(n="leading"in r?!!r.leading:n,o="trailing"in r?!!r.trailing:o),_u(t,e,{leading:n,maxWait:e,trailing:o})},xr.thru=ru,xr.toArray=ea,xr.toPairs=xa,xr.toPairsIn=Oa,xr.toPath=function(t){return Pu(t)?ve(t,Ai):Ku(t)?[t]:mo(ji(aa(t)))},xr.toPlainObject=ua,xr.transform=function(t,e,r){var n=Pu(t),o=n||Lu(t)||Yu(t);if(e=Ko(e,4),null==r){var i=t&&t.constructor;r=o?n?new i:[]:$u(t)&&Wu(i)?Or(Gt(t)):{}}return(o?ae:cn)(t,(function(t,n,o){return e(r,t,n,o)})),r},xr.unary=function(t){return yu(t,1)},xr.union=qi,xr.unionBy=Gi,xr.unionWith=Vi,xr.uniq=function(t){return t&&t.length?Yn(t):[]},xr.uniqBy=function(t,e){return t&&t.length?Yn(t,Ko(e,2)):[]},xr.uniqWith=function(t,e){return e="function"==typeof e?e:void 0,t&&t.length?Yn(t,void 0,e):[]},xr.unset=function(t,e){return null==t||Xn(t,e)},xr.unzip=Hi,xr.unzipWith=Qi,xr.update=function(t,e,r){return null==t?t:to(t,e,uo(r))},xr.updateWith=function(t,e,r,n){return n="function"==typeof n?n:void 0,null==t?t:to(t,e,uo(r),n)},xr.values=Sa,xr.valuesIn=function(t){return null==t?[]:Ce(t,ba(t))},xr.without=Ji,xr.words=Wa,xr.wrap=function(t,e){return Au(uo(e),t)},xr.xor=Zi,xr.xorBy=Ki,xr.xorWith=Yi,xr.zip=Xi,xr.zipObject=function(t,e){return oo(t||[],e||[],zr)},xr.zipObjectDeep=function(t,e){return oo(t||[],e||[],Un)},xr.zipWith=tu,xr.entries=xa,xr.entriesIn=Oa,xr.extend=la,xr.extendWith=fa,Za(xr,xr),xr.add=uc,xr.attempt=Ua,xr.camelCase=ka,xr.capitalize=Ca,xr.ceil=ac,xr.clamp=function(t,e,r){return void 0===r&&(r=e,e=void 0),void 0!==r&&(r=(r=ia(r))==r?r:0),void 0!==e&&(e=(e=ia(e))==e?e:0),Qr(ia(t),e,r)},xr.clone=function(t){return Jr(t,4)},xr.cloneDeep=function(t){return Jr(t,5)},xr.cloneDeepWith=function(t,e){return Jr(t,5,e="function"==typeof e?e:void 0)},xr.cloneWith=function(t,e){return Jr(t,4,e="function"==typeof e?e:void 0)},xr.conformsTo=function(t,e){return null==e||Zr(t,e,_a(e))},xr.deburr=Na,xr.defaultTo=function(t,e){return null==t||t!=t?e:t},xr.divide=cc,xr.endsWith=function(t,e,r){t=aa(t),e=Kn(e);var n=t.length,o=r=void 0===r?n:Qr(na(r),0,n);return(r-=e.length)>=0&&t.slice(r,o)==e},xr.eq=Su,xr.escape=function(t){return(t=aa(t))&&M.test(t)?t.replace(L,Le):t},xr.escapeRegExp=function(t){return(t=aa(t))&&H.test(t)?t.replace(V,"\\$&"):t},xr.every=function(t,e,r){var n=Pu(t)?le:en;return r&&ci(t,e,r)&&(e=void 0),n(t,Ko(e,3))},xr.find=iu,xr.findIndex=Ni,xr.findKey=function(t,e){return De(t,Ko(e,3),cn)},xr.findLast=uu,xr.findLastIndex=Pi,xr.findLastKey=function(t,e){return De(t,Ko(e,3),ln)},xr.floor=lc,xr.forEach=au,xr.forEachRight=cu,xr.forIn=function(t,e){return null==t?t:un(t,Ko(e,3),ba)},xr.forInRight=function(t,e){return null==t?t:an(t,Ko(e,3),ba)},xr.forOwn=function(t,e){return t&&cn(t,Ko(e,3))},xr.forOwnRight=function(t,e){return t&&ln(t,Ko(e,3))},xr.get=ha,xr.gt=ku,xr.gte=Cu,xr.has=function(t,e){return null!=t&&oi(t,e,hn)},xr.hasIn=ya,xr.head=Ri,xr.identity=Va,xr.includes=function(t,e,r,n){t=Ru(t)?t:Sa(t),r=r&&!n?na(r):0;var o=t.length;return r<0&&(r=ir(o+r,0)),Zu(t)?r<=o&&t.indexOf(e,r)>-1:!!o&&be(t,e,r)>-1},xr.indexOf=function(t,e,r){var n=null==t?0:t.length;if(!n)return-1;var o=null==r?0:na(r);return o<0&&(o=ir(n+o,0)),be(t,e,o)},xr.inRange=function(t,e,r){return e=ra(e),void 0===r?(r=e,e=0):r=ra(r),function(t,e,r){return t>=ur(e,r)&&t=-9007199254740991&&t<=9007199254740991},xr.isSet=Ju,xr.isString=Zu,xr.isSymbol=Ku,xr.isTypedArray=Yu,xr.isUndefined=function(t){return void 0===t},xr.isWeakMap=function(t){return qu(t)&&ni(t)==E},xr.isWeakSet=function(t){return qu(t)&&"[object WeakSet]"==vn(t)},xr.join=function(t,e){return null==t?"":nr.call(t,e)},xr.kebabCase=Pa,xr.last=Mi,xr.lastIndexOf=function(t,e,r){var n=null==t?0:t.length;if(!n)return-1;var o=n;return void 0!==r&&(o=(o=na(r))<0?ir(n+o,0):ur(o,n-1)),e==e?function(t,e,r){for(var n=r+1;n--;)if(t[n]===e)return n;return n}(t,e,o):_e(t,we,o,!0)},xr.lowerCase=Ia,xr.lowerFirst=Ra,xr.lt=Xu,xr.lte=ta,xr.max=function(t){return t&&t.length?rn(t,Va,dn):void 0},xr.maxBy=function(t,e){return t&&t.length?rn(t,Ko(e,2),dn):void 0},xr.mean=function(t){return Fe(t,Va)},xr.meanBy=function(t,e){return Fe(t,Ko(e,2))},xr.min=function(t){return t&&t.length?rn(t,Va,An):void 0},xr.minBy=function(t,e){return t&&t.length?rn(t,Ko(e,2),An):void 0},xr.stubArray=oc,xr.stubFalse=ic,xr.stubObject=function(){return{}},xr.stubString=function(){return""},xr.stubTrue=function(){return!0},xr.multiply=sc,xr.nth=function(t,e){return t&&t.length?Cn(t,na(e)):void 0},xr.noConflict=function(){return Ht._===this&&(Ht._=St),this},xr.noop=Ka,xr.now=hu,xr.pad=function(t,e,r){t=aa(t);var n=(e=na(e))?Ge(t):0;if(!e||n>=e)return t;var o=(e-n)/2;return Po(Xe(o),r)+t+Po(Ye(o),r)},xr.padEnd=function(t,e,r){t=aa(t);var n=(e=na(e))?Ge(t):0;return e&&ne){var n=t;t=e,e=n}if(r||t%1||e%1){var o=lr();return ur(t+o*(e-t+$t("1e-"+((o+"").length-1))),e)}return Bn(t,e)},xr.reduce=function(t,e,r){var n=Pu(t)?he:xe,o=arguments.length<3;return n(t,Ko(e,4),r,o,Xr)},xr.reduceRight=function(t,e,r){var n=Pu(t)?ye:xe,o=arguments.length<3;return n(t,Ko(e,4),r,o,tn)},xr.repeat=function(t,e,r){return e=(r?ci(t,e,r):void 0===e)?1:na(e),Ln(aa(t),e)},xr.replace=function(){var t=arguments,e=aa(t[0]);return t.length<3?e:e.replace(t[1],t[2])},xr.result=function(t,e,r){var n=-1,o=(e=ao(e,t)).length;for(o||(o=1,t=void 0);++n9007199254740991)return[];var r=4294967295,n=ur(t,4294967295);t-=4294967295;for(var o=Se(n,e=Ko(e));++r=i)return t;var a=r-Ge(n);if(a<1)return n;var c=u?lo(u,0,a).join(""):t.slice(0,a);if(void 0===o)return c+n;if(u&&(a+=c.length-a),Qu(o)){if(t.slice(a).search(o)){var l,f=c;for(o.global||(o=yt(o.source,aa(nt.exec(o))+"g")),o.lastIndex=0;l=o.exec(f);)var s=l.index;c=c.slice(0,void 0===s?a:s)}}else if(t.indexOf(Kn(o),a)!=a){var p=c.lastIndexOf(o);p>-1&&(c=c.slice(0,p))}return c+n},xr.unescape=function(t){return(t=aa(t))&&T.test(t)?t.replace(B,He):t},xr.uniqueId=function(t){var e=++jt;return aa(t)+e},xr.upperCase=Ta,xr.upperFirst=Ma,xr.each=au,xr.eachRight=cu,xr.first=Ri,Za(xr,(fc={},cn(xr,(function(t,e){Ft.call(xr.prototype,e)||(fc[e]=t)})),fc),{chain:!1}),xr.VERSION="4.17.15",ae(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(t){xr[t].placeholder=xr})),ae(["drop","take"],(function(t,e){Cr.prototype[t]=function(r){r=void 0===r?1:ir(na(r),0);var n=this.__filtered__&&!e?new Cr(this):this.clone();return n.__filtered__?n.__takeCount__=ur(r,n.__takeCount__):n.__views__.push({size:ur(r,4294967295),type:t+(n.__dir__<0?"Right":"")}),n},Cr.prototype[t+"Right"]=function(e){return this.reverse()[t](e).reverse()}})),ae(["filter","map","takeWhile"],(function(t,e){var r=e+1,n=1==r||3==r;Cr.prototype[t]=function(t){var e=this.clone();return e.__iteratees__.push({iteratee:Ko(t,3),type:r}),e.__filtered__=e.__filtered__||n,e}})),ae(["head","last"],(function(t,e){var r="take"+(e?"Right":"");Cr.prototype[t]=function(){return this[r](1).value()[0]}})),ae(["initial","tail"],(function(t,e){var r="drop"+(e?"":"Right");Cr.prototype[t]=function(){return this.__filtered__?new Cr(this):this[r](1)}})),Cr.prototype.compact=function(){return this.filter(Va)},Cr.prototype.find=function(t){return this.filter(t).head()},Cr.prototype.findLast=function(t){return this.reverse().find(t)},Cr.prototype.invokeMap=Tn((function(t,e){return"function"==typeof t?new Cr(this):this.map((function(r){return mn(r,t,e)}))})),Cr.prototype.reject=function(t){return this.filter(Fu(Ko(t)))},Cr.prototype.slice=function(t,e){t=na(t);var r=this;return r.__filtered__&&(t>0||e<0)?new Cr(r):(t<0?r=r.takeRight(-t):t&&(r=r.drop(t)),void 0!==e&&(r=(e=na(e))<0?r.dropRight(-e):r.take(e-t)),r)},Cr.prototype.takeRightWhile=function(t){return this.reverse().takeWhile(t).reverse()},Cr.prototype.toArray=function(){return this.take(4294967295)},cn(Cr.prototype,(function(t,e){var r=/^(?:filter|find|map|reject)|While$/.test(e),n=/^(?:head|last)$/.test(e),o=xr[n?"take"+("last"==e?"Right":""):e],i=n||/^find/.test(e);o&&(xr.prototype[e]=function(){var e=this.__wrapped__,u=n?[1]:arguments,a=e instanceof Cr,c=u[0],l=a||Pu(e),f=function(t){var e=o.apply(xr,de([t],u));return n&&s?e[0]:e};l&&r&&"function"==typeof c&&1!=c.length&&(a=l=!1);var s=this.__chain__,p=!!this.__actions__.length,v=i&&!s,d=a&&!p;if(!i&&l){e=d?e:new Cr(this);var h=t.apply(e,u);return h.__actions__.push({func:ru,args:[f],thisArg:void 0}),new kr(h,s)}return v&&d?t.apply(this,u):(h=this.thru(f),v?n?h.value()[0]:h.value():h)})})),ae(["pop","push","shift","sort","splice","unshift"],(function(t){var e=Dt[t],r=/^(?:push|sort|unshift)$/.test(t)?"tap":"thru",n=/^(?:pop|shift)$/.test(t);xr.prototype[t]=function(){var t=arguments;if(n&&!this.__chain__){var o=this.value();return e.apply(Pu(o)?o:[],t)}return this[r]((function(r){return e.apply(Pu(r)?r:[],t)}))}})),cn(Cr.prototype,(function(t,e){var r=xr[e];if(r){var n=r.name+"";Ft.call(mr,n)||(mr[n]=[]),mr[n].push({name:e,func:r})}})),mr[So(void 0,2).name]=[{name:"wrapper",func:void 0}],Cr.prototype.clone=function(){var t=new Cr(this.__wrapped__);return t.__actions__=mo(this.__actions__),t.__dir__=this.__dir__,t.__filtered__=this.__filtered__,t.__iteratees__=mo(this.__iteratees__),t.__takeCount__=this.__takeCount__,t.__views__=mo(this.__views__),t},Cr.prototype.reverse=function(){if(this.__filtered__){var t=new Cr(this);t.__dir__=-1,t.__filtered__=!0}else(t=this.clone()).__dir__*=-1;return t},Cr.prototype.value=function(){var t=this.__wrapped__.value(),e=this.__dir__,r=Pu(t),n=e<0,o=r?t.length:0,i=function(t,e,r){var n=-1,o=r.length;for(;++n=this.__values__.length;return{done:t,value:t?void 0:this.__values__[this.__index__++]}},xr.prototype.plant=function(t){for(var e,r=this;r instanceof Sr;){var n=Oi(r);n.__index__=0,n.__values__=void 0,e?o.__wrapped__=n:e=n;var o=n;r=r.__wrapped__}return o.__wrapped__=t,e},xr.prototype.reverse=function(){var t=this.__wrapped__;if(t instanceof Cr){var e=t;return this.__actions__.length&&(e=new Cr(this)),(e=e.reverse()).__actions__.push({func:ru,args:[$i],thisArg:void 0}),new kr(e,this.__chain__)}return this.thru($i)},xr.prototype.toJSON=xr.prototype.valueOf=xr.prototype.value=function(){return ro(this.__wrapped__,this.__actions__)},xr.prototype.first=xr.prototype.head,Yt&&(xr.prototype[Yt]=function(){return this}),xr}();Ht._=Qe,void 0===(o=function(){return Qe}.call(e,r,e,n))||(n.exports=o)}).call(this)}).call(this,r(76),r(456)(t))},454:function(t,e,r){"use strict";var n=r(0),o=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});e.a=o},455:function(t,e,r){"use strict";r.d(e,"a",(function(){return i}));r(77),r(473),r(439),r(78);var n=r(475),o=r.n(n);function i(t,e){var r=new o.a;return t.map((function(t){var n=t;return"string"==typeof t&&(n={label:t,permalink:"/blog/tags/"+r.slug(t)}),function(t,e){var r=t.label.split(": ",2),n=r[0],o=r[1],i="primary";switch(e){case"blog":case"guides":i=function(t){switch(t){case"domain":return"blue";case"type":return"pink";default:return"primary"}}(n)}return{category:n,count:t.count,label:t.label,permalink:t.permalink,style:i,value:o}}(n,e)}))}},456:function(t,e){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},465:function(t,e,r){var n=r(30),o=r(54),i=r(27),u=r(26),a=r(466);t.exports=function(t,e){var r=1==t,c=2==t,l=3==t,f=4==t,s=6==t,p=5==t||s,v=e||a;return function(e,a,d){for(var h,y,g=i(e),m=o(g),D=n(a,d,3),_=u(m.length),b=0,E=r?v(e,_):c?v(e,0):void 0;_>b;b++)if((p||b in m)&&(y=D(h=m[b],b,g),t))if(r)E[b]=y;else if(y)switch(t){case 3:return!0;case 5:return h;case 6:return b;case 2:E.push(h)}else if(f)return!1;return s?-1:l||f?f:E}}},466:function(t,e,r){var n=r(467);t.exports=function(t,e){return new(n(t))(e)}},467:function(t,e,r){var n=r(13),o=r(468),i=r(2)("species");t.exports=function(t){var e;return o(t)&&("function"!=typeof(e=t.constructor)||e!==Array&&!o(e.prototype)||(e=void 0),n(e)&&null===(e=e[i])&&(e=void 0)),void 0===e?Array:e}},468:function(t,e,r){var n=r(23);t.exports=Array.isArray||function(t){return"Array"==n(t)}},469:function(t,e,r){"use strict";var n=SyntaxError,o=Function,i=TypeError,u=function(t){try{return o('"use strict"; return ('+t+").constructor;")()}catch(e){}},a=Object.getOwnPropertyDescriptor;if(a)try{a({},"")}catch(x){a=null}var c=function(){throw new i},l=a?function(){try{return c}catch(t){try{return a(arguments,"callee").get}catch(e){return c}}}():c,f=r(507)(),s=Object.getPrototypeOf||function(t){return t.__proto__},p={},v="undefined"==typeof Uint8Array?void 0:s(Uint8Array),d={"%AggregateError%":"undefined"==typeof AggregateError?void 0:AggregateError,"%Array%":Array,"%ArrayBuffer%":"undefined"==typeof ArrayBuffer?void 0:ArrayBuffer,"%ArrayIteratorPrototype%":f?s([][Symbol.iterator]()):void 0,"%AsyncFromSyncIteratorPrototype%":void 0,"%AsyncFunction%":p,"%AsyncGenerator%":p,"%AsyncGeneratorFunction%":p,"%AsyncIteratorPrototype%":p,"%Atomics%":"undefined"==typeof Atomics?void 0:Atomics,"%BigInt%":"undefined"==typeof BigInt?void 0:BigInt,"%Boolean%":Boolean,"%DataView%":"undefined"==typeof DataView?void 0:DataView,"%Date%":Date,"%decodeURI%":decodeURI,"%decodeURIComponent%":decodeURIComponent,"%encodeURI%":encodeURI,"%encodeURIComponent%":encodeURIComponent,"%Error%":Error,"%eval%":eval,"%EvalError%":EvalError,"%Float32Array%":"undefined"==typeof Float32Array?void 0:Float32Array,"%Float64Array%":"undefined"==typeof Float64Array?void 0:Float64Array,"%FinalizationRegistry%":"undefined"==typeof FinalizationRegistry?void 0:FinalizationRegistry,"%Function%":o,"%GeneratorFunction%":p,"%Int8Array%":"undefined"==typeof Int8Array?void 0:Int8Array,"%Int16Array%":"undefined"==typeof Int16Array?void 0:Int16Array,"%Int32Array%":"undefined"==typeof Int32Array?void 0:Int32Array,"%isFinite%":isFinite,"%isNaN%":isNaN,"%IteratorPrototype%":f?s(s([][Symbol.iterator]())):void 0,"%JSON%":"object"==typeof JSON?JSON:void 0,"%Map%":"undefined"==typeof Map?void 0:Map,"%MapIteratorPrototype%":"undefined"!=typeof Map&&f?s((new Map)[Symbol.iterator]()):void 0,"%Math%":Math,"%Number%":Number,"%Object%":Object,"%parseFloat%":parseFloat,"%parseInt%":parseInt,"%Promise%":"undefined"==typeof Promise?void 0:Promise,"%Proxy%":"undefined"==typeof Proxy?void 0:Proxy,"%RangeError%":RangeError,"%ReferenceError%":ReferenceError,"%Reflect%":"undefined"==typeof Reflect?void 0:Reflect,"%RegExp%":RegExp,"%Set%":"undefined"==typeof Set?void 0:Set,"%SetIteratorPrototype%":"undefined"!=typeof Set&&f?s((new Set)[Symbol.iterator]()):void 0,"%SharedArrayBuffer%":"undefined"==typeof SharedArrayBuffer?void 0:SharedArrayBuffer,"%String%":String,"%StringIteratorPrototype%":f?s(""[Symbol.iterator]()):void 0,"%Symbol%":f?Symbol:void 0,"%SyntaxError%":n,"%ThrowTypeError%":l,"%TypedArray%":v,"%TypeError%":i,"%Uint8Array%":"undefined"==typeof Uint8Array?void 0:Uint8Array,"%Uint8ClampedArray%":"undefined"==typeof Uint8ClampedArray?void 0:Uint8ClampedArray,"%Uint16Array%":"undefined"==typeof Uint16Array?void 0:Uint16Array,"%Uint32Array%":"undefined"==typeof Uint32Array?void 0:Uint32Array,"%URIError%":URIError,"%WeakMap%":"undefined"==typeof WeakMap?void 0:WeakMap,"%WeakRef%":"undefined"==typeof WeakRef?void 0:WeakRef,"%WeakSet%":"undefined"==typeof WeakSet?void 0:WeakSet},h={"%ArrayBufferPrototype%":["ArrayBuffer","prototype"],"%ArrayPrototype%":["Array","prototype"],"%ArrayProto_entries%":["Array","prototype","entries"],"%ArrayProto_forEach%":["Array","prototype","forEach"],"%ArrayProto_keys%":["Array","prototype","keys"],"%ArrayProto_values%":["Array","prototype","values"],"%AsyncFunctionPrototype%":["AsyncFunction","prototype"],"%AsyncGenerator%":["AsyncGeneratorFunction","prototype"],"%AsyncGeneratorPrototype%":["AsyncGeneratorFunction","prototype","prototype"],"%BooleanPrototype%":["Boolean","prototype"],"%DataViewPrototype%":["DataView","prototype"],"%DatePrototype%":["Date","prototype"],"%ErrorPrototype%":["Error","prototype"],"%EvalErrorPrototype%":["EvalError","prototype"],"%Float32ArrayPrototype%":["Float32Array","prototype"],"%Float64ArrayPrototype%":["Float64Array","prototype"],"%FunctionPrototype%":["Function","prototype"],"%Generator%":["GeneratorFunction","prototype"],"%GeneratorPrototype%":["GeneratorFunction","prototype","prototype"],"%Int8ArrayPrototype%":["Int8Array","prototype"],"%Int16ArrayPrototype%":["Int16Array","prototype"],"%Int32ArrayPrototype%":["Int32Array","prototype"],"%JSONParse%":["JSON","parse"],"%JSONStringify%":["JSON","stringify"],"%MapPrototype%":["Map","prototype"],"%NumberPrototype%":["Number","prototype"],"%ObjectPrototype%":["Object","prototype"],"%ObjProto_toString%":["Object","prototype","toString"],"%ObjProto_valueOf%":["Object","prototype","valueOf"],"%PromisePrototype%":["Promise","prototype"],"%PromiseProto_then%":["Promise","prototype","then"],"%Promise_all%":["Promise","all"],"%Promise_reject%":["Promise","reject"],"%Promise_resolve%":["Promise","resolve"],"%RangeErrorPrototype%":["RangeError","prototype"],"%ReferenceErrorPrototype%":["ReferenceError","prototype"],"%RegExpPrototype%":["RegExp","prototype"],"%SetPrototype%":["Set","prototype"],"%SharedArrayBufferPrototype%":["SharedArrayBuffer","prototype"],"%StringPrototype%":["String","prototype"],"%SymbolPrototype%":["Symbol","prototype"],"%SyntaxErrorPrototype%":["SyntaxError","prototype"],"%TypedArrayPrototype%":["TypedArray","prototype"],"%TypeErrorPrototype%":["TypeError","prototype"],"%Uint8ArrayPrototype%":["Uint8Array","prototype"],"%Uint8ClampedArrayPrototype%":["Uint8ClampedArray","prototype"],"%Uint16ArrayPrototype%":["Uint16Array","prototype"],"%Uint32ArrayPrototype%":["Uint32Array","prototype"],"%URIErrorPrototype%":["URIError","prototype"],"%WeakMapPrototype%":["WeakMap","prototype"],"%WeakSetPrototype%":["WeakSet","prototype"]},y=r(470),g=r(510),m=y.call(Function.call,Array.prototype.concat),D=y.call(Function.apply,Array.prototype.splice),_=y.call(Function.call,String.prototype.replace),b=y.call(Function.call,String.prototype.slice),E=y.call(Function.call,RegExp.prototype.exec),w=/[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g,F=/\\(\\)?/g,j=function(t){var e=b(t,0,1),r=b(t,-1);if("%"===e&&"%"!==r)throw new n("invalid intrinsic syntax, expected closing `%`");if("%"===r&&"%"!==e)throw new n("invalid intrinsic syntax, expected opening `%`");var o=[];return _(t,w,(function(t,e,r,n){o[o.length]=r?_(n,F,"$1"):e||t})),o},A=function(t,e){var r,o=t;if(g(h,o)&&(o="%"+(r=h[o])[0]+"%"),g(d,o)){var a=d[o];if(a===p&&(a=function t(e){var r;if("%AsyncFunction%"===e)r=u("async function () {}");else if("%GeneratorFunction%"===e)r=u("function* () {}");else if("%AsyncGeneratorFunction%"===e)r=u("async function* () {}");else if("%AsyncGenerator%"===e){var n=t("%AsyncGeneratorFunction%");n&&(r=n.prototype)}else if("%AsyncIteratorPrototype%"===e){var o=t("%AsyncGenerator%");o&&(r=s(o.prototype))}return d[e]=r,r}(o)),void 0===a&&!e)throw new i("intrinsic "+t+" exists, but is not available. Please file an issue!");return{alias:r,name:o,value:a}}throw new n("intrinsic "+t+" does not exist!")};t.exports=function(t,e){if("string"!=typeof t||0===t.length)throw new i("intrinsic name must be a non-empty string");if(arguments.length>1&&"boolean"!=typeof e)throw new i('"allowMissing" argument must be a boolean');if(null===E(/^%?[^%]*%?$/,t))throw new n("`%` may not be present anywhere but at the beginning and end of the intrinsic name");var r=j(t),o=r.length>0?r[0]:"",u=A("%"+o+"%",e),c=u.name,l=u.value,f=!1,s=u.alias;s&&(o=s[0],D(r,m([0,1],s)));for(var p=1,v=!0;p=r.length){var w=a(l,h);l=(v=!!w)&&"get"in w&&!("originalValue"in w.get)?w.get:l[h]}else v=g(l,h),l=l[h];v&&!f&&(d[c]=l)}}return l}},470:function(t,e,r){"use strict";var n=r(509);t.exports=Function.prototype.bind||n},471:function(t,e,r){"use strict";var n=String.prototype.replace,o=/%20/g,i="RFC1738",u="RFC3986";t.exports={default:u,formatters:{RFC1738:function(t){return n.call(t,o,"+")},RFC3986:function(t){return String(t)}},RFC1738:i,RFC3986:u}},474:function(t,e,r){"use strict";var n=r(0),o=r.n(n),i=r(430),u=r(423),a=r.n(u);e.a=function(t){var e=t.count,r=t.label,n=t.permalink,u=t.style,c=t.value,l=t.valueOnly;return o.a.createElement(i.a,{to:n+"/",className:a()("badge","badge--rounded","badge--"+u)},l?c:r,e&&o.a.createElement(o.a.Fragment,null," (",e,")"))}},475:function(t,e,r){var n=r(476);t.exports=a;var o=Object.hasOwnProperty,i=/\s/g,u=/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~\u2019]/g;function a(){if(!(this instanceof a))return new a;this.reset()}function c(t,e){return"string"!=typeof t?"":(e||(t=t.toLowerCase()),t.trim().replace(u,"").replace(n(),"").replace(i,"-"))}a.prototype.slug=function(t,e){for(var r=c(t,!0===e),n=r;o.call(this.occurrences,r);)this.occurrences[n]++,r=n+"-"+this.occurrences[n];return this.occurrences[r]=0,r},a.prototype.reset=function(){this.occurrences=Object.create(null)},a.slug=c},476:function(t,e){t.exports=function(){return/[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD79\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED0\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3]|\uD83E[\uDD10-\uDD18\uDD80-\uDD84\uDDC0]|\uD83C\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uD83C\uDDFE\uD83C[\uDDEA\uDDF9]|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDFC\uD83C[\uDDEB\uDDF8]|\uD83C\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uD83C\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF8\uDDFE\uDDFF]|\uD83C\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uD83C\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uD83C\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uD83C\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uD83C\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uD83C\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uD83C\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uD83C\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uD83C\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uD83C\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uD83C\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uD83C\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uD83C\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uD83C\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uD83C\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uD83C\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|[#\*0-9]\u20E3/g}},478:function(t,e,r){"use strict";var n=r(471),o=Object.prototype.hasOwnProperty,i=Array.isArray,u=function(){for(var t=[],e=0;e<256;++e)t.push("%"+((e<16?"0":"")+e.toString(16)).toUpperCase());return t}(),a=function(t,e){for(var r=e&&e.plainObjects?Object.create(null):{},n=0;n1;){var e=t.pop(),r=e.obj[e.prop];if(i(r)){for(var n=[],o=0;o=48&&f<=57||f>=65&&f<=90||f>=97&&f<=122||i===n.RFC1738&&(40===f||41===f)?c+=a.charAt(l):f<128?c+=u[f]:f<2048?c+=u[192|f>>6]+u[128|63&f]:f<55296||f>=57344?c+=u[224|f>>12]+u[128|f>>6&63]+u[128|63&f]:(l+=1,f=65536+((1023&f)<<10|1023&a.charCodeAt(l)),c+=u[240|f>>18]+u[128|f>>12&63]+u[128|f>>6&63]+u[128|63&f])}return c},isBuffer:function(t){return!(!t||"object"!=typeof t)&&!!(t.constructor&&t.constructor.isBuffer&&t.constructor.isBuffer(t))},isRegExp:function(t){return"[object RegExp]"===Object.prototype.toString.call(t)},maybeMap:function(t,e){if(i(t)){for(var r=[],n=0;n0?j.join(",")||null:void 0}];else if(c(v))I=v;else{var B=Object.keys(j);I=y?B.sort(y):B}for(var L=u&&c(j)&&1===j.length?r+"[]":r,T=0;T0?b+_:""}},506:function(t,e,r){"use strict";var n=r(469),o=r(511),i=r(513),u=n("%TypeError%"),a=n("%WeakMap%",!0),c=n("%Map%",!0),l=o("WeakMap.prototype.get",!0),f=o("WeakMap.prototype.set",!0),s=o("WeakMap.prototype.has",!0),p=o("Map.prototype.get",!0),v=o("Map.prototype.set",!0),d=o("Map.prototype.has",!0),h=function(t,e){for(var r,n=t;null!==(r=n.next);n=r)if(r.key===e)return n.next=r.next,r.next=t.next,t.next=r,r};t.exports=function(){var t,e,r,n={assert:function(t){if(!n.has(t))throw new u("Side channel does not contain "+i(t))},get:function(n){if(a&&n&&("object"==typeof n||"function"==typeof n)){if(t)return l(t,n)}else if(c){if(e)return p(e,n)}else if(r)return function(t,e){var r=h(t,e);return r&&r.value}(r,n)},has:function(n){if(a&&n&&("object"==typeof n||"function"==typeof n)){if(t)return s(t,n)}else if(c){if(e)return d(e,n)}else if(r)return function(t,e){return!!h(t,e)}(r,n);return!1},set:function(n,o){a&&n&&("object"==typeof n||"function"==typeof n)?(t||(t=new a),f(t,n,o)):c?(e||(e=new c),v(e,n,o)):(r||(r={key:{},next:null}),function(t,e,r){var n=h(t,e);n?n.value=r:t.next={key:e,next:t.next,value:r}}(r,n,o))}};return n}},507:function(t,e,r){"use strict";var n="undefined"!=typeof Symbol&&Symbol,o=r(508);t.exports=function(){return"function"==typeof n&&("function"==typeof Symbol&&("symbol"==typeof n("foo")&&("symbol"==typeof Symbol("bar")&&o())))}},508:function(t,e,r){"use strict";t.exports=function(){if("function"!=typeof Symbol||"function"!=typeof Object.getOwnPropertySymbols)return!1;if("symbol"==typeof Symbol.iterator)return!0;var t={},e=Symbol("test"),r=Object(e);if("string"==typeof e)return!1;if("[object Symbol]"!==Object.prototype.toString.call(e))return!1;if("[object Symbol]"!==Object.prototype.toString.call(r))return!1;for(e in t[e]=42,t)return!1;if("function"==typeof Object.keys&&0!==Object.keys(t).length)return!1;if("function"==typeof Object.getOwnPropertyNames&&0!==Object.getOwnPropertyNames(t).length)return!1;var n=Object.getOwnPropertySymbols(t);if(1!==n.length||n[0]!==e)return!1;if(!Object.prototype.propertyIsEnumerable.call(t,e))return!1;if("function"==typeof Object.getOwnPropertyDescriptor){var o=Object.getOwnPropertyDescriptor(t,e);if(42!==o.value||!0!==o.enumerable)return!1}return!0}},509:function(t,e,r){"use strict";var n="Function.prototype.bind called on incompatible ",o=Array.prototype.slice,i=Object.prototype.toString;t.exports=function(t){var e=this;if("function"!=typeof e||"[object Function]"!==i.call(e))throw new TypeError(n+e);for(var r,u=o.call(arguments,1),a=function(){if(this instanceof r){var n=e.apply(this,u.concat(o.call(arguments)));return Object(n)===n?n:this}return e.apply(t,u.concat(o.call(arguments)))},c=Math.max(0,e.length-u.length),l=[],f=0;f-1?o(r):r}},512:function(t,e,r){"use strict";var n=r(470),o=r(469),i=o("%Function.prototype.apply%"),u=o("%Function.prototype.call%"),a=o("%Reflect.apply%",!0)||n.call(u,i),c=o("%Object.getOwnPropertyDescriptor%",!0),l=o("%Object.defineProperty%",!0),f=o("%Math.max%");if(l)try{l({},"a",{value:1})}catch(p){l=null}t.exports=function(t){var e=a(n,u,arguments);if(c&&l){var r=c(e,"length");r.configurable&&l(e,"length",{value:1+f(0,t.length-(arguments.length-1))})}return e};var s=function(){return a(n,i,arguments)};l?l(t.exports,"apply",{value:s}):t.exports.apply=s},513:function(t,e,r){var n="function"==typeof Map&&Map.prototype,o=Object.getOwnPropertyDescriptor&&n?Object.getOwnPropertyDescriptor(Map.prototype,"size"):null,i=n&&o&&"function"==typeof o.get?o.get:null,u=n&&Map.prototype.forEach,a="function"==typeof Set&&Set.prototype,c=Object.getOwnPropertyDescriptor&&a?Object.getOwnPropertyDescriptor(Set.prototype,"size"):null,l=a&&c&&"function"==typeof c.get?c.get:null,f=a&&Set.prototype.forEach,s="function"==typeof WeakMap&&WeakMap.prototype?WeakMap.prototype.has:null,p="function"==typeof WeakSet&&WeakSet.prototype?WeakSet.prototype.has:null,v="function"==typeof WeakRef&&WeakRef.prototype?WeakRef.prototype.deref:null,d=Boolean.prototype.valueOf,h=Object.prototype.toString,y=Function.prototype.toString,g=String.prototype.match,m=String.prototype.slice,D=String.prototype.replace,_=String.prototype.toUpperCase,b=String.prototype.toLowerCase,E=RegExp.prototype.test,w=Array.prototype.concat,F=Array.prototype.join,j=Array.prototype.slice,A=Math.floor,x="function"==typeof BigInt?BigInt.prototype.valueOf:null,O=Object.getOwnPropertySymbols,S="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?Symbol.prototype.toString:null,k="function"==typeof Symbol&&"object"==typeof Symbol.iterator,C="function"==typeof Symbol&&Symbol.toStringTag&&(typeof Symbol.toStringTag===k||"symbol")?Symbol.toStringTag:null,N=Object.prototype.propertyIsEnumerable,P=("function"==typeof Reflect?Reflect.getPrototypeOf:Object.getPrototypeOf)||([].__proto__===Array.prototype?function(t){return t.__proto__}:null);function I(t,e){if(t===1/0||t===-1/0||t!=t||t&&t>-1e3&&t<1e3||E.call(/e/,e))return e;var r=/[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;if("number"==typeof t){var n=t<0?-A(-t):A(t);if(n!==t){var o=String(n),i=m.call(e,o.length+1);return D.call(o,r,"$&_")+"."+D.call(D.call(i,/([0-9]{3})/g,"$&_"),/_$/,"")}}return D.call(e,r,"$&_")}var R=r(514),B=R.custom,L=z(B)?B:null;function T(t,e,r){var n="double"===(r.quoteStyle||e)?'"':"'";return n+t+n}function M(t){return D.call(String(t),/"/g,""")}function W(t){return!("[object Array]"!==G(t)||C&&"object"==typeof t&&C in t)}function U(t){return!("[object RegExp]"!==G(t)||C&&"object"==typeof t&&C in t)}function z(t){if(k)return t&&"object"==typeof t&&t instanceof Symbol;if("symbol"==typeof t)return!0;if(!t||"object"!=typeof t||!S)return!1;try{return S.call(t),!0}catch(e){}return!1}t.exports=function t(e,r,n,o){var a=r||{};if(q(a,"quoteStyle")&&"single"!==a.quoteStyle&&"double"!==a.quoteStyle)throw new TypeError('option "quoteStyle" must be "single" or "double"');if(q(a,"maxStringLength")&&("number"==typeof a.maxStringLength?a.maxStringLength<0&&a.maxStringLength!==1/0:null!==a.maxStringLength))throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`');var c=!q(a,"customInspect")||a.customInspect;if("boolean"!=typeof c&&"symbol"!==c)throw new TypeError("option \"customInspect\", if provided, must be `true`, `false`, or `'symbol'`");if(q(a,"indent")&&null!==a.indent&&"\t"!==a.indent&&!(parseInt(a.indent,10)===a.indent&&a.indent>0))throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`');if(q(a,"numericSeparator")&&"boolean"!=typeof a.numericSeparator)throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`');var h=a.numericSeparator;if(void 0===e)return"undefined";if(null===e)return"null";if("boolean"==typeof e)return e?"true":"false";if("string"==typeof e)return function t(e,r){if(e.length>r.maxStringLength){var n=e.length-r.maxStringLength,o="... "+n+" more character"+(n>1?"s":"");return t(m.call(e,0,r.maxStringLength),r)+o}return T(D.call(D.call(e,/(['\\])/g,"\\$1"),/[\x00-\x1f]/g,H),"single",r)}(e,a);if("number"==typeof e){if(0===e)return 1/0/e>0?"0":"-0";var _=String(e);return h?I(e,_):_}if("bigint"==typeof e){var E=String(e)+"n";return h?I(e,E):E}var A=void 0===a.depth?5:a.depth;if(void 0===n&&(n=0),n>=A&&A>0&&"object"==typeof e)return W(e)?"[Array]":"[Object]";var O=function(t,e){var r;if("\t"===t.indent)r="\t";else{if(!("number"==typeof t.indent&&t.indent>0))return null;r=F.call(Array(t.indent+1)," ")}return{base:r,prev:F.call(Array(e+1),r)}}(a,n);if(void 0===o)o=[];else if(V(o,e)>=0)return"[Circular]";function B(e,r,i){if(r&&(o=j.call(o)).push(r),i){var u={depth:a.depth};return q(a,"quoteStyle")&&(u.quoteStyle=a.quoteStyle),t(e,u,n+1,o)}return t(e,a,n+1,o)}if("function"==typeof e&&!U(e)){var $=function(t){if(t.name)return t.name;var e=g.call(y.call(t),/^function\s*([\w$]+)/);if(e)return e[1];return null}(e),X=Y(e,B);return"[Function"+($?": "+$:" (anonymous)")+"]"+(X.length>0?" { "+F.call(X,", ")+" }":"")}if(z(e)){var tt=k?D.call(String(e),/^(Symbol\(.*\))_[^)]*$/,"$1"):S.call(e);return"object"!=typeof e||k?tt:Q(tt)}if(function(t){if(!t||"object"!=typeof t)return!1;if("undefined"!=typeof HTMLElement&&t instanceof HTMLElement)return!0;return"string"==typeof t.nodeName&&"function"==typeof t.getAttribute}(e)){for(var et="<"+b.call(String(e.nodeName)),rt=e.attributes||[],nt=0;nt"}if(W(e)){if(0===e.length)return"[]";var ot=Y(e,B);return O&&!function(t){for(var e=0;e=0)return!1;return!0}(ot)?"["+K(ot,O)+"]":"[ "+F.call(ot,", ")+" ]"}if(function(t){return!("[object Error]"!==G(t)||C&&"object"==typeof t&&C in t)}(e)){var it=Y(e,B);return"cause"in Error.prototype||!("cause"in e)||N.call(e,"cause")?0===it.length?"["+String(e)+"]":"{ ["+String(e)+"] "+F.call(it,", ")+" }":"{ ["+String(e)+"] "+F.call(w.call("[cause]: "+B(e.cause),it),", ")+" }"}if("object"==typeof e&&c){if(L&&"function"==typeof e[L]&&R)return R(e,{depth:A-n});if("symbol"!==c&&"function"==typeof e.inspect)return e.inspect()}if(function(t){if(!i||!t||"object"!=typeof t)return!1;try{i.call(t);try{l.call(t)}catch(et){return!0}return t instanceof Map}catch(e){}return!1}(e)){var ut=[];return u.call(e,(function(t,r){ut.push(B(r,e,!0)+" => "+B(t,e))})),Z("Map",i.call(e),ut,O)}if(function(t){if(!l||!t||"object"!=typeof t)return!1;try{l.call(t);try{i.call(t)}catch(e){return!0}return t instanceof Set}catch(r){}return!1}(e)){var at=[];return f.call(e,(function(t){at.push(B(t,e))})),Z("Set",l.call(e),at,O)}if(function(t){if(!s||!t||"object"!=typeof t)return!1;try{s.call(t,s);try{p.call(t,p)}catch(et){return!0}return t instanceof WeakMap}catch(e){}return!1}(e))return J("WeakMap");if(function(t){if(!p||!t||"object"!=typeof t)return!1;try{p.call(t,p);try{s.call(t,s)}catch(et){return!0}return t instanceof WeakSet}catch(e){}return!1}(e))return J("WeakSet");if(function(t){if(!v||!t||"object"!=typeof t)return!1;try{return v.call(t),!0}catch(e){}return!1}(e))return J("WeakRef");if(function(t){return!("[object Number]"!==G(t)||C&&"object"==typeof t&&C in t)}(e))return Q(B(Number(e)));if(function(t){if(!t||"object"!=typeof t||!x)return!1;try{return x.call(t),!0}catch(e){}return!1}(e))return Q(B(x.call(e)));if(function(t){return!("[object Boolean]"!==G(t)||C&&"object"==typeof t&&C in t)}(e))return Q(d.call(e));if(function(t){return!("[object String]"!==G(t)||C&&"object"==typeof t&&C in t)}(e))return Q(B(String(e)));if(!function(t){return!("[object Date]"!==G(t)||C&&"object"==typeof t&&C in t)}(e)&&!U(e)){var ct=Y(e,B),lt=P?P(e)===Object.prototype:e instanceof Object||e.constructor===Object,ft=e instanceof Object?"":"null prototype",st=!lt&&C&&Object(e)===e&&C in e?m.call(G(e),8,-1):ft?"Object":"",pt=(lt||"function"!=typeof e.constructor?"":e.constructor.name?e.constructor.name+" ":"")+(st||ft?"["+F.call(w.call([],st||[],ft||[]),": ")+"] ":"");return 0===ct.length?pt+"{}":O?pt+"{"+K(ct,O)+"}":pt+"{ "+F.call(ct,", ")+" }"}return String(e)};var $=Object.prototype.hasOwnProperty||function(t){return t in this};function q(t,e){return $.call(t,e)}function G(t){return h.call(t)}function V(t,e){if(t.indexOf)return t.indexOf(e);for(var r=0,n=t.length;r-1?t.split(","):t},l=function(t,e,r,n){if(t){var i=r.allowDots?t.replace(/\.([^.[]+)/g,"[$1]"):t,u=/(\[[^[\]]*])/g,a=r.depth>0&&/(\[[^[\]]*])/.exec(i),l=a?i.slice(0,a.index):i,f=[];if(l){if(!r.plainObjects&&o.call(Object.prototype,l)&&!r.allowPrototypes)return;f.push(l)}for(var s=0;r.depth>0&&null!==(a=u.exec(i))&&s=0;--i){var u,a=t[i];if("[]"===a&&r.parseArrays)u=[].concat(o);else{u=r.plainObjects?Object.create(null):{};var l="["===a.charAt(0)&&"]"===a.charAt(a.length-1)?a.slice(1,-1):a,f=parseInt(l,10);r.parseArrays||""!==l?!isNaN(f)&&a!==l&&String(f)===l&&f>=0&&r.parseArrays&&f<=r.arrayLimit?(u=[])[f]=o:"__proto__"!==l&&(u[l]=o):u={0:o}}o=u}return o}(f,e,r,n)}};t.exports=function(t,e){var r=function(t){if(!t)return u;if(null!==t.decoder&&void 0!==t.decoder&&"function"!=typeof t.decoder)throw new TypeError("Decoder has to be a function.");if(void 0!==t.charset&&"utf-8"!==t.charset&&"iso-8859-1"!==t.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var e=void 0===t.charset?u.charset:t.charset;return{allowDots:void 0===t.allowDots?u.allowDots:!!t.allowDots,allowPrototypes:"boolean"==typeof t.allowPrototypes?t.allowPrototypes:u.allowPrototypes,allowSparse:"boolean"==typeof t.allowSparse?t.allowSparse:u.allowSparse,arrayLimit:"number"==typeof t.arrayLimit?t.arrayLimit:u.arrayLimit,charset:e,charsetSentinel:"boolean"==typeof t.charsetSentinel?t.charsetSentinel:u.charsetSentinel,comma:"boolean"==typeof t.comma?t.comma:u.comma,decoder:"function"==typeof t.decoder?t.decoder:u.decoder,delimiter:"string"==typeof t.delimiter||n.isRegExp(t.delimiter)?t.delimiter:u.delimiter,depth:"number"==typeof t.depth||!1===t.depth?+t.depth:u.depth,ignoreQueryPrefix:!0===t.ignoreQueryPrefix,interpretNumericEntities:"boolean"==typeof t.interpretNumericEntities?t.interpretNumericEntities:u.interpretNumericEntities,parameterLimit:"number"==typeof t.parameterLimit?t.parameterLimit:u.parameterLimit,parseArrays:!1!==t.parseArrays,plainObjects:"boolean"==typeof t.plainObjects?t.plainObjects:u.plainObjects,strictNullHandling:"boolean"==typeof t.strictNullHandling?t.strictNullHandling:u.strictNullHandling}}(e);if(""===t||null==t)return r.plainObjects?Object.create(null):{};for(var f="string"==typeof t?function(t,e){var r,l={},f=e.ignoreQueryPrefix?t.replace(/^\?/,""):t,s=e.parameterLimit===1/0?void 0:e.parameterLimit,p=f.split(e.delimiter,s),v=-1,d=e.charset;if(e.charsetSentinel)for(r=0;r-1&&(y=i(y)?[y]:y),o.call(l,h)?l[h]=n.combine(l[h],y):l[h]=y}return l}(t,r):t,s=r.plainObjects?Object.create(null):{},p=Object.keys(f),v=0;v \\\n --project \\\n --environment \\\n --application \\\n --commit-id ${{ github.sha }} \\\n --watch\n")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"on")," section contains a ",Object(i.b)("inlineCode",{parentName:"li"},"workflow_call")," directive. It means that this workflow will be triggered when called from another workflow.\nWe're doing this because we won't use this workflow directly. Since we might have several environments to deploy to Qovery depending on the branch, we could have one workflow per environment, and we want to avoid repeating all the steps."),Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"inputs")," and ",Object(i.b)("inlineCode",{parentName:"li"},"secrets")," sections are defining the values that we will need to pass to our workflow"),Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"jobs")," section lists the ",Object(i.b)("inlineCode",{parentName:"li"},"jobs")," and the ",Object(i.b)("inlineCode",{parentName:"li"},"steps")," that in needs to accomplish. Here we have two jobs and five steps:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"test")," where we check out the code, we install Yarn modules, and we run tests through Jest"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"deploy")," where we check out the code and deploy to Qovery.")))),Object(i.b)("p",null,"Several things worth noting:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"The organization / project / environment / application are case-sensitive."),Object(i.b)("li",{parentName:"ul"},"Our ",Object(i.b)("inlineCode",{parentName:"li"},"deploy")," job has a ",Object(i.b)("inlineCode",{parentName:"li"},"needs")," instructions, telling GitHub Actions that this job can only run when the ",Object(i.b)("inlineCode",{parentName:"li"},"test")," job succeeds."),Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"with")," section of our last ",Object(i.b)("inlineCode",{parentName:"li"},"deploy")," step contains interpolated strings: ${{ inputs.xxxx }}. Those are values passed to our workflow, that our Qovery action needs. They will be passed from the calling workflow."))),Object(i.b)("li",null,Object(i.b)("h3",{id:"get-a-qovery-api-token"},"Get a Qovery API token"),Object(i.b)("p",null,"To get an API token, use the Qovery CLI:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"qovery token\n")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Select your organization. (tokens are valid for only one organization)."),Object(i.b)("li",{parentName:"ul"},"Enter a name for your token."),Object(i.b)("li",{parentName:"ul"},"Enter a description for your token.")),Object(i.b)("p",null,"You will get an output like this one:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{}),"qovery token Qovery: ---- Never share this authentication token and keep it secure ----\nQovery: qov_xxx....\nQovery: ---- Never share this authentication token and keep it secure ----\n")),Object(i.b)(c.a,{type:"warning",mdxType:"Alert"},"At the time of writing, we don't have a way to invalidate tokens. Store it carefully.")),Object(i.b)("li",null,Object(i.b)("h3",{id:"add-your-token-to-your-github-repository-secrets"},"Add your token to your GitHub repository secrets"),Object(i.b)("p",null,"Go to your GitHub repository then to the ",Object(i.b)("inlineCode",{parentName:"p"},"Settings"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/3.png",alt:""})),Object(i.b)("p",null,"Got to the ",Object(i.b)("inlineCode",{parentName:"p"},"Secrets/Actions")," section and click on ",Object(i.b)("inlineCode",{parentName:"p"},"New repository secret"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/4.png",alt:""})),Object(i.b)("p",null,"Add your secret with the name ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_API_TOKEN")," and save:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/5.png",alt:""}))))),Object(i.b)("h2",{id:"execute-the-github-actions-pipeline"},"Execute the GitHub Actions Pipeline"),Object(i.b)("p",null,"We're done with the setup. You can now push your code to the ",Object(i.b)("inlineCode",{parentName:"p"},"main")," branch. If you did it properly, under the ",Object(i.b)("inlineCode",{parentName:"p"},"Actions")," tab on your GitHub repository, you should see your job being run."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/6.png",alt:""})),Object(i.b)("p",null,"You can click on it to see the details of the jobs. Once the testing phase is green, it will start the deployment job."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/7.png",alt:""})),Object(i.b)("p",null,"As soon as the job is set up, and it starts actually deploying, go to the Qovery console and check that your application is actually being deployed."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/8.png",alt:""})),Object(i.b)("h2",{id:"advanced-use-cases"},"Advanced use-cases"),Object(i.b)("p",null,"It's possible to support any use cases by using the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI"),". Like cloning an environment, changing the branch of some applications and deploying only a subset of applications. Refers to the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI documentation")," to explore all the commands that you can use."),Object(i.b)("p",null,"Check out our ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"GitHub Actions integration page")," to check out more examples."),Object(i.b)("h2",{id:"conclusion"},"Conclusion"),Object(i.b)("p",null,"Integrating Qovery with GitHub Actions enables more complex workflows than just deploying on code push. You can make sure your test suite succeeds before deploying\nor anything else you need, without sacrificing the simplicity of deployment Qovery brings you."))}d.isMDXComponent=!0},420:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=o,h=p["".concat(a,".").concat(d)]||p[d]||b[d]||i;return n?r.a.createElement(h,c({ref:t},s,{components:n})):r.a.createElement(h,c({ref:t},s))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,a[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=a>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var o=n(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var o=n(0),r=n.n(o),i=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var o=n(432),r=n(51);function i(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(r),i,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[i(t,e),"[",o,"]"].join(""):[i(t,e),"[",i(o,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return i(o,t);if(Array.isArray(r)){var a=[];return r.slice().forEach((function(e){void 0!==e&&a.push(n(o,e,a.length))})),a.join("&")}return i(o,t)+"="+i(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(420),n(428)),a=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(l),u=Object(o.useState)(null),p=u[0],b=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!p&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see c7bfb1d3.15c65c19.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[207],{359:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return d}));var o=n(1),r=n(9),i=(n(0),n(425)),a=n(434),c=n(424),l=n(429),s={last_modified_on:"2023-09-27",$schema:"/.meta/.schemas/guides.json",title:"How to integrate Qovery with GitHub Actions",description:"Learn how to integrate Qovery with GitHub Actions",author_github:"https://github.com/l0ck3",tags:["type: tutorial","technology: github"],hide_pagination:!0},u={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to integrate Qovery with GitHub Actions",description:"Learn how to integrate Qovery with GitHub Actions",permalink:"/guides/tutorial/how-to-integrate-qovery-with-github-actions",readingTime:"6 min read",source:"@site/guides/tutorial/how-to-integrate-qovery-with-github-actions.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: github",permalink:"/guides/tags/technology-github"}],title:"How to integrate Qovery with GitHub Actions",truncated:!1,prevItem:{title:"How to deploy Helm charts",permalink:"/guides/tutorial/how-to-deploy-helm-charts"},nextItem:{title:"How to run commands before the application starts",permalink:"/guides/tutorial/how-to-run-commands-at-application-startup"}},p=[{value:"Goal",id:"goal",children:[]},{value:"Get your application ready",id:"get-your-application-ready",children:[]},{value:"Add your GitHub Actions Workflow",id:"add-your-github-actions-workflow",children:[{value:"Create the Workflows directory",id:"create-the-workflows-directory",children:[]},{value:"Add a Test and Deploy workflow",id:"add-a-test-and-deploy-workflow",children:[]},{value:"Get a Qovery API token",id:"get-a-qovery-api-token",children:[]},{value:"Add your token to your GitHub repository secrets",id:"add-your-token-to-your-github-repository-secrets",children:[]}]},{value:"Execute the GitHub Actions Pipeline",id:"execute-the-github-actions-pipeline",children:[]},{value:"Advanced use-cases",id:"advanced-use-cases",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],b={rightToc:p};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Getting started with Qovery is easy. Just plug your Git repository, and you can deploy your application directly.\nBut in some cases you will want a more advanced CI workflow where some steps need to happen before deployment."),Object(i.b)("p",null,"One of the CI tools you can use for that matter is GitHub Actions."),Object(i.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"You have a Qovery cluster running."),Object(i.b)("li",{parentName:"ul"},"You are using GitHub Actions as a CI server."),Object(i.b)("li",{parentName:"ul"},"You have a Qovery application deployed."),Object(i.b)("li",{parentName:"ul"},"You have the Qovery CLI installed and configured."))),Object(i.b)("p",null,"If you don't have an application running on Qovery yet, check ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/getting-started/deploy-my-app/"}),"the documentation")," to create one."),Object(i.b)("h2",{id:"goal"},"Goal"),Object(i.b)("p",null,"In this tutorial, we will deploy an application with GitHub Actions by using the Qovery CLI."),Object(i.b)("h2",{id:"get-your-application-ready"},"Get your application ready"),Object(i.b)("p",null,"The first thing we need to do, is to disable automatic deployments. By default, Qovery applications get re-deployed whenever you push some code to the configured branch.\nSince we want to trigger the deployment through GitHub Actions, we need to disable this behavior."),Object(i.b)("p",null,"Go to your application page, then click ",Object(i.b)("inlineCode",{parentName:"p"},"Settings"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/1.png",alt:""})),Object(i.b)("p",null,"Then on the ",Object(i.b)("inlineCode",{parentName:"p"},"General")," section go to the ",Object(i.b)("inlineCode",{parentName:"p"},"Auto-deploy")," field, select ",Object(i.b)("inlineCode",{parentName:"p"},"Off"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/2.png",alt:""})),Object(i.b)("p",null,"Click save."),Object(i.b)("h2",{id:"add-your-github-actions-workflow"},"Add your GitHub Actions Workflow"),Object(i.b)("p",null,"We will now add a GitHub Actions workflow to your application. Workflow are defined with YAML configuration files that are placed in the code directory of your application.\nAs an example we will define a workflow for a NodeJS application. We will first run our unit tests, then launch the Qovery deployment if the tests pass."),Object(i.b)("p",null,"You can adapt those steps for your own stack and needs. Read the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.github.com/en/actions"}),"GitHub Actions documentation")," to learn more."),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("h3",{id:"create-the-workflows-directory"},"Create the Workflows directory"),Object(i.b)("p",null,"All your workflows files must be stored in a specific ",Object(i.b)("inlineCode",{parentName:"p"},".github/workflows")," directory. Create this directory at the root of your project.")),Object(i.b)("li",null,Object(i.b)("h3",{id:"add-a-test-and-deploy-workflow"},"Add a Test and Deploy workflow"),Object(i.b)("p",null,"In your Workflows folder, create a ",Object(i.b)("inlineCode",{parentName:"p"},"test-and-deploy.yaml")," file with the following content:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-yaml",metastring:'title=".github/workflows/test-and-deploy.yaml"',title:'".github/workflows/test-and-deploy.yaml"'}),"name: Test And Deploy to Qovery\non:\n workflow_call:\n secrets:\n api-token:\n required: true\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v2\n - name: Install modules\n run: yarn\n - name: Run tests\n run: yarn test\n deploy:\n needs: test\n runs-on: ubuntu-latest\n name: Deploy on Qovery\n steps:\n - name: Deploy with Qovery\n uses: actions/checkout@v3\n env:\n QOVERY_CLI_ACCESS_TOKEN: ${{ secrets.QOVERY_CLI_ACCESS_TOKEN }}\n shell: bash\n run: |\n # Download and install Qovery CLI\n curl -s https://get.qovery.com | bash\n\n qovery application deploy \\\n --organization \\\n --project \\\n --environment \\\n --application \\\n --commit-id ${{ github.sha }} \\\n --watch\n")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"on")," section contains a ",Object(i.b)("inlineCode",{parentName:"li"},"workflow_call")," directive. It means that this workflow will be triggered when called from another workflow.\nWe're doing this because we won't use this workflow directly. Since we might have several environments to deploy to Qovery depending on the branch, we could have one workflow per environment, and we want to avoid repeating all the steps."),Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"inputs")," and ",Object(i.b)("inlineCode",{parentName:"li"},"secrets")," sections are defining the values that we will need to pass to our workflow"),Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"jobs")," section lists the ",Object(i.b)("inlineCode",{parentName:"li"},"jobs")," and the ",Object(i.b)("inlineCode",{parentName:"li"},"steps")," that in needs to accomplish. Here we have two jobs and five steps:",Object(i.b)("ul",{parentName:"li"},Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"test")," where we check out the code, we install Yarn modules, and we run tests through Jest"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"deploy")," where we check out the code and deploy to Qovery.")))),Object(i.b)("p",null,"Several things worth noting:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"The organization / project / environment / application are case-sensitive."),Object(i.b)("li",{parentName:"ul"},"Our ",Object(i.b)("inlineCode",{parentName:"li"},"deploy")," job has a ",Object(i.b)("inlineCode",{parentName:"li"},"needs")," instructions, telling GitHub Actions that this job can only run when the ",Object(i.b)("inlineCode",{parentName:"li"},"test")," job succeeds."),Object(i.b)("li",{parentName:"ul"},"The ",Object(i.b)("inlineCode",{parentName:"li"},"with")," section of our last ",Object(i.b)("inlineCode",{parentName:"li"},"deploy")," step contains interpolated strings: ${{ inputs.xxxx }}. Those are values passed to our workflow, that our Qovery action needs. They will be passed from the calling workflow."))),Object(i.b)("li",null,Object(i.b)("h3",{id:"get-a-qovery-api-token"},"Get a Qovery API token"),Object(i.b)("p",null,"To get an API token, use the Qovery CLI:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"qovery token\n")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Select your organization. (tokens are valid for only one organization)."),Object(i.b)("li",{parentName:"ul"},"Enter a name for your token."),Object(i.b)("li",{parentName:"ul"},"Enter a description for your token.")),Object(i.b)("p",null,"You will get an output like this one:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{}),"qovery token Qovery: ---- Never share this authentication token and keep it secure ----\nQovery: qov_xxx....\nQovery: ---- Never share this authentication token and keep it secure ----\n")),Object(i.b)(c.a,{type:"warning",mdxType:"Alert"},"At the time of writing, we don't have a way to invalidate tokens. Store it carefully.")),Object(i.b)("li",null,Object(i.b)("h3",{id:"add-your-token-to-your-github-repository-secrets"},"Add your token to your GitHub repository secrets"),Object(i.b)("p",null,"Go to your GitHub repository then to the ",Object(i.b)("inlineCode",{parentName:"p"},"Settings"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/3.png",alt:""})),Object(i.b)("p",null,"Got to the ",Object(i.b)("inlineCode",{parentName:"p"},"Secrets/Actions")," section and click on ",Object(i.b)("inlineCode",{parentName:"p"},"New repository secret"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/4.png",alt:""})),Object(i.b)("p",null,"Add your secret with the name ",Object(i.b)("inlineCode",{parentName:"p"},"QOVERY_API_TOKEN")," and save:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/5.png",alt:""}))))),Object(i.b)("h2",{id:"execute-the-github-actions-pipeline"},"Execute the GitHub Actions Pipeline"),Object(i.b)("p",null,"We're done with the setup. You can now push your code to the ",Object(i.b)("inlineCode",{parentName:"p"},"main")," branch. If you did it properly, under the ",Object(i.b)("inlineCode",{parentName:"p"},"Actions")," tab on your GitHub repository, you should see your job being run."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/6.png",alt:""})),Object(i.b)("p",null,"You can click on it to see the details of the jobs. Once the testing phase is green, it will start the deployment job."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/7.png",alt:""})),Object(i.b)("p",null,"As soon as the job is set up, and it starts actually deploying, go to the Qovery console and check that your application is actually being deployed."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/how-to-integrate-qovery-with-github-actions/8.png",alt:""})),Object(i.b)("h2",{id:"advanced-use-cases"},"Advanced use-cases"),Object(i.b)("p",null,"It's possible to support any use cases by using the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI"),". Like cloning an environment, changing the branch of some applications and deploying only a subset of applications. Refers to the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI documentation")," to explore all the commands that you can use."),Object(i.b)("p",null,"Check out our ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/integration/continuous-integration/github-actions/"}),"GitHub Actions integration page")," to check out more examples."),Object(i.b)("h2",{id:"conclusion"},"Conclusion"),Object(i.b)("p",null,"Integrating Qovery with GitHub Actions enables more complex workflows than just deploying on code push. You can make sure your test suite succeeds before deploying\nor anything else you need, without sacrificing the simplicity of deployment Qovery brings you."))}d.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=o,h=p["".concat(a,".").concat(d)]||p[d]||b[d]||i;return n?r.a.createElement(h,c({ref:t},s,{components:n})):r.a.createElement(h,c({ref:t},s))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,a[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=a>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var o=n(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||n(10)&&o(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var o=n(0),r=n.n(o),i=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var o=n(435),r=n(51);function i(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(r),i,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[i(t,e),"[",o,"]"].join(""):[i(t,e),"[",i(o,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return i(o,t);if(Array.isArray(r)){var a=[];return r.slice().forEach((function(e){void 0!==e&&a.push(n(o,e,a.length))})),a.join("&")}return i(o,t)+"="+i(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(423),n(433)),a=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(l),u=Object(o.useState)(null),p=u[0],b=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!p&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/cbb976f4.9c44e5c6.js.LICENSE.txt b/c7bfb1d3.15c65c19.js.LICENSE.txt similarity index 100% rename from cbb976f4.9c44e5c6.js.LICENSE.txt rename to c7bfb1d3.15c65c19.js.LICENSE.txt diff --git a/c8223350.ab418736.js b/c8223350.87539647.js similarity index 82% rename from c8223350.ab418736.js rename to c8223350.87539647.js index 6d5bd510da..6737f16249 100644 --- a/c8223350.ab418736.js +++ b/c8223350.87539647.js @@ -1,2 +1,2 @@ -/*! For license information please see c8223350.ab418736.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[205],{357:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return d}));var r=n(1),a=n(9),o=(n(0),n(422)),i=n(431),c=n(421),l=n(426),u=(n(429),{last_modified_on:"2022-02-25",$schema:"/.meta/.schemas/guides.json",title:"Setup VPC peering on AWS with Qovery",description:"How to peer a Qovery VPC with an existing VPC on AWS",author_github:"https://github.com/l0ck3",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),b={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Setup VPC peering on AWS with Qovery",description:"How to peer a Qovery VPC with an existing VPC on AWS",permalink:"/guides/tutorial/aws-vpc-peering-with-qovery",readingTime:"6 min read",source:"@site/guides/tutorial/aws-vpc-peering-with-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Setup VPC peering on AWS with Qovery",truncated:!1,prevItem:{title:"Setting up Cloudflare and Custom Domain on Qovery",permalink:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery"},nextItem:{title:"Terraform",permalink:"/guides/advanced/terraform"}},s=[{value:"Goal",id:"goal",children:[]}],p={rightToc:s};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"While Qovery is all you need to deploy and run your applications in AWS, you might have existing resources in another VPC that you want to access from your Qovery applications.\nThis tutorial will show you how to set up VPC peering between the Qovery VPC and an existing one in your account."),Object(o.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have an existing AWS VPC with a resource you need to access, like an RDS database"),Object(o.b)("li",{parentName:"ul"},"You have a ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.qovery.com/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes"}),"Qovery cluster ready on your AWS account")))),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Make sure the CIDR blocks of your two VPCs don't overlap. AWS won't allow the peering connection otherwise.",Object(o.b)("br",null),Object(o.b)("br",null),"To match this requirement, you can customize the Qovery VPC CIDR at cluster creation:",Object(o.b)("br",null),Object(o.b)("br",null),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/custom-cidr.png",alt:"Customise Qovery CIDR"}))),Object(o.b)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"In this tutorial, we will connect an existing VPC on our AWS accounts with the VPC of a Qovery managed cluster.\nWe should then be able to deploy an application using a PostgresSQL RDS instance in our existing VPC."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"gather-the-necessary-information"},"Gather the necessary information"),Object(o.b)("p",null,"Before we begin, you will need to gather some information. It is recommended that you keep this information at hand in a file for convenience."),Object(o.b)("p",null,"At the end of this step 1, you should have those elements:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Name"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Content"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"x.x.x.x/x")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-xxx")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"y.y.y.y/y")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-yyy")))),Object(o.b)("p",null,"Keep in mind the following convention:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Existing VPC: your current VPC infrastructure (not managed by Qovery)"),Object(o.b)("li",{parentName:"ul"},"Qovery VPC: the VPC deployed and managed by Qovery")),Object(o.b)("p",null),Object(o.b)("h5",{id:"your-existing-vpc-id"},"Your existing VPC ID"),Object(o.b)("p",null,"To get your existing VPC ID in your AWS console, go to: ",Object(o.b)("inlineCode",{parentName:"p"},"VPC > Your VPCs"),", find the VPC you would like to use as a peering target, and copy its ID"),Object(o.b)("p",null,"You will be able to have those information:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Name"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Content"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"x.x.x.x/x")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-xxx")))),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/vpc-console-1.png",alt:"AWS console VPC list"})),Object(o.b)("h5",{id:"the-qovery-vpc-id"},"The Qovery VPC ID"),Object(o.b)("p",null,"You can use the same method to get the Qovery VPC ID. It should be named ",Object(o.b)("inlineCode",{parentName:"p"},"qovery-eks-workers"),"."),Object(o.b)("p",null,"You will be able to have those information:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Name"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Content"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"x.x.x.x/x")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-xxx")))),Object(o.b)("p",null)),Object(o.b)("li",null,Object(o.b)("h5",{id:"the-cidr-ranges-of-both-vpcs"},"The CIDR ranges of both VPCs"),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Make sure the CIDR blocks of your two VPCs don't overlap or you won't be able to create the peering connection."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/find-cidr.png",alt:"AWS console VPC CIDR ranges"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-peering-connection"},"Create a peering connection"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"A VPC peering connection is a networking connection between two VPCs that enables you to route traffic between them privately.")),Object(o.b)("p",null,"In the AWS console, go to ",Object(o.b)("inlineCode",{parentName:"p"},"VPC > Peering connections")," and click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create peering connection")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Give it a name"),Object(o.b)("li",{parentName:"ul"},"As a requester, select your Qovery VPC"),Object(o.b)("li",{parentName:"ul"},"As an accepter, select your existing VPC"),Object(o.b)("li",{parentName:"ul"},"Click on ",Object(o.b)("inlineCode",{parentName:"li"},"Create peering connection"))),Object(o.b)("br",null),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/peering-form.png",alt:"AWS create VPC peering form"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"accept-the-peering-request"},"Accept the peering request"),Object(o.b)("p",null,"Once created, the peering connection needs to be accepted.\nOn the peering connection view, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Actions")," then ",Object(o.b)("inlineCode",{parentName:"p"},"Accept request")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/accept-peering-request.png",alt:"AWS accept VPC peering request"})),Object(o.b)("p",null,"You should see your peering connection marked as ",Object(o.b)("inlineCode",{parentName:"p"},"Active")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/peering-active.png",alt:"AWS VPC peering active"})),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("b",null,"Take note of the peering connection ID. You will need it later."))),Object(o.b)("li",null,Object(o.b)("h4",{id:"update-existing-vpc-route-table"},"Update existing VPC route table"),Object(o.b)("p",null,"In the AWS console of your ",Object(o.b)("strong",{parentName:"p"},"non Qovery VPC"),", go to ",Object(o.b)("inlineCode",{parentName:"p"},"VPC > Route Tables"),".\nYou can filter the list using the IDs you noted at step 1 to find the routing table for your existing VPC."),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"Thanks Kevin M. for your contribution here \ud83d\ude0a")),Object(o.b)("p",null,"For your existing VPC edit the route table:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/existing-rt.png",alt:"AWS VPC Qovery Route Table"})),Object(o.b)("p",null,"Click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Edit routes")," button then ",Object(o.b)("inlineCode",{parentName:"p"},"Add route"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/existing-rt-add.png",alt:"AWS VPC Qovery Route Table add route"})),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"As a destination, enter the CIDR of your Qovery VPC"),Object(o.b)("li",{parentName:"ul"},"As a target, select the ",Object(o.b)("inlineCode",{parentName:"li"},"Peering connection")," you created earlier")),Object(o.b)("p",null,"Click ",Object(o.b)("inlineCode",{parentName:"p"},"Save changes"),"."),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Do not alter existing routes. Make sure you are adding a new one.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"update-qovery-vpc-route-table"},"Update Qovery VPC route table"),Object(o.b)("p",null,"This part needs to be done through the Qovery console."),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Make sure you are adding a new route. Do not edit or remove existing routes to avoid service interruption."),Object(o.b)("p",null,"In the cluster settings, under the ",Object(o.b)("inlineCode",{parentName:"p"},"Network")," tab, click ",Object(o.b)("inlineCode",{parentName:"p"},"ADD ROUTE")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/qovery-rt.png",alt:"AWS VPC Qovery Route Table add route"})),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"As a destination, enter the CIDR of your existing VPC"),Object(o.b)("li",{parentName:"ul"},"As a target, enter the ID of the peering connection you created earlier"),Object(o.b)("li",{parentName:"ul"},"You can put anything you want as a description.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/qovery-rt-added.png",alt:"AWS VPC Qovery Route Table add route"})),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,'You need to update your cluster to apply the configuration change. Click on the cluster ellipsis > "update".'))),Object(o.b)("li",null,Object(o.b)("h4",{id:"update-the-security-groups"},"Update the security groups"),Object(o.b)("p",null,"Our two VPCs are now connected, but we still need to update the security groups to allow communication between the Qovery applications and your existing resources."),Object(o.b)("p",null,"What rules to put on your security groups depends on what you are trying to achieve.\nIn our case, we would like to access an RDS instance from our Qovery applications."),Object(o.b)("p",null,"We will edit the RDS security group in our existing VPC to add an inbound rule allowing PostgreSQL traffic from our Qovery instances:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/pg-inbound-rule.png",alt:"AWS Security Group inbound rules"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"deploy-an-application"},"Deploy an application"),Object(o.b)("p",null,"You should now be able to deploy an application using the RDS PostgreSQL database on your Qovery cluster.\nRefer to ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"this guide")," if you need help deploying an application on Qovery.")))),Object(o.b)("p",null,"You can learn more about VPC peering on AWS here: ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html"}),"https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html")))}d.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),b=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},s=function(e){var t=b(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),s=b(n),d=r,m=s["".concat(i,".").concat(d)]||s[d]||p[d]||o;return n?a.a.createElement(m,c({ref:t},u,{components:n})):a.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(430),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,s=Object(c.a)(b),p=Object(a.useRef)(!1),d=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!d&&s&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,s]),b&&s?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var n,r;d&&e&&s&&(n=e,r=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:b})):o.a.createElement("a",Object(r.a)({},e,{href:b}))}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,l=e.rightIcon,u=e.size,b=e.target,s=e.to,p=c()("jump-to","jump-to--"+u,n),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return b?a.a.createElement("a",{href:s,target:b,className:p},d):a.a.createElement(o.a,{to:s,className:p},d)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),b=Object(r.useState)(null),s=b[0],p=b[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!s&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==s&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see c8223350.87539647.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[208],{360:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return d}));var r=n(1),a=n(9),o=(n(0),n(425)),i=n(434),c=n(424),l=n(429),u=(n(431),{last_modified_on:"2022-02-25",$schema:"/.meta/.schemas/guides.json",title:"Setup VPC peering on AWS with Qovery",description:"How to peer a Qovery VPC with an existing VPC on AWS",author_github:"https://github.com/l0ck3",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),b={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Setup VPC peering on AWS with Qovery",description:"How to peer a Qovery VPC with an existing VPC on AWS",permalink:"/guides/tutorial/aws-vpc-peering-with-qovery",readingTime:"6 min read",source:"@site/guides/tutorial/aws-vpc-peering-with-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Setup VPC peering on AWS with Qovery",truncated:!1,prevItem:{title:"Setting up Cloudflare and Custom Domain on Qovery",permalink:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery"},nextItem:{title:"Terraform",permalink:"/guides/advanced/terraform"}},s=[{value:"Goal",id:"goal",children:[]}],p={rightToc:s};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"While Qovery is all you need to deploy and run your applications in AWS, you might have existing resources in another VPC that you want to access from your Qovery applications.\nThis tutorial will show you how to set up VPC peering between the Qovery VPC and an existing one in your account."),Object(o.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have an existing AWS VPC with a resource you need to access, like an RDS database"),Object(o.b)("li",{parentName:"ul"},"You have a ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.qovery.com/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes"}),"Qovery cluster ready on your AWS account")))),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Make sure the CIDR blocks of your two VPCs don't overlap. AWS won't allow the peering connection otherwise.",Object(o.b)("br",null),Object(o.b)("br",null),"To match this requirement, you can customize the Qovery VPC CIDR at cluster creation:",Object(o.b)("br",null),Object(o.b)("br",null),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/custom-cidr.png",alt:"Customise Qovery CIDR"}))),Object(o.b)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"In this tutorial, we will connect an existing VPC on our AWS accounts with the VPC of a Qovery managed cluster.\nWe should then be able to deploy an application using a PostgresSQL RDS instance in our existing VPC."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"gather-the-necessary-information"},"Gather the necessary information"),Object(o.b)("p",null,"Before we begin, you will need to gather some information. It is recommended that you keep this information at hand in a file for convenience."),Object(o.b)("p",null,"At the end of this step 1, you should have those elements:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Name"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Content"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"x.x.x.x/x")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-xxx")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"y.y.y.y/y")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-yyy")))),Object(o.b)("p",null,"Keep in mind the following convention:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Existing VPC: your current VPC infrastructure (not managed by Qovery)"),Object(o.b)("li",{parentName:"ul"},"Qovery VPC: the VPC deployed and managed by Qovery")),Object(o.b)("p",null),Object(o.b)("h5",{id:"your-existing-vpc-id"},"Your existing VPC ID"),Object(o.b)("p",null,"To get your existing VPC ID in your AWS console, go to: ",Object(o.b)("inlineCode",{parentName:"p"},"VPC > Your VPCs"),", find the VPC you would like to use as a peering target, and copy its ID"),Object(o.b)("p",null,"You will be able to have those information:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Name"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Content"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"x.x.x.x/x")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-xxx")))),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/vpc-console-1.png",alt:"AWS console VPC list"})),Object(o.b)("h5",{id:"the-qovery-vpc-id"},"The Qovery VPC ID"),Object(o.b)("p",null,"You can use the same method to get the Qovery VPC ID. It should be named ",Object(o.b)("inlineCode",{parentName:"p"},"qovery-eks-workers"),"."),Object(o.b)("p",null,"You will be able to have those information:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Name"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Content"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"x.x.x.x/x")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-xxx")))),Object(o.b)("p",null)),Object(o.b)("li",null,Object(o.b)("h5",{id:"the-cidr-ranges-of-both-vpcs"},"The CIDR ranges of both VPCs"),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Make sure the CIDR blocks of your two VPCs don't overlap or you won't be able to create the peering connection."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/find-cidr.png",alt:"AWS console VPC CIDR ranges"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-peering-connection"},"Create a peering connection"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"A VPC peering connection is a networking connection between two VPCs that enables you to route traffic between them privately.")),Object(o.b)("p",null,"In the AWS console, go to ",Object(o.b)("inlineCode",{parentName:"p"},"VPC > Peering connections")," and click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create peering connection")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Give it a name"),Object(o.b)("li",{parentName:"ul"},"As a requester, select your Qovery VPC"),Object(o.b)("li",{parentName:"ul"},"As an accepter, select your existing VPC"),Object(o.b)("li",{parentName:"ul"},"Click on ",Object(o.b)("inlineCode",{parentName:"li"},"Create peering connection"))),Object(o.b)("br",null),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/peering-form.png",alt:"AWS create VPC peering form"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"accept-the-peering-request"},"Accept the peering request"),Object(o.b)("p",null,"Once created, the peering connection needs to be accepted.\nOn the peering connection view, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Actions")," then ",Object(o.b)("inlineCode",{parentName:"p"},"Accept request")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/accept-peering-request.png",alt:"AWS accept VPC peering request"})),Object(o.b)("p",null,"You should see your peering connection marked as ",Object(o.b)("inlineCode",{parentName:"p"},"Active")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/peering-active.png",alt:"AWS VPC peering active"})),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("b",null,"Take note of the peering connection ID. You will need it later."))),Object(o.b)("li",null,Object(o.b)("h4",{id:"update-existing-vpc-route-table"},"Update existing VPC route table"),Object(o.b)("p",null,"In the AWS console of your ",Object(o.b)("strong",{parentName:"p"},"non Qovery VPC"),", go to ",Object(o.b)("inlineCode",{parentName:"p"},"VPC > Route Tables"),".\nYou can filter the list using the IDs you noted at step 1 to find the routing table for your existing VPC."),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"Thanks Kevin M. for your contribution here \ud83d\ude0a")),Object(o.b)("p",null,"For your existing VPC edit the route table:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/existing-rt.png",alt:"AWS VPC Qovery Route Table"})),Object(o.b)("p",null,"Click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Edit routes")," button then ",Object(o.b)("inlineCode",{parentName:"p"},"Add route"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/existing-rt-add.png",alt:"AWS VPC Qovery Route Table add route"})),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"As a destination, enter the CIDR of your Qovery VPC"),Object(o.b)("li",{parentName:"ul"},"As a target, select the ",Object(o.b)("inlineCode",{parentName:"li"},"Peering connection")," you created earlier")),Object(o.b)("p",null,"Click ",Object(o.b)("inlineCode",{parentName:"p"},"Save changes"),"."),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Do not alter existing routes. Make sure you are adding a new one.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"update-qovery-vpc-route-table"},"Update Qovery VPC route table"),Object(o.b)("p",null,"This part needs to be done through the Qovery console."),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Make sure you are adding a new route. Do not edit or remove existing routes to avoid service interruption."),Object(o.b)("p",null,"In the cluster settings, under the ",Object(o.b)("inlineCode",{parentName:"p"},"Network")," tab, click ",Object(o.b)("inlineCode",{parentName:"p"},"ADD ROUTE")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/qovery-rt.png",alt:"AWS VPC Qovery Route Table add route"})),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"As a destination, enter the CIDR of your existing VPC"),Object(o.b)("li",{parentName:"ul"},"As a target, enter the ID of the peering connection you created earlier"),Object(o.b)("li",{parentName:"ul"},"You can put anything you want as a description.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/qovery-rt-added.png",alt:"AWS VPC Qovery Route Table add route"})),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,'You need to update your cluster to apply the configuration change. Click on the cluster ellipsis > "update".'))),Object(o.b)("li",null,Object(o.b)("h4",{id:"update-the-security-groups"},"Update the security groups"),Object(o.b)("p",null,"Our two VPCs are now connected, but we still need to update the security groups to allow communication between the Qovery applications and your existing resources."),Object(o.b)("p",null,"What rules to put on your security groups depends on what you are trying to achieve.\nIn our case, we would like to access an RDS instance from our Qovery applications."),Object(o.b)("p",null,"We will edit the RDS security group in our existing VPC to add an inbound rule allowing PostgreSQL traffic from our Qovery instances:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/pg-inbound-rule.png",alt:"AWS Security Group inbound rules"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"deploy-an-application"},"Deploy an application"),Object(o.b)("p",null,"You should now be able to deploy an application using the RDS PostgreSQL database on your Qovery cluster.\nRefer to ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"this guide")," if you need help deploying an application on Qovery.")))),Object(o.b)("p",null,"You can learn more about VPC peering on AWS here: ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html"}),"https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html")))}d.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),b=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},s=function(e){var t=b(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),s=b(n),d=r,m=s["".concat(i,".").concat(d)]||s[d]||p[d]||o;return n?a.a.createElement(m,c({ref:t},u,{components:n})):a.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(432),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,s=Object(c.a)(b),p=Object(a.useRef)(!1),d=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!d&&s&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,s]),b&&s?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var n,r;d&&e&&s&&(n=e,r=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:b})):o.a.createElement("a",Object(r.a)({},e,{href:b}))}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,l=e.rightIcon,u=e.size,b=e.target,s=e.to,p=c()("jump-to","jump-to--"+u,n),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return b?a.a.createElement("a",{href:s,target:b,className:p},d):a.a.createElement(o.a,{to:s,className:p},d)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),b=Object(r.useState)(null),s=b[0],p=b[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!s&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==s&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/cbcbf0e3.a6610e2f.js.LICENSE.txt b/c8223350.87539647.js.LICENSE.txt similarity index 100% rename from cbcbf0e3.a6610e2f.js.LICENSE.txt rename to c8223350.87539647.js.LICENSE.txt diff --git a/ca4f5154.5e74c550.js b/ca4f5154.ab8156b6.js similarity index 96% rename from ca4f5154.5e74c550.js rename to ca4f5154.ab8156b6.js index 9480925aee..1d2d3d2151 100644 --- a/ca4f5154.5e74c550.js +++ b/ca4f5154.ab8156b6.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[206],{358:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return c})),r.d(t,"metadata",(function(){return u})),r.d(t,"rightToc",(function(){return a})),r.d(t,"default",(function(){return s}));var o=r(1),n=r(9),i=(r(0),r(422)),c={last_modified_on:"2023-05-19",title:"Lifecycle Job Troubleshoot",description:"Everything you need to troubleshoot your lifecycle job with Qovery",hide_pagination:!0},u={id:"using-qovery/troubleshoot/lifecycle-troubleshoot",title:"Lifecycle Job Troubleshoot",description:"Everything you need to troubleshoot your lifecycle job with Qovery",source:"@site/docs/using-qovery/troubleshoot/lifecycle-troubleshoot.md",permalink:"/docs/using-qovery/troubleshoot/lifecycle-troubleshoot",sidebar:"docs",previous:{title:"Database Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/database-troubleshoot"},next:{title:"Cluster Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/cluster-troubleshoot"}},a=[{value:"Joib failed: either it couldn't be executed correctly after X retries or its execution didn't finish after Y minutes",id:"joib-failed-either-it-couldnt-be-executed-correctly-after-x-retries-or-its-execution-didnt-finish-after-y-minutes",children:[]}],l={rightToc:a};function s(e){var t=e.components,r=Object(n.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},l,r,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Within this section you will find the common errors you might encounter when deploying or running your Lifecycle Job with Qovery"),Object(i.b)("h2",{id:"joib-failed-either-it-couldnt-be-executed-correctly-after-x-retries-or-its-execution-didnt-finish-after-y-minutes"},"Joib failed: either it couldn't be executed correctly after X retries or its execution didn't finish after Y minutes"),Object(i.b)("p",null,"This errors occurs in the following two cases:"),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Job code execution failures"),"\nThe pod running your lifecycle job is crashing due to an exception in your code or OOM issue. Have a look at the Live Logs of your Lifecycle job to understand from where the issue is coming from your code."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"},"Job execution timeout"),"\nThe code run in your job is taking more time than expected and thus it's execution is stopped. If your code needs more time to be excecuted, increase the ",Object(i.b)("inlineCode",{parentName:"p"},"Max Duration")," value within the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/#job-configuration"}),"Lifecycle Job configuration page")))}s.isMDXComponent=!0},422:function(e,t,r){"use strict";r.d(t,"a",(function(){return b})),r.d(t,"b",(function(){return p}));var o=r(0),n=r.n(o);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function c(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function u(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=n.a.createContext({}),s=function(e){var t=n.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):u({},t,{},e)),r},b=function(e){var t=s(e.components);return n.a.createElement(l.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,c=e.parentName,l=a(e,["components","mdxType","originalType","parentName"]),b=s(r),d=o,p=b["".concat(c,".").concat(d)]||b[d]||f[d]||i;return r?n.a.createElement(p,u({ref:t},l,{components:r})):n.a.createElement(p,u({ref:t},l))}));function p(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,c=new Array(i);c[0]=d;var u={};for(var a in t)hasOwnProperty.call(t,a)&&(u[a]=t[a]);u.originalType=e,u.mdxType="string"==typeof e?e:o,c[1]=u;for(var l=2;l=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=n.a.createContext({}),s=function(e){var t=n.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):u({},t,{},e)),r},b=function(e){var t=s(e.components);return n.a.createElement(l.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,c=e.parentName,l=a(e,["components","mdxType","originalType","parentName"]),b=s(r),d=o,p=b["".concat(c,".").concat(d)]||b[d]||f[d]||i;return r?n.a.createElement(p,u({ref:t},l,{components:r})):n.a.createElement(p,u({ref:t},l))}));function p(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,c=new Array(i);c[0]=d;var u={};for(var a in t)hasOwnProperty.call(t,a)&&(u[a]=t[a]);u.originalType=e,u.mdxType="string"==typeof e?e:o,c[1]=u;for(var l=2;l=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},l=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,c=e.parentName,u=p(e,["components","mdxType","originalType","parentName"]),l=s(r),d=n,y=l["".concat(c,".").concat(d)]||l[d]||f[d]||a;return r?o.a.createElement(y,i({ref:t},u,{components:r})):o.a.createElement(y,i({ref:t},u))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=r.length,c=new Array(a);c[0]=d;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var u=2;u=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},l=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,c=e.parentName,u=p(e,["components","mdxType","originalType","parentName"]),l=s(r),d=n,y=l["".concat(c,".").concat(d)]||l[d]||f[d]||a;return r?o.a.createElement(y,i({ref:t},u,{components:r})):o.a.createElement(y,i({ref:t},u))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=r.length,c=new Array(a);c[0]=d;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var u=2;u {\n console.log(data);\n res.end('Success');\n // process data.\n },\n (error) => {\n console.error(error);\n res.end('Error');\n // error handling.\n }\n);\n")),Object(o.b)("p",null,"To deploy the app on Qovery, all you need to do is to fork the repository from above and create a new app adding port ",Object(o.b)("inlineCode",{parentName:"p"},"3000"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/4.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Afterwards, we need to add two environment variables:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"accessKeyId")," - your AWS access key ID"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"secretAccessKey")," - your AWS secret access key")),Object(o.b)("p",null,"You can add them in ",Object(o.b)("inlineCode",{parentName:"p"},"Environment Variebles")," ",Object(o.b)("inlineCode",{parentName:"p"},"Secret")," section in your application settings:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/5.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/6.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"After all the setup is all done, click the ",Object(o.b)("inlineCode",{parentName:"p"},"Deploy")," button - the application will be shortly deployed."),Object(o.b)("h2",{id:"create-lambda-consumers"},"Create Lambda Consumers"),Object(o.b)("p",null,"In AWS Console, open ",Object(o.b)("inlineCode",{parentName:"p"},"AWS Lambda")," panel."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/7.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"For the sake of the guide, we will use a simple ",Object(o.b)("inlineCode",{parentName:"p"},"hello-world")," lambda from AWS serverless app repository."),Object(o.b)("p",null,"Browse the app repository and pick the ",Object(o.b)("inlineCode",{parentName:"p"},"hello-world")," function as shown in the screenshot above, and deploy the function"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/8.png",alt:"AWS SQS Lambda"})),Object(o.b)("h2",{id:"create-lambda-trigger"},"Create Lambda Trigger"),Object(o.b)("p",null,"To make our Lambdas consume messages from SQS, we will need to add a ",Object(o.b)("inlineCode",{parentName:"p"},"Lambda Trigger")," in the SQS configuration."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/9.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Click on ",Object(o.b)("inlineCode",{parentName:"p"},"Configure Lambda Function Trigger")," as shown in the screenshot above and select your lambda function from the dropdown, then save the changes:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/10.png",alt:"AWS SQS Lambda"})),Object(o.b)("h2",{id:"configure-permissions"},"Configure Permissions"),Object(o.b)("p",null,"Let's now grant our Lambda functions access to the SQS queue we created before."),Object(o.b)("p",null,"In our lambda view, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Configure"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/11.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Then, click on a role in ",Object(o.b)("inlineCode",{parentName:"p"},"Execution role")," to get redirected to a view where we can alter our Lambda permissions."),Object(o.b)("p",null,"In the role summary screen, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Edit policy")," next to ",Object(o.b)("inlineCode",{parentName:"p"},"helloWorldrolePolicy")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/12.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"In the ",Object(o.b)("inlineCode",{parentName:"p"},"SQS")," section, grant permissions to all Read/Write options in the ",Object(o.b)("inlineCode",{parentName:"p"},"Actions")," ",Object(o.b)("inlineCode",{parentName:"p"},"Access level")," and accept the changes:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/13.png",alt:"AWS SQS Lambda"})),Object(o.b)("h2",{id:"test-lambda-as-an-sqs-consumer-flow"},"Test Lambda as an SQS Consumer Flow"),Object(o.b)("p",null,"To push messages to our SQS queue from the backend app deployed on Qovery, click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Open")," button in the application we deployed in the previous step. It will redirect you to the API endpoint exposed by the backend app - the logic inside the application is made so that it sends messages to the SQS queue."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/14.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Now, in the ",Object(o.b)("inlineCode",{parentName:"p"},"Monitoring")," section of SQS in AWS Console, we will see messages received on metrics charts:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/15.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"To validate that our consumer Lambdas processed the messages, navigate to your lambda ",Object(o.b)("inlineCode",{parentName:"p"},"Monitor")," panel:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/16.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"In the ",Object(o.b)("inlineCode",{parentName:"p"},"Invocations")," chart, you'll notice that our Lambda was triggered several times by the messages sent over the SQS."),Object(o.b)("h2",{id:"conclusions"},"Conclusions"),Object(o.b)("p",null,"In this part of the tutorial, we learned how to send messages over from an application deployed on Qovery to SQS and consume them from serverless Lambda functions. In the next part, we will create a scalable group of worker applications deployed by Qovery that consume messages from the same Queue."))}b.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),b=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s({},t,{},e)),n},u=function(e){var t=b(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=b(n),m=a,p=u["".concat(i,".").concat(m)]||u[m]||d[m]||o;return n?r.a.createElement(p,s({ref:t},l,{components:n})):r.a.createElement(p,s({ref:t},l))}));function p(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s.mdxType="string"==typeof e?e:a,i[1]=s;for(var l=2;l1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,l=void 0===c?n:r(c,n);l>s;)t[s++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),s=n(430),c=n(20),l=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,b=n||c,u=Object(s.a)(b),d=Object(r.useRef)(!1),m=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&u&&window.docusaurus.prefetch(b),function(){m&&t&&t.disconnect()}}),[b,m,u]),b&&u?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(b),d.current=!0)},innerRef:function(e){var n,a;m&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:b})):o.a.createElement("a",Object(a.a)({},e,{href:b}))}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),i=n(420),s=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,l=e.size,b=e.target,u=e.to,d=s()("jump-to","jump-to--"+l,n),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return b?r.a.createElement("a",{href:u,target:b,className:d},m):r.a.createElement(o.a,{to:u,className:d},m)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see cbb976f4.11b76fa1.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[212],{364:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return c})),n.d(t,"default",(function(){return b}));var a=n(1),r=n(9),o=(n(0),n(425)),i=(n(424),n(429),n(431),{last_modified_on:"2021-12-28",$schema:"/.meta/.schemas/guides.json",title:"Using Amazon SQS and Lambda on Qovery",description:"How to integrate Amazon SQS and Lambda on Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Using Amazon SQS and Lambda on Qovery",description:"How to integrate Amazon SQS and Lambda on Qovery",permalink:"/guides/tutorial/aws-sqs-lambda-with-qovery",readingTime:"5 min read",source:"@site/guides/tutorial/aws-sqs-lambda-with-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Using Amazon SQS and Lambda on Qovery",truncated:!1,prevItem:{title:"Use AWS IAM roles with Qovery",permalink:"/guides/tutorial/use-aws-iam-roles-with-qovery"},nextItem:{title:"Working with Git Submodules",permalink:"/guides/tutorial/working-with-git-submodules"}},c=[{value:"Goal",id:"goal",children:[]},{value:"Configure SQS",id:"configure-sqs",children:[]},{value:"Create Message Producer",id:"create-message-producer",children:[]},{value:"Create Lambda Consumers",id:"create-lambda-consumers",children:[]},{value:"Create Lambda Trigger",id:"create-lambda-trigger",children:[]},{value:"Configure Permissions",id:"configure-permissions",children:[]},{value:"Test Lambda as an SQS Consumer Flow",id:"test-lambda-as-an-sqs-consumer-flow",children:[]},{value:"Conclusions",id:"conclusions",children:[]}],l={rightToc:c};function b(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Message queuing service enables you to decouple and scale microservices, distributed systems, and serverless applications. In this guide, we'll show you how to leverage a queue system (",Object(o.b)("inlineCode",{parentName:"p"},"Amazon SQS"),") to build a highly scalable backend."),Object(o.b)("p",null,"Using Amazon SQS eliminates the complexity and overhead associated with managing and operating message-oriented middleware and empowers developers to focus on differentiating work. With SQS, you can send, store, and receive messages between software components at any volume without losing messages or requiring other services to be available."),Object(o.b)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"In this guide, we'll create a backend microservice that sends messages on an event queue. Additionally, we'll go through two ways of consuming and processing those messages:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"We will use ",Object(o.b)("inlineCode",{parentName:"li"},"AWS Lambda")," to process events from the queue in a serverless way"),Object(o.b)("li",{parentName:"ul"},"We will use Qovery-managed backend application workers to process events from the queue")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/1.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"As for now, Qovery does not natively integrate with AWS Lambda and SQS, but the integration part is quite easy, and we will go through it in the following steps."),Object(o.b)("p",null,"The backend application and workers servers that consume messages from the queue will be fully managed and deployed by Qovery."),Object(o.b)("p",null,"Let's get started."),Object(o.b)("h2",{id:"configure-sqs"},"Configure SQS"),Object(o.b)("p",null,"Open ",Object(o.b)("inlineCode",{parentName:"p"},"Amazon SQS")," service in AWS Console and click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create Queue")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/2.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"We will use the ",Object(o.b)("inlineCode",{parentName:"p"},"Standard")," queue and leave all the settings in defaults for now. Type in the name of the queue and click ",Object(o.b)("inlineCode",{parentName:"p"},"Create"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/3.png",alt:"AWS SQS Lambda"})),Object(o.b)("h2",{id:"create-message-producer"},"Create Message Producer"),Object(o.b)("p",null,"In this step, we will deploy an app that pushes messages to the SQS queue. The source code of the app is available ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/aws-sqs-example/blob/main/index.js"}),"here"),"."),Object(o.b)("p",null,"The source code of the app is simple - it's a web server that sends messages to the SQS queue each time someone hits its API endpoint:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const command = new SendMessageCommand({});\n\nclient.send(command).then(\n (data) => {\n console.log(data);\n res.end('Success');\n // process data.\n },\n (error) => {\n console.error(error);\n res.end('Error');\n // error handling.\n }\n);\n")),Object(o.b)("p",null,"To deploy the app on Qovery, all you need to do is to fork the repository from above and create a new app adding port ",Object(o.b)("inlineCode",{parentName:"p"},"3000"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/4.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Afterwards, we need to add two environment variables:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"accessKeyId")," - your AWS access key ID"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"secretAccessKey")," - your AWS secret access key")),Object(o.b)("p",null,"You can add them in ",Object(o.b)("inlineCode",{parentName:"p"},"Environment Variebles")," ",Object(o.b)("inlineCode",{parentName:"p"},"Secret")," section in your application settings:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/5.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/6.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"After all the setup is all done, click the ",Object(o.b)("inlineCode",{parentName:"p"},"Deploy")," button - the application will be shortly deployed."),Object(o.b)("h2",{id:"create-lambda-consumers"},"Create Lambda Consumers"),Object(o.b)("p",null,"In AWS Console, open ",Object(o.b)("inlineCode",{parentName:"p"},"AWS Lambda")," panel."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/7.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"For the sake of the guide, we will use a simple ",Object(o.b)("inlineCode",{parentName:"p"},"hello-world")," lambda from AWS serverless app repository."),Object(o.b)("p",null,"Browse the app repository and pick the ",Object(o.b)("inlineCode",{parentName:"p"},"hello-world")," function as shown in the screenshot above, and deploy the function"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/8.png",alt:"AWS SQS Lambda"})),Object(o.b)("h2",{id:"create-lambda-trigger"},"Create Lambda Trigger"),Object(o.b)("p",null,"To make our Lambdas consume messages from SQS, we will need to add a ",Object(o.b)("inlineCode",{parentName:"p"},"Lambda Trigger")," in the SQS configuration."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/9.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Click on ",Object(o.b)("inlineCode",{parentName:"p"},"Configure Lambda Function Trigger")," as shown in the screenshot above and select your lambda function from the dropdown, then save the changes:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/10.png",alt:"AWS SQS Lambda"})),Object(o.b)("h2",{id:"configure-permissions"},"Configure Permissions"),Object(o.b)("p",null,"Let's now grant our Lambda functions access to the SQS queue we created before."),Object(o.b)("p",null,"In our lambda view, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Configure"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/11.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Then, click on a role in ",Object(o.b)("inlineCode",{parentName:"p"},"Execution role")," to get redirected to a view where we can alter our Lambda permissions."),Object(o.b)("p",null,"In the role summary screen, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Edit policy")," next to ",Object(o.b)("inlineCode",{parentName:"p"},"helloWorldrolePolicy")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/12.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"In the ",Object(o.b)("inlineCode",{parentName:"p"},"SQS")," section, grant permissions to all Read/Write options in the ",Object(o.b)("inlineCode",{parentName:"p"},"Actions")," ",Object(o.b)("inlineCode",{parentName:"p"},"Access level")," and accept the changes:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/13.png",alt:"AWS SQS Lambda"})),Object(o.b)("h2",{id:"test-lambda-as-an-sqs-consumer-flow"},"Test Lambda as an SQS Consumer Flow"),Object(o.b)("p",null,"To push messages to our SQS queue from the backend app deployed on Qovery, click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Open")," button in the application we deployed in the previous step. It will redirect you to the API endpoint exposed by the backend app - the logic inside the application is made so that it sends messages to the SQS queue."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/14.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"Now, in the ",Object(o.b)("inlineCode",{parentName:"p"},"Monitoring")," section of SQS in AWS Console, we will see messages received on metrics charts:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/15.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"To validate that our consumer Lambdas processed the messages, navigate to your lambda ",Object(o.b)("inlineCode",{parentName:"p"},"Monitor")," panel:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/16.png",alt:"AWS SQS Lambda"})),Object(o.b)("p",null,"In the ",Object(o.b)("inlineCode",{parentName:"p"},"Invocations")," chart, you'll notice that our Lambda was triggered several times by the messages sent over the SQS."),Object(o.b)("h2",{id:"conclusions"},"Conclusions"),Object(o.b)("p",null,"In this part of the tutorial, we learned how to send messages over from an application deployed on Qovery to SQS and consume them from serverless Lambda functions. In the next part, we will create a scalable group of worker applications deployed by Qovery that consume messages from the same Queue."))}b.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),b=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s({},t,{},e)),n},u=function(e){var t=b(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=b(n),m=a,p=u["".concat(i,".").concat(m)]||u[m]||d[m]||o;return n?r.a.createElement(p,s({ref:t},l,{components:n})):r.a.createElement(p,s({ref:t},l))}));function p(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s.mdxType="string"==typeof e?e:a,i[1]=s;for(var l=2;l1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,l=void 0===c?n:r(c,n);l>s;)t[s++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),s=n(432),c=n(20),l=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,b=n||c,u=Object(s.a)(b),d=Object(r.useRef)(!1),m=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&u&&window.docusaurus.prefetch(b),function(){m&&t&&t.disconnect()}}),[b,m,u]),b&&u?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(b),d.current=!0)},innerRef:function(e){var n,a;m&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:b})):o.a.createElement("a",Object(a.a)({},e,{href:b}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),i=n(423),s=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,l=e.size,b=e.target,u=e.to,d=s()("jump-to","jump-to--"+l,n),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return b?r.a.createElement("a",{href:u,target:b,className:d},m):r.a.createElement(o.a,{to:u,className:d},m)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/cc9be38a.8b9a5741.js.LICENSE.txt b/cbb976f4.11b76fa1.js.LICENSE.txt similarity index 100% rename from cc9be38a.8b9a5741.js.LICENSE.txt rename to cbb976f4.11b76fa1.js.LICENSE.txt diff --git a/cbcbf0e3.a6610e2f.js b/cbcbf0e3.1f027439.js similarity index 92% rename from cbcbf0e3.a6610e2f.js rename to cbcbf0e3.1f027439.js index 09001779e0..82a0e001e1 100644 --- a/cbcbf0e3.a6610e2f.js +++ b/cbcbf0e3.1f027439.js @@ -1,2 +1,2 @@ -/*! For license information please see cbcbf0e3.a6610e2f.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[210],{362:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return d}));var r=n(1),a=n(9),o=(n(0),n(422)),i=n(426),c=n(431),l={last_modified_on:"2023-03-31",$schema:"/.meta/.schemas/guides.json",title:"Customizing Preview URL with Qovery CLI",description:"How to customize preview url with qovery cli",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},u={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Customizing Preview URL with Qovery CLI",description:"How to customize preview url with qovery cli",permalink:"/guides/tutorial/customizing-preview-url-with-qovery-cli",readingTime:"3 min read",source:"@site/guides/tutorial/customizing-preview-url-with-qovery-cli.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Customizing Preview URL with Qovery CLI",truncated:!1,prevItem:{title:"Creating API clients using OpenAPI Tools",permalink:"/guides/tutorial/generate-qovery-api-client"},nextItem:{title:"Deploy API Gateway",permalink:"/guides/advanced/deploy-api-gateway"}},s=[{value:"Wrapping up",id:"wrapping-up",children:[]}],p={rightToc:s};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"In this quick guide, we will show you how to automatically customize your preview URL when a new environment has been created using the Qovery CLI. By following these steps, you can create a custom domain for your service and link it to your DNS provider."),Object(o.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI")," installed"),Object(o.b)("li",{parentName:"ul"},"Access to your DNS provider"))),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-custom-domain-for-your-service"},"Create a Custom Domain for Your Service"),Object(o.b)("p",null,"To create a custom domain for your service, run the following command in your terminal:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'# Get Pull Request ID from Qovery Environment Variables\n$ PR_ID=`qovery application env list -n "Backend" --show-values | grep "QOVERY_PROJECT_ID" | awk \'{print $10}\'`\n\n# Create a custom domain\n$ qovery application domain create -n "app name" --domain app-$PR_ID.domain.name\n')),Object(o.b)("p",null,"Replace ",Object(o.b)("inlineCode",{parentName:"p"},"app name")," with the name of your application and ",Object(o.b)("inlineCode",{parentName:"p"},"app.domain.name")," with your desired custom domain."),Object(o.b)("p",null,"User ",Object(o.b)("inlineCode",{parentName:"p"},"--organization"),", ",Object(o.b)("inlineCode",{parentName:"p"},"--project"),", ",Object(o.b)("inlineCode",{parentName:"p"},"--environment")," flags to specify the organization, project, and environment where you want to create the custom domain.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"retrieve-the-validation-domain"},"Retrieve the Validation Domain"),Object(o.b)("p",null,"To get the validation domain required for the next step, run the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ qovery application domain list -n "app name" | grep "app-$PR_ID.domain.name" | awk \'{print $7}\'\n')),Object(o.b)("p",null,"Replace ",Object(o.b)("inlineCode",{parentName:"p"},"app name")," and ",Object(o.b)("inlineCode",{parentName:"p"},"app.domain.name")," with the appropriate values. This command will output the validation domain.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-cname-record-in-your-dns-provider"},"Create a CNAME Record in Your DNS Provider"),Object(o.b)("p",null,"Use the validation domain from the previous step to create a CNAME record in your DNS provider. The CNAME record should point to the validation domain."),Object(o.b)("p",null,"Example with Route53:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ aws cli route53 change-resource-record-sets --hosted-zone-id "hosted zone id" --change-batch \'{"Changes":[{"Action":"CREATE","ResourceRecordSet":{"Name":"app-$PR_ID.domain.name","Type":"CNAME","TTL":300,"ResourceRecords":[{"Value":"validation-domain"}]}}]}\'\n')),Object(o.b)("p",null,"Example with Cloudflare:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records" \\\n -H "X-Auth-Email: {email}" \\\n -H "X-Auth-Key: {key}" \\\n -H "Content-Type: application/json" \\\n --data \'{"type":"CNAME","name":"app-$PR_ID.domain.name","content":"validation-domain","ttl":1,"proxied":false}\'\n')),Object(o.b)("p",null,"The idea here is to create a CNAME record that points to the validation domain. The validation domain is a temporary domain that is used to validate the ownership of the custom domain.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"redeploy-your-application"},"Redeploy your application"),Object(o.b)("p",null,"Once the DNS changes have propagated, redeploy your application to complete the process."),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ qovery application redeploy -n "app name" -w\n')),Object(o.b)("p",null,"Your application should now be available at ",Object(o.b)("inlineCode",{parentName:"p"},"app-{PR ID}.domain.name"),".")))),Object(o.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(o.b)("p",null,"Congratulations! You have successfully customized your preview URL using the Qovery CLI. Now, whenever a new environment is created, the custom domain will be automatically configured. If you encounter any issues, please reach out to our support team on the Qovery forum."))}d.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),m=r,b=p["".concat(i,".").concat(m)]||p[m]||d[m]||o;return n?a.a.createElement(b,c({ref:t},u,{components:n})):a.a.createElement(b,c({ref:t},u))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),s=Object(r.useState)(null),p=s[0],d=s[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see cbcbf0e3.1f027439.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[213],{365:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return d}));var r=n(1),a=n(9),o=(n(0),n(425)),i=n(429),c=n(434),l={last_modified_on:"2023-03-31",$schema:"/.meta/.schemas/guides.json",title:"Customizing Preview URL with Qovery CLI",description:"How to customize preview url with qovery cli",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},u={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Customizing Preview URL with Qovery CLI",description:"How to customize preview url with qovery cli",permalink:"/guides/tutorial/customizing-preview-url-with-qovery-cli",readingTime:"3 min read",source:"@site/guides/tutorial/customizing-preview-url-with-qovery-cli.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Customizing Preview URL with Qovery CLI",truncated:!1,prevItem:{title:"Creating API clients using OpenAPI Tools",permalink:"/guides/tutorial/generate-qovery-api-client"},nextItem:{title:"Deploy API Gateway",permalink:"/guides/advanced/deploy-api-gateway"}},s=[{value:"Wrapping up",id:"wrapping-up",children:[]}],p={rightToc:s};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"In this quick guide, we will show you how to automatically customize your preview URL when a new environment has been created using the Qovery CLI. By following these steps, you can create a custom domain for your service and link it to your DNS provider."),Object(o.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/interface/cli/"}),"Qovery CLI")," installed"),Object(o.b)("li",{parentName:"ul"},"Access to your DNS provider"))),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-custom-domain-for-your-service"},"Create a Custom Domain for Your Service"),Object(o.b)("p",null,"To create a custom domain for your service, run the following command in your terminal:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'# Get Pull Request ID from Qovery Environment Variables\n$ PR_ID=`qovery application env list -n "Backend" --show-values | grep "QOVERY_PROJECT_ID" | awk \'{print $10}\'`\n\n# Create a custom domain\n$ qovery application domain create -n "app name" --domain app-$PR_ID.domain.name\n')),Object(o.b)("p",null,"Replace ",Object(o.b)("inlineCode",{parentName:"p"},"app name")," with the name of your application and ",Object(o.b)("inlineCode",{parentName:"p"},"app.domain.name")," with your desired custom domain."),Object(o.b)("p",null,"User ",Object(o.b)("inlineCode",{parentName:"p"},"--organization"),", ",Object(o.b)("inlineCode",{parentName:"p"},"--project"),", ",Object(o.b)("inlineCode",{parentName:"p"},"--environment")," flags to specify the organization, project, and environment where you want to create the custom domain.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"retrieve-the-validation-domain"},"Retrieve the Validation Domain"),Object(o.b)("p",null,"To get the validation domain required for the next step, run the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ qovery application domain list -n "app name" | grep "app-$PR_ID.domain.name" | awk \'{print $7}\'\n')),Object(o.b)("p",null,"Replace ",Object(o.b)("inlineCode",{parentName:"p"},"app name")," and ",Object(o.b)("inlineCode",{parentName:"p"},"app.domain.name")," with the appropriate values. This command will output the validation domain.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-cname-record-in-your-dns-provider"},"Create a CNAME Record in Your DNS Provider"),Object(o.b)("p",null,"Use the validation domain from the previous step to create a CNAME record in your DNS provider. The CNAME record should point to the validation domain."),Object(o.b)("p",null,"Example with Route53:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ aws cli route53 change-resource-record-sets --hosted-zone-id "hosted zone id" --change-batch \'{"Changes":[{"Action":"CREATE","ResourceRecordSet":{"Name":"app-$PR_ID.domain.name","Type":"CNAME","TTL":300,"ResourceRecords":[{"Value":"validation-domain"}]}}]}\'\n')),Object(o.b)("p",null,"Example with Cloudflare:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records" \\\n -H "X-Auth-Email: {email}" \\\n -H "X-Auth-Key: {key}" \\\n -H "Content-Type: application/json" \\\n --data \'{"type":"CNAME","name":"app-$PR_ID.domain.name","content":"validation-domain","ttl":1,"proxied":false}\'\n')),Object(o.b)("p",null,"The idea here is to create a CNAME record that points to the validation domain. The validation domain is a temporary domain that is used to validate the ownership of the custom domain.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"redeploy-your-application"},"Redeploy your application"),Object(o.b)("p",null,"Once the DNS changes have propagated, redeploy your application to complete the process."),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'$ qovery application redeploy -n "app name" -w\n')),Object(o.b)("p",null,"Your application should now be available at ",Object(o.b)("inlineCode",{parentName:"p"},"app-{PR ID}.domain.name"),".")))),Object(o.b)("h2",{id:"wrapping-up"},"Wrapping up"),Object(o.b)("p",null,"Congratulations! You have successfully customized your preview URL using the Qovery CLI. Now, whenever a new environment is created, the custom domain will be automatically configured. If you encounter any issues, please reach out to our support team on the Qovery forum."))}d.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),m=r,b=p["".concat(i,".").concat(m)]||p[m]||d[m]||o;return n?a.a.createElement(b,c({ref:t},u,{components:n})):a.a.createElement(b,c({ref:t},u))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),s=Object(r.useState)(null),p=s[0],d=s[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/d2075f7f.ef775b77.js.LICENSE.txt b/cbcbf0e3.1f027439.js.LICENSE.txt similarity index 100% rename from d2075f7f.ef775b77.js.LICENSE.txt rename to cbcbf0e3.1f027439.js.LICENSE.txt diff --git a/cc9be38a.8b9a5741.js b/cc9be38a.958460f6.js similarity index 90% rename from cc9be38a.8b9a5741.js rename to cc9be38a.958460f6.js index a4dbcfd047..1c324d48bf 100644 --- a/cc9be38a.8b9a5741.js +++ b/cc9be38a.958460f6.js @@ -1,2 +1,2 @@ -/*! For license information please see cc9be38a.8b9a5741.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[211],{363:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),o=(n(0),n(422)),i=n(431),c=n(421),l=(n(485),n(426)),s={last_modified_on:"2023-11-24",$schema:"/.meta/.schemas/guides.json",title:"Hello World. Deploy your first application.",description:"How to deploy your first application with Qovery",series_position:1,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Hello World. Deploy your first application.",description:"How to deploy your first application with Qovery",permalink:"/guides/getting-started/deploy-your-first-application",readingTime:"2 min read",seriesPosition:1,source:"@site/guides/getting-started/deploy-your-first-application.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Hello World. Deploy your first application.",truncated:!1,nextItem:{title:"Create a database",permalink:"/guides/getting-started/create-a-database"}},p=[{value:"Step-by-step tutorial",id:"step-by-step-tutorial",children:[{value:"Sign up",id:"sign-up",children:[]},{value:"Install Qovery on your AWS account",id:"install-qovery-on-your-aws-account",children:[]},{value:"Deploy your first application",id:"deploy-your-first-application",children:[]}]},{value:"Next Steps",id:"next-steps",children:[]}],d={rightToc:p};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery is an easy way to deploy a full-stack application. Meaning, you can deploy a backend, frontend and a database seamlessly. In this guide, I'll show you how to deploy a template app."),Object(o.b)(l.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://github.com"}),"Github"),", ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://gitlab.com"}),"Gitlab")," or ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://bitbucket.com"}),"Bitbucket")," account"))),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you want to migrate from Heroku to AWS with Qovery? ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/migrate-your-application-from-heroku-to-aws/"}),"Check out this step-by-step guide"))),Object(o.b)("h2",{id:"step-by-step-tutorial"},"Step-by-step tutorial"),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h3",{id:"sign-up"},"Sign up"),Object(o.b)("p",null,"Sign in to the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web interface"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("a",{href:"https://onboarding.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.jpg",alt:"Qovery Sign-up page"})))),Object(o.b)("li",null,Object(o.b)("h3",{id:"install-qovery-on-your-aws-account"},"Install Qovery on your AWS account"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you want to deploy your apps on another cloud service provider than AWS? Click ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/cloud-provider"}),"here"),". Do you want to deploy Qovery on your Kubernetes cluster? Click ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/provider/guide-kubernetes/"}),"here"))),Object(o.b)("p",null,"Here is a video showing how to install Qovery on your AWS account. (Check out our written tutorial ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/cloud-provider/guide-amazon-web-services/"}),"here"),")"),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/3450aa0c4122467892cd7c6e1fc85f6e",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0})))),Object(o.b)("li",null,Object(o.b)("h3",{id:"deploy-your-first-application"},"Deploy your first application"),Object(o.b)("p",null,"Here is a short video showing how to deploy your app with the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery Web interface"),"."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/464c7b6f062e4e59bbd57ec238f88665",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)(c.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"That's it! your application is now deployed on your AWS account \ud83d\udcaa"))))),Object(o.b)("h2",{id:"next-steps"},"Next Steps"),Object(o.b)("p",null,"To deploy your application, it's as simple as that. In the following article, we will see how to add a database. Let's get started!"))}b.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),b=r,f=p["".concat(i,".").concat(b)]||p[b]||d[b]||o;return n?a.a.createElement(f,c({ref:t},s,{components:n})):a.a.createElement(f,c({ref:t},s))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(r.useState)(null),p=u[0],d=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},485:function(e,t,n){"use strict";var r=n(0),a=n.n(r);n(421),n(144);t.a=function(e){var t=e.children,n=Object(r.useState)(!1),o=n[0],i=n[1];return o?a.a.createElement("div",{className:"code-explanation code-explanation--expanded"},t,a.a.createElement("div",{className:"code-explanation--toggle",onClick:function(){return i(!o)}},a.a.createElement("i",{className:"feather icon-arrow-up-circle"})," hide")):a.a.createElement("div",{className:"code-explanation code-explanation--collapsed"},a.a.createElement("div",{className:"code-explanation--toggle",onClick:function(){return i(!o)}},a.a.createElement("i",{className:"feather icon-info"})," explain this command"))}}}]); \ No newline at end of file +/*! For license information please see cc9be38a.958460f6.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[214],{366:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),o=(n(0),n(425)),i=n(434),c=n(424),l=(n(488),n(429)),s={last_modified_on:"2023-11-24",$schema:"/.meta/.schemas/guides.json",title:"Hello World. Deploy your first application.",description:"How to deploy your first application with Qovery",series_position:1,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Hello World. Deploy your first application.",description:"How to deploy your first application with Qovery",permalink:"/guides/getting-started/deploy-your-first-application",readingTime:"2 min read",seriesPosition:1,source:"@site/guides/getting-started/deploy-your-first-application.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Hello World. Deploy your first application.",truncated:!1,nextItem:{title:"Create a database",permalink:"/guides/getting-started/create-a-database"}},p=[{value:"Step-by-step tutorial",id:"step-by-step-tutorial",children:[{value:"Sign up",id:"sign-up",children:[]},{value:"Install Qovery on your AWS account",id:"install-qovery-on-your-aws-account",children:[]},{value:"Deploy your first application",id:"deploy-your-first-application",children:[]}]},{value:"Next Steps",id:"next-steps",children:[]}],d={rightToc:p};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery is an easy way to deploy a full-stack application. Meaning, you can deploy a backend, frontend and a database seamlessly. In this guide, I'll show you how to deploy a template app."),Object(o.b)(l.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://github.com"}),"Github"),", ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://gitlab.com"}),"Gitlab")," or ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://bitbucket.com"}),"Bitbucket")," account"))),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you want to migrate from Heroku to AWS with Qovery? ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/migrate-your-application-from-heroku-to-aws/"}),"Check out this step-by-step guide"))),Object(o.b)("h2",{id:"step-by-step-tutorial"},"Step-by-step tutorial"),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h3",{id:"sign-up"},"Sign up"),Object(o.b)("p",null,"Sign in to the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web interface"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("a",{href:"https://onboarding.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.jpg",alt:"Qovery Sign-up page"})))),Object(o.b)("li",null,Object(o.b)("h3",{id:"install-qovery-on-your-aws-account"},"Install Qovery on your AWS account"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you want to deploy your apps on another cloud service provider than AWS? Click ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/cloud-provider"}),"here"),". Do you want to deploy Qovery on your Kubernetes cluster? Click ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/provider/guide-kubernetes/"}),"here"))),Object(o.b)("p",null,"Here is a video showing how to install Qovery on your AWS account. (Check out our written tutorial ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/cloud-provider/guide-amazon-web-services/"}),"here"),")"),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/3450aa0c4122467892cd7c6e1fc85f6e",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0})))),Object(o.b)("li",null,Object(o.b)("h3",{id:"deploy-your-first-application"},"Deploy your first application"),Object(o.b)("p",null,"Here is a short video showing how to deploy your app with the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery Web interface"),"."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/464c7b6f062e4e59bbd57ec238f88665",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)(c.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"That's it! your application is now deployed on your AWS account \ud83d\udcaa"))))),Object(o.b)("h2",{id:"next-steps"},"Next Steps"),Object(o.b)("p",null,"To deploy your application, it's as simple as that. In the following article, we will see how to add a database. Let's get started!"))}b.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),b=r,f=p["".concat(i,".").concat(b)]||p[b]||d[b]||o;return n?a.a.createElement(f,c({ref:t},s,{components:n})):a.a.createElement(f,c({ref:t},s))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(r.useState)(null),p=u[0],d=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},488:function(e,t,n){"use strict";var r=n(0),a=n.n(r);n(424),n(144);t.a=function(e){var t=e.children,n=Object(r.useState)(!1),o=n[0],i=n[1];return o?a.a.createElement("div",{className:"code-explanation code-explanation--expanded"},t,a.a.createElement("div",{className:"code-explanation--toggle",onClick:function(){return i(!o)}},a.a.createElement("i",{className:"feather icon-arrow-up-circle"})," hide")):a.a.createElement("div",{className:"code-explanation code-explanation--collapsed"},a.a.createElement("div",{className:"code-explanation--toggle",onClick:function(){return i(!o)}},a.a.createElement("i",{className:"feather icon-info"})," explain this command"))}}}]); \ No newline at end of file diff --git a/d2397242.e61c5e2d.js.LICENSE.txt b/cc9be38a.958460f6.js.LICENSE.txt similarity index 100% rename from d2397242.e61c5e2d.js.LICENSE.txt rename to cc9be38a.958460f6.js.LICENSE.txt diff --git a/cf490432.44c56ebb.js b/cf490432.eb4e2084.js similarity index 96% rename from cf490432.44c56ebb.js rename to cf490432.eb4e2084.js index 62e811aeee..6a6de3c18d 100644 --- a/cf490432.44c56ebb.js +++ b/cf490432.eb4e2084.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[212],{364:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return i})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return u}));var r=n(1),o=n(9),a=(n(0),n(422)),c={last_modified_on:"2023-03-17",title:"SOC2",description:"Systems and Organizations Controls 2"},i={id:"security-and-compliance/soc2",title:"SOC2",description:"Systems and Organizations Controls 2",source:"@site/docs/security-and-compliance/soc2.md",permalink:"/docs/security-and-compliance/soc2",sidebar:"docs",previous:{title:"GDPR",permalink:"/docs/security-and-compliance/gdpr"},next:{title:"FAQ",permalink:"/docs/useful-resources/faq"}},s=[{value:"Cluster advanced settings",id:"cluster-advanced-settings",children:[{value:"Log retention days",id:"log-retention-days",children:[]}]}],l={rightToc:s};function u(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,Object(a.b)("img",Object(r.a)({parentName:"p"},{src:"/img/soc2_logo.png",alt:null}))),Object(a.b)("p",null,"Qovery infrastructure and process comply with SOC2 (Systems and Organizations Controls 2) best practices. Qovery also brings by default many security features to your applications, clusters, and databases to comply with the most stringent security standards of SOC2.\nYou can find additional information on the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://trust.qovery.com/"}),"Qovery trust page"),"."),Object(a.b)("p",null,"All customers using Qovery, requiring to be SOC2 compliant, save a lot of time as the deployed infrastructure is SOC2 ready!"),Object(a.b)("p",null,"In this documentation, you will find settings to update to comply with SOC2 and even more."),Object(a.b)("h2",{id:"cluster-advanced-settings"},"Cluster advanced settings"),Object(a.b)("p",null,"In the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cluster-advanced-settings/"}),"cluster advanced settings"),", you will find several options to update based on your wishes and to comply with SOC2. Here are the most important ones:"),Object(a.b)("h3",{id:"log-retention-days"},"Log retention days"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"AWS Cloudwatch retention days (aws.cloudwatch.eks_logs_retention_days): 365 days is what SOC2 requests at least"),Object(a.b)("li",{parentName:"ul"},"Enable VPC flow logs (aws.vpc.enable_s3_flow_logs and aws.vpc.flow_logs_retention_days): Enable it and set the retention days to 365 days"),Object(a.b)("li",{parentName:"ul"},"Allowed databases CIDR: you have to disable or restrict public access, but not let them open to the world")))}u.isMDXComponent=!0},422:function(e,t,n){"use strict";n.d(t,"a",(function(){return d})),n.d(t,"b",(function(){return y}));var r=n(0),o=n.n(r);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=o.a.createContext({}),u=function(e){var t=o.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},d=function(e){var t=u(e.components);return o.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),d=u(n),b=r,y=d["".concat(c,".").concat(b)]||d[b]||p[b]||a;return n?o.a.createElement(y,i({ref:t},l,{components:n})):o.a.createElement(y,i({ref:t},l))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,c=new Array(a);c[0]=b;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var l=2;l=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=o.a.createContext({}),u=function(e){var t=o.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},d=function(e){var t=u(e.components);return o.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),d=u(n),b=r,y=d["".concat(c,".").concat(b)]||d[b]||p[b]||a;return n?o.a.createElement(y,i({ref:t},l,{components:n})):o.a.createElement(y,i({ref:t},l))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,c=new Array(a);c[0]=b;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var l=2;l - + - + - + - + - + - + - + - + @@ -45,19 +45,19 @@ - + - + - + - + - + - + - + diff --git a/components/index.html b/components/index.html index 3bd6101536..1a5c923642 100644 --- a/components/index.html +++ b/components/index.html @@ -21,22 +21,22 @@ - + - + - + - + - + - + - + - + @@ -45,19 +45,19 @@

Qovery Components

Components allow you to collect, transform, and route data with ease. Learn more.
The Qovery Logo
no components found
- + - + - + - + - + - + - + diff --git a/contact/index.html b/contact/index.html index 766fce7926..080d5cb8bb 100644 --- a/contact/index.html +++ b/contact/index.html @@ -21,22 +21,22 @@ - + - + - + - + - + - + - + - + @@ -45,19 +45,19 @@

Contact

Qovery is a Timber.io open-source product. You can contact the Qovery & Timber team using any of the options below.
- + - + - + - + - + - + - + diff --git a/d0db1526.ca14a6cf.js b/d0db1526.a16802df.js similarity index 96% rename from d0db1526.ca14a6cf.js rename to d0db1526.a16802df.js index 7b8d8cace9..6e045d7569 100644 --- a/d0db1526.ca14a6cf.js +++ b/d0db1526.a16802df.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[213],{365:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return u})),t.d(r,"metadata",(function(){return i})),t.d(r,"rightToc",(function(){return c})),t.d(r,"default",(function(){return p}));var o=t(1),n=t(9),a=(t(0),t(422)),u={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Microsoft Azure account",description:"Learn how to install Qovery on your Microsoft Azure account",author_github:"https://github.com/evoxmusic",tags:["type: guide","cloud_provider: azure"]},i={categories:[{name:"cloud-provider",title:"Cloud Provider",description:"Install Qovery on your favorite cloud provider.",permalink:"/guides/cloud-provider"}],coverLabel:"Install Qovery on your Microsoft Azure account",description:"Learn how to install Qovery on your Microsoft Azure account",permalink:"/guides/cloud-provider/guide-microsoft-azure",readingTime:"1 min read",source:"@site/guides/cloud-provider/guide-microsoft-azure.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"cloud_provider: azure",permalink:"/guides/tags/cloud-provider-azure"}],title:"Install Qovery on your Microsoft Azure account",truncated:!1,prevItem:{title:"Install Qovery on your Kubernetes cluster",permalink:"/guides/provider/guide-kubernetes"},nextItem:{title:"Install Qovery on your Scaleway account",permalink:"/guides/cloud-provider/guide-scaleway"}},c=[],l={rightToc:c};function p(e){var r=e.components,t=Object(n.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},l,t,{components:r,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Thank you for your interest! You are more and more to request the support of Qovery for ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://azure.microsoft.com"}),"Azure")," (Microsoft Azure). However, we do not support it yet. You have 2 ways of speed up the support:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Upvote the support of Microsoft Azure ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"https://roadmap.qovery.com/roadmap/support-azure"}),"here"),"."),Object(a.b)("li",{parentName:"ol"},"We are hiring backend and frontend engineers to build the future of the Cloud. It could be you? \ud83d\ude04 ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"https://jobs.qovery.com"}),"Apply here"))),Object(a.b)("p",null,"Today, Qovery supports the following Cloud providers:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/cloud-provider/guide-amazon-web-services/"}),"Amazon Web Services (AWS)")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/cloud-provider/guide-scaleway/"}),"Scaleway"))))}p.isMDXComponent=!0},422:function(e,r,t){"use strict";t.d(r,"a",(function(){return s})),t.d(r,"b",(function(){return f}));var o=t(0),n=t.n(o);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function u(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);r&&(o=o.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,o)}return t}function i(e){for(var r=1;r=0||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(n[t]=e[t])}return n}var l=n.a.createContext({}),p=function(e){var r=n.a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):i({},r,{},e)),t},s=function(e){var r=p(e.components);return n.a.createElement(l.Provider,{value:r},e.children)},d={inlineCode:"code",wrapper:function(e){var r=e.children;return n.a.createElement(n.a.Fragment,{},r)}},b=Object(o.forwardRef)((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,u=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),s=p(t),b=o,f=s["".concat(u,".").concat(b)]||s[b]||d[b]||a;return t?n.a.createElement(f,i({ref:r},l,{components:t})):n.a.createElement(f,i({ref:r},l))}));function f(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,u=new Array(a);u[0]=b;var i={};for(var c in r)hasOwnProperty.call(r,c)&&(i[c]=r[c]);i.originalType=e,i.mdxType="string"==typeof e?e:o,u[1]=i;for(var l=2;l=0||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(n[t]=e[t])}return n}var l=n.a.createContext({}),p=function(e){var r=n.a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):i({},r,{},e)),t},s=function(e){var r=p(e.components);return n.a.createElement(l.Provider,{value:r},e.children)},d={inlineCode:"code",wrapper:function(e){var r=e.children;return n.a.createElement(n.a.Fragment,{},r)}},b=Object(o.forwardRef)((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,u=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),s=p(t),b=o,f=s["".concat(u,".").concat(b)]||s[b]||d[b]||a;return t?n.a.createElement(f,i({ref:r},l,{components:t})):n.a.createElement(f,i({ref:r},l))}));function f(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,u=new Array(a);u[0]=b;var i={};for(var c in r)hasOwnProperty.call(r,c)&&(i[c]=r[c]);i.originalType=e,i.mdxType="string"==typeof e?e:o,u[1]=i;for(var l=2;l=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=o.a.createContext({}),s=function(e){var r=o.a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},p=function(e){var r=s(e.components);return o.a.createElement(l.Provider,{value:r},e.children)},f={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},d=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),p=s(t),d=n,y=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return t?o.a.createElement(y,c({ref:r},l,{components:t})):o.a.createElement(y,c({ref:r},l))}));function y(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var a=t.length,i=new Array(a);i[0]=d;var c={};for(var u in r)hasOwnProperty.call(r,u)&&(c[u]=r[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l1?arguments[1]:void 0,t),u=i>2?arguments[2]:void 0,l=void 0===u?t:o(u,t);l>c;)r[c++]=e;return r}}}]); \ No newline at end of file +/*! For license information please see d2075f7f.db5c8cdc.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[217],{422:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return c})),t.d(r,"metadata",(function(){return u})),t.d(r,"rightToc",(function(){return l})),t.d(r,"default",(function(){return p}));var n=t(1),o=t(9),a=(t(0),t(425)),i=t(424);t(423),t(369);var c={last_modified_on:"2023-04-12",title:"Help and Support",description:"Get support from Qovery team"},u={id:"useful-resources/help-and-support",title:"Help and Support",description:"Get support from Qovery team",source:"@site/docs/useful-resources/help-and-support.md",permalink:"/docs/useful-resources/help-and-support",sidebar:"docs",previous:{title:"FAQ",permalink:"/docs/useful-resources/faq"}},l=[{value:"Qovery support",id:"qovery-support",children:[]},{value:"Cloud provider support",id:"cloud-provider-support",children:[]}],s={rightToc:l};function p(e){var r=e.components,t=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},s,t,{components:r,mdxType:"MDXLayout"}),Object(a.b)("h2",{id:"qovery-support"},"Qovery support"),Object(a.b)("p",null,"If you need any help, you can:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Most common issues and solutions are listed in the ",Object(a.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/troubleshoot/"}),"troubleshooting section"),"."),Object(a.b)("li",{parentName:"ol"},Object(a.b)("a",Object(n.a)({parentName:"li"},{href:"https://discuss.qovery.com/"}),"Qovery Community Forum")," is the first place to tool at. You will find a lot of qualitative questions and answers."),Object(a.b)("li",{parentName:"ol"},"Finally, if you did not receive answers on the forum or if you have a big outage, you can contact us from the product on Intercom.")),Object(a.b)("p",null,"There, you can discuss directly with our fantastic team as well as our wonderful community!"),Object(a.b)("h2",{id:"cloud-provider-support"},"Cloud provider support"),Object(a.b)("p",null,"Qovery is responsible for deployed elements on your cloud provider made and maintained by Qovery. We are not responsible for the cloud provider itself."),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Qovery strongly advises you to take a support plan with your cloud provider. When outages occur, Qovery is limited to the elements given by the cloud provider, and sometimes does not have enough information to diagnose a service failure."),Object(a.b)("p",null,"In those cases, you will need to contact your cloud provider support. for investigation.")))}p.isMDXComponent=!0},423:function(e,r,t){var n;!function(){"use strict";var t={}.hasOwnProperty;function o(){for(var e=[],r=0;r=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=o.a.createContext({}),s=function(e){var r=o.a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},p=function(e){var r=s(e.components);return o.a.createElement(l.Provider,{value:r},e.children)},f={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},d=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),p=s(t),d=n,y=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return t?o.a.createElement(y,c({ref:r},l,{components:t})):o.a.createElement(y,c({ref:r},l))}));function y(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var a=t.length,i=new Array(a);i[0]=d;var c={};for(var u in r)hasOwnProperty.call(r,u)&&(c[u]=r[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l1?arguments[1]:void 0,t),u=i>2?arguments[2]:void 0,l=void 0===u?t:o(u,t);l>c;)r[c++]=e;return r}}}]); \ No newline at end of file diff --git a/d3437d81.ac367079.js.LICENSE.txt b/d2075f7f.db5c8cdc.js.LICENSE.txt similarity index 100% rename from d3437d81.ac367079.js.LICENSE.txt rename to d2075f7f.db5c8cdc.js.LICENSE.txt diff --git a/d2397242.e61c5e2d.js b/d2397242.58f80809.js similarity index 90% rename from d2397242.e61c5e2d.js rename to d2397242.58f80809.js index f932cc3b5c..73fc87de93 100644 --- a/d2397242.e61c5e2d.js +++ b/d2397242.58f80809.js @@ -1,2 +1,2 @@ -/*! For license information please see d2397242.e61c5e2d.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[215],{367:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),o=(n(0),n(422)),i=n(431),c=n(421),l=(n(485),n(426)),s={last_modified_on:"2023-11-24",$schema:"/.meta/.schemas/guides.json",title:"Hello World. Deploy your first application.",description:"How to deploy your first application with Qovery",series_position:1,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Hello World. Deploy your first application.",description:"How to deploy your first application with Qovery",permalink:"/guides/getting-started/deploy-your-first-application",readingTime:"2 min read",seriesPosition:1,source:"@site/guides/getting-started/deploy-your-first-application.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Hello World. Deploy your first application.",truncated:!1,nextItem:{title:"Create a database",permalink:"/guides/getting-started/create-a-database"}},p=[{value:"Step-by-step tutorial",id:"step-by-step-tutorial",children:[{value:"Sign up",id:"sign-up",children:[]},{value:"Install Qovery on your AWS account",id:"install-qovery-on-your-aws-account",children:[]},{value:"Deploy your first application",id:"deploy-your-first-application",children:[]}]},{value:"Next Steps",id:"next-steps",children:[]}],d={rightToc:p};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery is an easy way to deploy a full-stack application. Meaning, you can deploy a backend, frontend and a database seamlessly. In this guide, I'll show you how to deploy a template app."),Object(o.b)(l.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://github.com"}),"Github"),", ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://gitlab.com"}),"Gitlab")," or ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://bitbucket.com"}),"Bitbucket")," account"))),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you want to migrate from Heroku to AWS with Qovery? ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/migrate-your-application-from-heroku-to-aws/"}),"Check out this step-by-step guide"))),Object(o.b)("h2",{id:"step-by-step-tutorial"},"Step-by-step tutorial"),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h3",{id:"sign-up"},"Sign up"),Object(o.b)("p",null,"Sign in to the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web interface"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("a",{href:"https://onboarding.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.jpg",alt:"Qovery Sign-up page"})))),Object(o.b)("li",null,Object(o.b)("h3",{id:"install-qovery-on-your-aws-account"},"Install Qovery on your AWS account"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you want to deploy your apps on another cloud service provider than AWS? Click ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/cloud-provider"}),"here"),". Do you want to deploy Qovery on your Kubernetes cluster? Click ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/provider/guide-kubernetes/"}),"here"))),Object(o.b)("p",null,"Here is a video showing how to install Qovery on your AWS account. (Check out our written tutorial ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/cloud-provider/guide-amazon-web-services/"}),"here"),")"),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/3450aa0c4122467892cd7c6e1fc85f6e",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0})))),Object(o.b)("li",null,Object(o.b)("h3",{id:"deploy-your-first-application"},"Deploy your first application"),Object(o.b)("p",null,"Here is a short video showing how to deploy your app with the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery Web interface"),"."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/464c7b6f062e4e59bbd57ec238f88665",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)(c.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"That's it! your application is now deployed on your AWS account \ud83d\udcaa"))))),Object(o.b)("h2",{id:"next-steps"},"Next Steps"),Object(o.b)("p",null,"To deploy your application, it's as simple as that. In the following article, we will see how to add a database. Let's get started!"))}b.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),b=r,f=p["".concat(i,".").concat(b)]||p[b]||d[b]||o;return n?a.a.createElement(f,c({ref:t},s,{components:n})):a.a.createElement(f,c({ref:t},s))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(r.useState)(null),p=u[0],d=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},485:function(e,t,n){"use strict";var r=n(0),a=n.n(r);n(421),n(144);t.a=function(e){var t=e.children,n=Object(r.useState)(!1),o=n[0],i=n[1];return o?a.a.createElement("div",{className:"code-explanation code-explanation--expanded"},t,a.a.createElement("div",{className:"code-explanation--toggle",onClick:function(){return i(!o)}},a.a.createElement("i",{className:"feather icon-arrow-up-circle"})," hide")):a.a.createElement("div",{className:"code-explanation code-explanation--collapsed"},a.a.createElement("div",{className:"code-explanation--toggle",onClick:function(){return i(!o)}},a.a.createElement("i",{className:"feather icon-info"})," explain this command"))}}}]); \ No newline at end of file +/*! For license information please see d2397242.58f80809.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[218],{370:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),o=(n(0),n(425)),i=n(434),c=n(424),l=(n(488),n(429)),s={last_modified_on:"2023-11-24",$schema:"/.meta/.schemas/guides.json",title:"Hello World. Deploy your first application.",description:"How to deploy your first application with Qovery",series_position:1,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Hello World. Deploy your first application.",description:"How to deploy your first application with Qovery",permalink:"/guides/getting-started/deploy-your-first-application",readingTime:"2 min read",seriesPosition:1,source:"@site/guides/getting-started/deploy-your-first-application.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Hello World. Deploy your first application.",truncated:!1,nextItem:{title:"Create a database",permalink:"/guides/getting-started/create-a-database"}},p=[{value:"Step-by-step tutorial",id:"step-by-step-tutorial",children:[{value:"Sign up",id:"sign-up",children:[]},{value:"Install Qovery on your AWS account",id:"install-qovery-on-your-aws-account",children:[]},{value:"Deploy your first application",id:"deploy-your-first-application",children:[]}]},{value:"Next Steps",id:"next-steps",children:[]}],d={rightToc:p};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery is an easy way to deploy a full-stack application. Meaning, you can deploy a backend, frontend and a database seamlessly. In this guide, I'll show you how to deploy a template app."),Object(o.b)(l.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://github.com"}),"Github"),", ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://gitlab.com"}),"Gitlab")," or ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://bitbucket.com"}),"Bitbucket")," account"))),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you want to migrate from Heroku to AWS with Qovery? ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/migrate-your-application-from-heroku-to-aws/"}),"Check out this step-by-step guide"))),Object(o.b)("h2",{id:"step-by-step-tutorial"},"Step-by-step tutorial"),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h3",{id:"sign-up"},"Sign up"),Object(o.b)("p",null,"Sign in to the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web interface"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("a",{href:"https://onboarding.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.jpg",alt:"Qovery Sign-up page"})))),Object(o.b)("li",null,Object(o.b)("h3",{id:"install-qovery-on-your-aws-account"},"Install Qovery on your AWS account"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Do you want to deploy your apps on another cloud service provider than AWS? Click ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/cloud-provider"}),"here"),". Do you want to deploy Qovery on your Kubernetes cluster? Click ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/provider/guide-kubernetes/"}),"here"))),Object(o.b)("p",null,"Here is a video showing how to install Qovery on your AWS account. (Check out our written tutorial ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/cloud-provider/guide-amazon-web-services/"}),"here"),")"),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/3450aa0c4122467892cd7c6e1fc85f6e",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0})))),Object(o.b)("li",null,Object(o.b)("h3",{id:"deploy-your-first-application"},"Deploy your first application"),Object(o.b)("p",null,"Here is a short video showing how to deploy your app with the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery Web interface"),"."),Object(o.b)("div",{class:"video-container"},Object(o.b)("p",{align:"center"},Object(o.b)("iframe",{src:"https://www.loom.com/embed/464c7b6f062e4e59bbd57ec238f88665",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(o.b)(c.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"That's it! your application is now deployed on your AWS account \ud83d\udcaa"))))),Object(o.b)("h2",{id:"next-steps"},"Next Steps"),Object(o.b)("p",null,"To deploy your application, it's as simple as that. In the following article, we will see how to add a database. Let's get started!"))}b.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),b=r,f=p["".concat(i,".").concat(b)]||p[b]||d[b]||o;return n?a.a.createElement(f,c({ref:t},s,{components:n})):a.a.createElement(f,c({ref:t},s))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=b;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(r.useState)(null),p=u[0],d=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},488:function(e,t,n){"use strict";var r=n(0),a=n.n(r);n(424),n(144);t.a=function(e){var t=e.children,n=Object(r.useState)(!1),o=n[0],i=n[1];return o?a.a.createElement("div",{className:"code-explanation code-explanation--expanded"},t,a.a.createElement("div",{className:"code-explanation--toggle",onClick:function(){return i(!o)}},a.a.createElement("i",{className:"feather icon-arrow-up-circle"})," hide")):a.a.createElement("div",{className:"code-explanation code-explanation--collapsed"},a.a.createElement("div",{className:"code-explanation--toggle",onClick:function(){return i(!o)}},a.a.createElement("i",{className:"feather icon-info"})," explain this command"))}}}]); \ No newline at end of file diff --git a/d589d3a7.c5453097.js.LICENSE.txt b/d2397242.58f80809.js.LICENSE.txt similarity index 100% rename from d589d3a7.c5453097.js.LICENSE.txt rename to d2397242.58f80809.js.LICENSE.txt diff --git a/d24a1a4d.d232069e.js b/d24a1a4d.1cedb6af.js similarity index 74% rename from d24a1a4d.d232069e.js rename to d24a1a4d.1cedb6af.js index 5aed33a2cc..eb14745912 100644 --- a/d24a1a4d.d232069e.js +++ b/d24a1a4d.1cedb6af.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[216],{368:function(p){p.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"cloud-provider-gcp","name":"cloud_provider: gcp","count":1,"permalink":"/guides/tags/cloud-provider-gcp"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[219],{371:function(p){p.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"cloud-provider-gcp","name":"cloud_provider: gcp","count":1,"permalink":"/guides/tags/cloud-provider-gcp"}')}}]); \ No newline at end of file diff --git a/d28d5470.3541801e.js b/d28d5470.ed439387.js similarity index 94% rename from d28d5470.3541801e.js rename to d28d5470.ed439387.js index 5f5c142178..b6f030399c 100644 --- a/d28d5470.3541801e.js +++ b/d28d5470.ed439387.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[217],{369:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return a})),r.d(t,"metadata",(function(){return c})),r.d(t,"rightToc",(function(){return u})),r.d(t,"default",(function(){return l}));var n=r(1),o=r(9),i=(r(0),r(422)),a={last_modified_on:"2022-06-15",title:"API",description:"Learn how to use the Qovery API"},c={id:"using-qovery/integration/api-integration",title:"API",description:"Learn how to use the Qovery API",source:"@site/docs/using-qovery/integration/api-integration.md",permalink:"/docs/using-qovery/integration/api-integration",sidebar:"docs",previous:{title:"Webhooks",permalink:"/docs/using-qovery/integration/webhook"},next:{title:"Slack",permalink:"/docs/using-qovery/integration/slack"}},u=[],p={rightToc:u};function l(e){var t=e.components,r=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(n.a)({},p,r,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"Check out ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/interface/rest-api/"}),"our REST API page"),"."))}l.isMDXComponent=!0},422:function(e,t,r){"use strict";r.d(t,"a",(function(){return s})),r.d(t,"b",(function(){return b}));var n=r(0),o=r.n(n);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var p=o.a.createContext({}),l=function(e){var t=o.a.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},s=function(e){var t=l(e.components);return o.a.createElement(p.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},y=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,a=e.parentName,p=u(e,["components","mdxType","originalType","parentName"]),s=l(r),y=n,b=s["".concat(a,".").concat(y)]||s[y]||f[y]||i;return r?o.a.createElement(b,c({ref:t},p,{components:r})):o.a.createElement(b,c({ref:t},p))}));function b(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,a=new Array(i);a[0]=y;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,a[1]=c;for(var p=2;p=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var p=o.a.createContext({}),l=function(e){var t=o.a.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},s=function(e){var t=l(e.components);return o.a.createElement(p.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},y=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,a=e.parentName,p=u(e,["components","mdxType","originalType","parentName"]),s=l(r),y=n,b=s["".concat(a,".").concat(y)]||s[y]||f[y]||i;return r?o.a.createElement(b,c({ref:t},p,{components:r})):o.a.createElement(b,c({ref:t},p))}));function b(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,a=new Array(i);a[0]=y;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,a[1]=c;for(var p=2;p=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),d=a,y=b["".concat(c,".").concat(d)]||b[d]||p[d]||o;return n?r.a.createElement(y,i({ref:t},s,{components:n})):r.a.createElement(y,i({ref:t},s))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,c=new Array(o);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:a,c[1]=i;for(var s=2;s1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>i;)t[i++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var a=n(432),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var c=[];return r.slice().forEach((function(e){void 0!==e&&c.push(n(a,e,c.length))})),c.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(420),n(428)),c=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),u=Object(a.useState)(null),b=u[0],p=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see d3437d81.a62bb90b.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[221],{373:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return d}));var a=n(1),r=n(9),o=(n(0),n(425)),c=n(434),i=n(424),l=n(429),s={last_modified_on:"2023-12-11",title:"Scaleway (SCW)",description:"Learn how to configure and plug your Scaleway (SCW) account"},u={id:"using-qovery/configuration/cloud-service-provider/scaleway",title:"Scaleway (SCW)",description:"Learn how to configure and plug your Scaleway (SCW) account",source:"@site/docs/using-qovery/configuration/cloud-service-provider/scaleway.md",permalink:"/docs/using-qovery/configuration/cloud-service-provider/scaleway",sidebar:"docs",previous:{title:"Microsoft Azure",permalink:"/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure"},next:{title:"Other Cloud Service Provider",permalink:"/docs/using-qovery/configuration/cloud-service-provider/other-csps"}},b=[{value:"Getting started",id:"getting-started",children:[{value:"Connect your Scaleway account",id:"connect-your-scaleway-account",children:[]},{value:"Install a new cluster on Qovery",id:"install-a-new-cluster-on-qovery",children:[]},{value:"Remove your Scaleway account",id:"remove-your-scaleway-account",children:[]},{value:"Delete Qovery from your Scaleway account",id:"delete-qovery-from-your-scaleway-account",children:[]}]},{value:"Regions",id:"regions",children:[]},{value:"How Qovery works on Scaleway",id:"how-qovery-works-on-scaleway",children:[{value:"Kubernetes",id:"kubernetes",children:[]},{value:"Managed services",id:"managed-services",children:[]},{value:"Security and compliance",id:"security-and-compliance",children:[]}]},{value:"FAQ",id:"faq",children:[{value:"How to choose a region?",id:"how-to-choose-a-region",children:[]},{value:"I don't find a region that is provided by Scaleway",id:"i-dont-find-a-region-that-is-provided-by-scaleway",children:[]},{value:"Migrate between Cloud providers and regions",id:"migrate-between-cloud-providers-and-regions",children:[]}]}],p={rightToc:b};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Please refer to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/provider/kubernetes/"}),"this page")," if you want to install Qovery on your own Kubernetes cluster (BYOK).")),Object(o.b)("p",null,"Qovery lets you quickly deploy applications to your ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.scaleway.com"}),"Scaleway (Scaleway)")," account. No knowledge needed, and it takes less than 10 minutes to install Qovery on your Scaleway account."),Object(o.b)("h2",{id:"getting-started"},"Getting started"),Object(o.b)(l.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/interface/"}),"Qovery")," account"),Object(o.b)("li",{parentName:"ul"},"You have created an ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization")),Object(o.b)("li",{parentName:"ul"},"You have a Scaleway account"))),Object(o.b)("h3",{id:"connect-your-scaleway-account"},"Connect your Scaleway account"),Object(o.b)("p",null,"To link your Scaleway account to Qovery you need to provide a Scaleway ",Object(o.b)("inlineCode",{parentName:"p"},"access key id"),", ",Object(o.b)("inlineCode",{parentName:"p"},"secret access key"),", ",Object(o.b)("inlineCode",{parentName:"p"},"organization id")," and a ",Object(o.b)("inlineCode",{parentName:"p"},"project id"),"."),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,'If your Scaleway account is new, you need to open a ticket to Scaleway support to unlock your quota. You can post the following message:\n"Hello, I am going to deploy my applications on Scaleway with Qovery. Can you increase my quota for current Kubernetes nodes type, to 10 please? Thanks"')),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"You can link more than one Scaleway account. Qovery also support multiple Cloud providers within the same Organization. Meaning, you can balance your workload on different Cloud providers. ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/advanced/"}),"Read more"),".")),Object(o.b)("h4",{id:"create-your-scaleway-credentials---access-key-id-secret-access-key-organization-id-and-project-id"},"Create your Scaleway credentials - ",Object(o.b)("inlineCode",{parentName:"h4"},"access key id"),", ",Object(o.b)("inlineCode",{parentName:"h4"},"secret access key"),", ",Object(o.b)("inlineCode",{parentName:"h4"},"organization id")," and ",Object(o.b)("inlineCode",{parentName:"h4"},"project id"),"."),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.scaleway.com"}),"Connect to your Scaleway console"))),Object(o.b)("li",null,Object(o.b)("p",null,"Go to ",Object(o.b)("inlineCode",{parentName:"p"},"IAM")),Object(o.b)("img",{src:"/img/scw-api-key/scw_IAM.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Go to ",Object(o.b)("inlineCode",{parentName:"p"},"Applications")),Object(o.b)("img",{src:"/img/scw-api-key/scw_applications.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Create a new application for your project"),Object(o.b)("img",{src:"/img/scw-api-key/scw_create_app.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Generate your new API key from your application view"),Object(o.b)("img",{src:"/img/scw-api-key/scw_create_key_1.png"}),"Set up the the preferred `Project` for `Object Storage` with your Scaleway Project",Object(o.b)("img",{src:"/img/scw-api-key/scw_create_key_2.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Save the generated ",Object(o.b)("inlineCode",{parentName:"p"},"access key id")," and ",Object(o.b)("inlineCode",{parentName:"p"},"secret access key"),"."),Object(o.b)("img",{src:"/img/scw-api-key/scw_creds.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Go to ",Object(o.b)("inlineCode",{parentName:"p"},"Policies")),Object(o.b)("img",{src:"/img/scw-api-key/scw_policies.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Create a new policy with ",Object(o.b)("inlineCode",{parentName:"p"},"Principal")," linked to the application you just created."),Object(o.b)("img",{src:"/img/scw-api-key/scw_create_policy.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Set the scope of the policy to your project"),Object(o.b)("img",{src:"/img/scw-api-key/scw_policy_scope.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Select the following rules for your policy"),Object(o.b)("ul",null,Object(o.b)("li",null,"Containers permissions",Object(o.b)("br",null),Object(o.b)("img",{src:"/img/scw-api-key/scw_perms_containers.png"})),Object(o.b)("li",null,"Network Service permissions",Object(o.b)("br",null),Object(o.b)("img",{src:"/img/scw-api-key/scw_perms_network.png"})),Object(o.b)("li",null,"Compute permissions",Object(o.b)("br",null),Object(o.b)("img",{src:"/img/scw-api-key/scw_perms_compute.png"})),Object(o.b)("li",null,"Storage permissions",Object(o.b)("br",null),Object(o.b)("img",{src:"/img/scw-api-key/scw_perms_storage.png"})),Object(o.b)("li",null,"VPC permissions",Object(o.b)("br",null),Object(o.b)("img",{src:"/img/scw-api-key/scw_perms_vpc.png"})))),Object(o.b)("li",null,Object(o.b)("p",null,"Create your policy"),Object(o.b)("img",{src:"/img/scw-api-key/scw_apply_policy.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Get your ",Object(o.b)("inlineCode",{parentName:"p"},"organization id")," in your ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.scaleway.com/organization/settings"}),"organization settings")),Object(o.b)("img",{src:"/img/scw-api-key/scw_organization_id.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Get your ",Object(o.b)("inlineCode",{parentName:"p"},"project id")," on your project dashboard"),Object(o.b)("img",{src:"/img/scw-api-key/scw_project_id.png"})))),Object(o.b)("p",null,"Well done!! You now have your Scaleway ",Object(o.b)("inlineCode",{parentName:"p"},"access key id"),", ",Object(o.b)("inlineCode",{parentName:"p"},"secret access key"),", ",Object(o.b)("inlineCode",{parentName:"p"},"organization_id")," and ",Object(o.b)("inlineCode",{parentName:"p"},"project id"),"; It is time to connect Qovery to your Scaleway account."),Object(o.b)("h3",{id:"install-a-new-cluster-on-qovery"},"Install a new cluster on Qovery"),Object(o.b)("p",null,"You will be able to use the credentials you just generated when creating a cluster via the Qovery console. This cluster will be linked to your Qovery organization.\nFollow ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"this documentation")," to create a new cluster on your organization."),Object(o.b)("h3",{id:"remove-your-scaleway-account"},"Remove your Scaleway account"),Object(o.b)("p",null,Object(o.b)("em",{parentName:"p"},"this section is under development - ",Object(o.b)("a",Object(a.a)({parentName:"em"},{href:"https://discord.qovery.com"}),"join us")," and be part of the first to try it")),Object(o.b)("h3",{id:"delete-qovery-from-your-scaleway-account"},"Delete Qovery from your Scaleway account"),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Your applications and your data will be deleted.")),Object(o.b)("p",null,"To delete Qovery from your Scaleway account you must be the owner of the Organization.\nOnce your Scaleway account removed from Qovery, everything configured (VPC, Kubernetes, databases, ...) by Qovery will be deleted forever."),Object(o.b)("h2",{id:"regions"},"Regions"),Object(o.b)("p",null,"Qovery supports the following Scalewav regions:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null})),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"name"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"description"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddeb\ud83c\uddf7"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"fr-par-1"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Paris DC1 (France)")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddeb\ud83c\uddf7"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"fr-par-2"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Paris DC2 (France)")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddeb\ud83c\uddf7"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"fr-par-3"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Paris DC3 (France)")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddf3\ud83c\uddf1"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"nl-ams-1"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Amsterdam DC1 (Netherlands)")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"\ud83c\uddf5\ud83c\uddf1"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"pl-waw-1"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Warsaw DC1 (Poland)")))),Object(o.b)("p",null,"Qovery supports regions where ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.scaleway.com/en/kubernetes-kapsule/"}),"Scaleway Kubernetes (Kapsule)")," is supported."),Object(o.b)("h2",{id:"how-qovery-works-on-scaleway"},"How Qovery works on Scaleway"),Object(o.b)("p",null,"Qovery is an abstraction layer on top of Scaleway and Kubernetes. Qovery manages the configuration of Scaleway account, and helps you to deploy production ready apps in seconds.\nTo make it works, Qovery rely on Kubernetes for stateless apps (containers), and Scaleway for stateful apps (databases, storage...)."),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/getting-started/how-qovery-works/"}),"Read more")," on how Qovery works behind the scene."),Object(o.b)("h3",{id:"kubernetes"},"Kubernetes"),Object(o.b)("p",null,"The first time you set up your Scaleway account, Qovery creates a Kubernetes cluster in your chosen region. Qovery managed it for you - no action required. It takes ~15 minutes to configure and bootstrap a Kubernetes cluster. Once bootstrapped, your Kubernetes cluster runs the Qovery app and is ready to deploy your applications."),Object(o.b)("h3",{id:"managed-services"},"Managed services"),Object(o.b)("p",null,"Scaleway provides managed services for ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/postgresql/"}),"PostgreSQL"),", ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/mysql/"}),"MySQL"),", ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/redis/"}),"Redis"),", ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/mongodb/"}),"MongoDB"),". Qovery gives you access to those services when you set the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/deployment-rule/#environment-deployment-rules"}),"environment mode")," to ",Object(o.b)("inlineCode",{parentName:"p"},"Production"),". In ",Object(o.b)("inlineCode",{parentName:"p"},"Development")," mode, Qovery provides containers equivalent, which is cheaper and faster to start."),Object(o.b)("h3",{id:"security-and-compliance"},"Security and compliance"),Object(o.b)("p",null,"Qovery runs your Kubernetes cluster and is autonomous to manage your applications, which means:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Your configuration are stored on your Scaleway account."),Object(o.b)("li",{parentName:"ul"},"Your configuration is encrypted on your Scaleway account."),Object(o.b)("li",{parentName:"ul"},"Qovery can't access to your data."),Object(o.b)("li",{parentName:"ul"},"Suppose Qovery stops to run, your applications are not impacted.")),Object(o.b)("h2",{id:"faq"},"FAQ"),Object(o.b)("h3",{id:"how-to-choose-a-region"},"How to choose a region?"),Object(o.b)("p",null,"Different datacenters are located in different geographic areas, and you may want to keep your site physically close to the bulk of your user base for reduced latency."),Object(o.b)("h3",{id:"i-dont-find-a-region-that-is-provided-by-scaleway"},"I don't find a region that is provided by Scaleway"),Object(o.b)("p",null,"We are probably testing the support of this region, please ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/contact"}),"contact us")," to know what's the status"),Object(o.b)("h3",{id:"migrate-between-cloud-providers-and-regions"},"Migrate between Cloud providers and regions"),Object(o.b)("p",null,"Today, you can't migrate an environment from one region to another after it has been created. Vote ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://roadmap.qovery.com/"}),"here")," if you need this feature."))}d.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),d=a,y=b["".concat(c,".").concat(d)]||b[d]||p[d]||o;return n?r.a.createElement(y,i({ref:t},s,{components:n})):r.a.createElement(y,i({ref:t},s))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,c=new Array(o);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:a,c[1]=i;for(var s=2;s1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>i;)t[i++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var a=n(435),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var c=[];return r.slice().forEach((function(e){void 0!==e&&c.push(n(a,e,c.length))})),c.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(423),n(433)),c=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),u=Object(a.useState)(null),b=u[0],p=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/da253275.e887eb13.js.LICENSE.txt b/d3437d81.a62bb90b.js.LICENSE.txt similarity index 100% rename from da253275.e887eb13.js.LICENSE.txt rename to d3437d81.a62bb90b.js.LICENSE.txt diff --git a/d471c358.89f970db.js b/d471c358.070724b2.js similarity index 94% rename from d471c358.89f970db.js rename to d471c358.070724b2.js index a45047b4ab..e34060bc9e 100644 --- a/d471c358.89f970db.js +++ b/d471c358.070724b2.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[219],{371:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return l}));var r=n(1),o=n(9),a=(n(0),n(422)),i={last_modified_on:"2022-02-23",title:"Datadog",description:"Learn how to configure and plug your Datadog account"},c={id:"using-qovery/integration/monitoring/datadog",title:"Datadog",description:"Learn how to configure and plug your Datadog account",source:"@site/docs/using-qovery/integration/monitoring/datadog.md",permalink:"/docs/using-qovery/integration/monitoring/datadog",sidebar:"docs",previous:{title:"Monitoring",permalink:"/docs/using-qovery/integration/monitoring"},next:{title:"New Relic",permalink:"/docs/using-qovery/integration/monitoring/new-relic"}},u=[],p={rightToc:u};function l(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Datadog is a recommended product to monitor and track down your application performance issue (APM). Qovery supports and recommends using Datadog (or another monitoring/observability platform).\nCheck out our tutorial to know ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/"}),"how to integrate Datadog with Qovery"),"."))}l.isMDXComponent=!0},422:function(e,t,n){"use strict";n.d(t,"a",(function(){return d})),n.d(t,"b",(function(){return g}));var r=n(0),o=n.n(r);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=o.a.createContext({}),l=function(e){var t=o.a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},d=function(e){var t=l(e.components);return o.a.createElement(p.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,p=u(e,["components","mdxType","originalType","parentName"]),d=l(n),f=r,g=d["".concat(i,".").concat(f)]||d[f]||s[f]||a;return n?o.a.createElement(g,c({ref:t},p,{components:n})):o.a.createElement(g,c({ref:t},p))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=f;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var p=2;p=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=o.a.createContext({}),l=function(e){var t=o.a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},d=function(e){var t=l(e.components);return o.a.createElement(p.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,p=u(e,["components","mdxType","originalType","parentName"]),d=l(n),f=r,g=d["".concat(i,".").concat(f)]||d[f]||s[f]||a;return n?o.a.createElement(g,c({ref:t},p,{components:n})):o.a.createElement(g,c({ref:t},p))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=f;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var p=2;p=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),p=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},l=function(e){var t=p(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),l=p(n),f=r,m=l["".concat(c,".").concat(f)]||l[f]||d[f]||o;return n?a.a.createElement(m,i({ref:t},u,{components:n})):a.a.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,c=new Array(o);c[0]=f;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var u=2;u0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:p})):o.a.createElement("a",Object(r.a)({},e,{href:p}))}},429:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(427),c=n(420),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,p=e.target,l=e.to,d=i()("jump-to","jump-to--"+u,n),f=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},c&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+c})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return p?a.a.createElement("a",{href:l,target:p,className:d},f):a.a.createElement(o.a,{to:l,className:d},f)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file +/*! For license information please see d589d3a7.6f7b206e.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[224],{376:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),o=(n(0),n(425)),c=n(431),i={last_modified_on:"2023-12-11",title:"Getting started",description:"About Qovery, the platform that accelerates and scales application development cycle with zero infrastructure management investment.",sidebar_label:"hidden",hide_pagination:!0},s={id:"getting-started",title:"Getting started",description:"About Qovery, the platform that accelerates and scales application development cycle with zero infrastructure management investment.",source:"@site/docs/getting-started.md",permalink:"/docs/getting-started",sidebar_label:"hidden",sidebar:"docs",next:{title:"What is Qovery?",permalink:"/docs/getting-started/what-is-qovery"}},u=[],p={rightToc:u};function l(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"This section covers the basic concepts of Qovery and provides a foundation for the rest of the documentation."),Object(o.b)(c.a,{to:"/docs/getting-started/basic-concepts/",mdxType:"Jump"},"Basic concepts"),Object(o.b)(c.a,{to:"/docs/getting-started/deploy-my-app/",mdxType:"Jump"},"Deploy my app"),Object(o.b)(c.a,{to:"/docs/getting-started/how-qovery-works/",mdxType:"Jump"},"How qovery works"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/",mdxType:"Jump"},"Install qovery"),Object(o.b)(c.a,{to:"/docs/getting-started/what-is-qovery/",mdxType:"Jump"},"What is qovery"),Object(o.b)(c.a,{to:"/docs/getting-started/whats-next/",mdxType:"Jump"},"Whats next"))}l.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),p=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},l=function(e){var t=p(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),l=p(n),f=r,m=l["".concat(c,".").concat(f)]||l[f]||d[f]||o;return n?a.a.createElement(m,i({ref:t},u,{components:n})):a.a.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,c=new Array(o);c[0]=f;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var u=2;u0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:p})):o.a.createElement("a",Object(r.a)({},e,{href:p}))}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(430),c=n(423),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,p=e.target,l=e.to,d=i()("jump-to","jump-to--"+u,n),f=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},c&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+c})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return p?a.a.createElement("a",{href:l,target:p,className:d},f):a.a.createElement(o.a,{to:l,className:d},f)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/dab3a2be.12f5c1ea.js.LICENSE.txt b/d589d3a7.6f7b206e.js.LICENSE.txt similarity index 100% rename from dab3a2be.12f5c1ea.js.LICENSE.txt rename to d589d3a7.6f7b206e.js.LICENSE.txt diff --git a/d64bf575.7a23a0bd.js b/d64bf575.12c6773a.js similarity index 96% rename from d64bf575.7a23a0bd.js rename to d64bf575.12c6773a.js index f4f36aa453..68f86d4c13 100644 --- a/d64bf575.7a23a0bd.js +++ b/d64bf575.12c6773a.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[222],{374:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return u})),t.d(r,"metadata",(function(){return i})),t.d(r,"rightToc",(function(){return c})),t.d(r,"default",(function(){return p}));var o=t(1),n=t(9),a=(t(0),t(422)),u={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Microsoft Azure account",description:"Learn how to install Qovery on your Microsoft Azure account",author_github:"https://github.com/evoxmusic",tags:["type: guide","cloud_provider: azure"]},i={categories:[{name:"cloud-provider",title:"Cloud Provider",description:"Install Qovery on your favorite cloud provider.",permalink:"/guides/cloud-provider"}],coverLabel:"Install Qovery on your Microsoft Azure account",description:"Learn how to install Qovery on your Microsoft Azure account",permalink:"/guides/cloud-provider/guide-microsoft-azure",readingTime:"1 min read",source:"@site/guides/cloud-provider/guide-microsoft-azure.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"cloud_provider: azure",permalink:"/guides/tags/cloud-provider-azure"}],title:"Install Qovery on your Microsoft Azure account",truncated:!1,prevItem:{title:"Install Qovery on your Kubernetes cluster",permalink:"/guides/provider/guide-kubernetes"},nextItem:{title:"Install Qovery on your Scaleway account",permalink:"/guides/cloud-provider/guide-scaleway"}},c=[],l={rightToc:c};function p(e){var r=e.components,t=Object(n.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},l,t,{components:r,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Thank you for your interest! You are more and more to request the support of Qovery for ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://azure.microsoft.com"}),"Azure")," (Microsoft Azure). However, we do not support it yet. You have 2 ways of speed up the support:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Upvote the support of Microsoft Azure ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"https://roadmap.qovery.com/roadmap/support-azure"}),"here"),"."),Object(a.b)("li",{parentName:"ol"},"We are hiring backend and frontend engineers to build the future of the Cloud. It could be you? \ud83d\ude04 ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"https://jobs.qovery.com"}),"Apply here"))),Object(a.b)("p",null,"Today, Qovery supports the following Cloud providers:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/cloud-provider/guide-amazon-web-services/"}),"Amazon Web Services (AWS)")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/cloud-provider/guide-scaleway/"}),"Scaleway"))))}p.isMDXComponent=!0},422:function(e,r,t){"use strict";t.d(r,"a",(function(){return s})),t.d(r,"b",(function(){return f}));var o=t(0),n=t.n(o);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function u(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);r&&(o=o.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,o)}return t}function i(e){for(var r=1;r=0||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(n[t]=e[t])}return n}var l=n.a.createContext({}),p=function(e){var r=n.a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):i({},r,{},e)),t},s=function(e){var r=p(e.components);return n.a.createElement(l.Provider,{value:r},e.children)},d={inlineCode:"code",wrapper:function(e){var r=e.children;return n.a.createElement(n.a.Fragment,{},r)}},b=Object(o.forwardRef)((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,u=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),s=p(t),b=o,f=s["".concat(u,".").concat(b)]||s[b]||d[b]||a;return t?n.a.createElement(f,i({ref:r},l,{components:t})):n.a.createElement(f,i({ref:r},l))}));function f(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,u=new Array(a);u[0]=b;var i={};for(var c in r)hasOwnProperty.call(r,c)&&(i[c]=r[c]);i.originalType=e,i.mdxType="string"==typeof e?e:o,u[1]=i;for(var l=2;l=0||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(n[t]=e[t])}return n}var l=n.a.createContext({}),p=function(e){var r=n.a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):i({},r,{},e)),t},s=function(e){var r=p(e.components);return n.a.createElement(l.Provider,{value:r},e.children)},d={inlineCode:"code",wrapper:function(e){var r=e.children;return n.a.createElement(n.a.Fragment,{},r)}},b=Object(o.forwardRef)((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,u=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),s=p(t),b=o,f=s["".concat(u,".").concat(b)]||s[b]||d[b]||a;return t?n.a.createElement(f,i({ref:r},l,{components:t})):n.a.createElement(f,i({ref:r},l))}));function f(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,u=new Array(a);u[0]=b;var i={};for(var c in r)hasOwnProperty.call(r,c)&&(i[c]=r[c]);i.originalType=e,i.mdxType="string"==typeof e?e:o,u[1]=i;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),u=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),d=o,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return n?r.a.createElement(m,c({ref:t},l,{components:n})):r.a.createElement(m,c({ref:t},l))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),u=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(n),d=o,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return n?r.a.createElement(m,c({ref:t},l,{components:n})):r.a.createElement(m,c({ref:t},l))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var l=2;l)\n Jul 15 08:46:13.019724 at Timeout._onTimeout (/usr/src/app/autoFunctions/levels.js:15:14)\n Jul 15 08:46:13.019728 at listOnTimeout (internal/timers.js:557:17)\n # ... the rest of logs\n")),Object(l.b)("p",null,"By default, the last 1000 logs is displayed."),Object(l.b)("h3",{id:"follow-logs"},"Follow Logs"),Object(l.b)("p",null,"To make the CLI follow your logs, use ",Object(l.b)("inlineCode",{parentName:"p"},"-f")," flag:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery log -f\n TIME MESSAGE\n Jul 15 08:46:13.019717 at /usr/src/app/autoFunctions/levels.js:17:16\n Jul 15 08:46:13.019721 at Array.forEach ()\n Jul 15 08:46:13.019724 at Timeout._onTimeout (/usr/src/app/autoFunctions/levels.js:15:14)\n Jul 15 08:46:13.019728 at listOnTimeout (internal/timers.js:557:17)\n # ... the rest of logs\n")),Object(l.b)("p",null,"This will make the CLI follow your application logs and append any new logs till you use ",Object(l.b)("inlineCode",{parentName:"p"},"CTRL+C"),"."),Object(l.b)("h2",{id:"status"},"Status"),Object(l.b)("p",null,"Status command lets you print the basic status of your application."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery status\n15 Jul 21 10:55 CEST\nApplication | Backend\nStatus | RUNNING\n")),Object(l.b)("h2",{id:"console"},"Console"),Object(l.b)("p",null,"Console command quickly opens the Qovery Console in your browser to let you display more information about your application."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery console\nQovery: Opening https://console.qovery.com/platform/organization/your-org/projects/your-proj/environments/your-env/applications/your-app/summary\n")),Object(l.b)("h2",{id:"shell"},"Shell"),Object(l.b)("p",null,"Shell command allows you to open a connection and execute commands directly on the container running application."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell\n/ # ls\nbin media srv\ndev mnt sys\ndocker-entrypoint.d opt tmp\ndocker-entrypoint.sh proc usr\netc root var\nhome run www\nlib sbin\n")),Object(l.b)(i.a,{type:"info",mdxType:"Alert"},"Keep in mind these limitations when using this feature:",Object(l.b)("ul",null,Object(l.b)("li",null,"Install a process reaper as pid one in your container (i.e: dumb-init), as you may leave zoombie process in your container if your shell terminate unproperly (i.e: ctrl+c, cnx restart). This is a known issue with kubernetes exec to leave process alive after attach is closed;"),Object(l.b)("li",null,"if your application is configured to run with more than one instance, you will be able to connect only to the oldest POD running one of your instances;"),Object(l.b)("li",null,"shell is force closed after [1 hour, 10Mb transmitted];"),Object(l.b)("li",null,"we use SH by default. To have auto-completion, start bash."))),Object(l.b)("h2",{id:"generate-api-token"},"Generate API token"),Object(l.b)("p",null,"To use the Qovery API you will need to generate an authentication token. To generate an API token you can install the CLI and type"),Object(l.b)(i.a,{type:"warning",mdxType:"Alert"},Object(l.b)("p",null,"Never share your API token with anyone.")),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery token\n\nQovery: Select organization\nOrganization:\n\u2714 My Organization\nChoose a token name\nToken name: Romaric\nChoose a token description\nToken description: used for Github Actions\nQovery: ---- Never share this authentication token and keep it secure ----\nQovery: qov_4LnEg2wFxxxxxHObGSQ22rjBZZyyyySgyR6Y_2500882691\nQovery: ---- Never share this authentication token and keep it secure ----\n")),Object(l.b)("p",null,"To use your token and list your organizations."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-shell"}),"curl -X GET -H 'Authorization: Token qov_4LnEg2wFxxxxxHObGSQ22rjBZZyyyySgyR6Y_2500882691' https://api.qovery.com/organization\n")),Object(l.b)(i.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,"The token can be used to interact programmatically with our API (directly, via our Terraform Provider etc..).\nIf you get a 424 error while trying to create new applications from one of your git repository, please make sure that the Organization Owner has access to the repository you are configuring for your app.")),Object(l.b)("p",null,"Check out our ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://api-doc.qovery.com"}),"API documentation")),Object(l.b)("h2",{id:"managing-services-and-environments"},"Managing services and environments"),Object(l.b)("p",null,"The CLI allows you to manage and deploy the environment and services within your organization"),Object(l.b)("p",null,"###\xa0application, container, lifecycle, cronjob\nThese commands allow you to manage all these services via the CLI. You can run the following actions on these services:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"cancel: Cancel the service deployment"),Object(l.b)("li",{parentName:"ul"},"delete: Delete a service"),Object(l.b)("li",{parentName:"ul"},"deploy: Deploy a service"),Object(l.b)("li",{parentName:"ul"},"list: List the service of the specified type"),Object(l.b)("li",{parentName:"ul"},"redeploy: Redeploy a service (already deployed before)"),Object(l.b)("li",{parentName:"ul"},"stop: Stop a service")),Object(l.b)("p",null,"Each action allows you to specify additional parameters to define the service you want to modify (you can find them via the --help command) "),Object(l.b)("p",null,"Example: Listing applications and triggering a deployment"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'$ qovery application list\nName | Type | Status | Last Update \nbackend | Application | STOPPED | 2023-02-02 14:48:05.339652 +0000 UTC\nfront-end | Application | STOPPED | 2023-02-09 14:04:38.079792 +0000 UTC\n\n$ qovery application deploy -n "backend"\nDeploying application backend in progress..\n\n$ qovery application list\nName | Type | Status | Last Update \nbackend | Application | RUNNING | 2023-02-13 12:59:23.228231 +0000 UTC\nfront-end | Application | STOPPED | 2023-02-09 14:04:38.079792 +0000 UTC\n')),Object(l.b)("h3",{id:"environment"},"Environment"),Object(l.b)("p",null,"The command ",Object(l.b)("inlineCode",{parentName:"p"},"environment")," allow you to manage a specific environment via the CLI. You can run the following actions on environments:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"cancel: Cancel an environment deployment"),Object(l.b)("li",{parentName:"ul"},"clone: Clone an environment"),Object(l.b)("li",{parentName:"ul"},"delete: Delete an environment"),Object(l.b)("li",{parentName:"ul"},"deploy: Deploy an environment"),Object(l.b)("li",{parentName:"ul"},"list: List environments"),Object(l.b)("li",{parentName:"ul"},"redeploy: Redeploy an environment"),Object(l.b)("li",{parentName:"ul"},"stage: Manage deployment stages"),Object(l.b)("li",{parentName:"ul"},"stop: Stop an environment")),Object(l.b)("p",null,"Each action allows you to specify additional parameters to define the service you want to modify (you can find them via the --help command)"),Object(l.b)("p",null,"Example: Manage deployment stages and triggering deployment"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'~ $ qovery environment stage list\n\n# deployment stage 1: "DATABASE DEFAULT"\nRename me to avoid default/legacy ordering\n\nType | Name\nDATABASE | Redis\nDATABASE | DB\n\n\n# deployment stage 2: "JOB DEFAULT"\nRename me to avoid default/legacy ordering\n\n\n\n\n# deployment stage 3: "CONTAINER DEFAULT"\nRename me to avoid default/legacy ordering\n\nType | Name\nCONTAINER | Rabbitmq\n\n\n# deployment stage 4: "APPLICATION DEFAULT"\nRename me to avoid default/legacy ordering\n\nType | Name\nAPPLICATION | Backend\nAPPLICATION | Frontend\nAPPLICATION | Pablo Backend App\nAPPLICATION | API gateway\n\n~ $ qovery environment deploy\nEnvironment is deploying!\n')),Object(l.b)("h2",{id:"managing-the-deployment-pipeline"},"Managing the Deployment Pipeline"),Object(l.b)("p",null,"In the following sections we will describe how to modify the Deployment Pipeline. "),Object(l.b)("h3",{id:"list-stages"},"List stages"),Object(l.b)("p",null,"You can list all the stages of your environment by using the following command:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage list\n")),Object(l.b)("h3",{id:"add-a-stage"},"Add a stage"),Object(l.b)("p",null,"You can add a new stage by using the following command:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage create -n -d \n")),Object(l.b)("p",null,"Note that the stage will be added at the end of the pipeline (the highest number)"),Object(l.b)("h3",{id:"modify-a-stage"},"Modify a stage"),Object(l.b)("p",null,"You can modify a stage by using the following command:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage edit -n --new-name --new-description \n")),Object(l.b)("h3",{id:"delete-a-stage"},"Delete a stage"),Object(l.b)("p",null,"You can modify a stage by using the following command:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage delete -n \n")),Object(l.b)("h3",{id:"change-stage-for-a-service"},"Change stage for a service"),Object(l.b)("p",null,"You can modify the stage associated to a service by using the following command:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage move -n --stage \n")),Object(l.b)("h2",{id:"support"},"Support"),Object(l.b)("p",null,"Do you have any issues with Qovery CLI? ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/issues"}),"Open an issue"),"."))}d.isMDXComponent=!0},421:function(e,n,t){"use strict";t(423);var a=t(0),o=t.n(a),l=t(420),r=t.n(l);t(132);n.a=function(e){var n=e.children,t=e.classNames,a=e.fill,l=e.icon,c=e.type,i=null;switch(c){case"danger":i="alert-triangle";break;case"success":i="check-circle";break;case"warning":i="alert-triangle";break;default:i="info"}return o.a.createElement("div",{className:r()(t,"alert","alert--"+c,{"alert--fill":a,"alert--icon":!1!==l}),role:"alert"},!1!==l&&o.a.createElement("i",{className:r()("feather","icon-"+(l||i))}),n)}},434:function(e,n,t){"use strict";var a=t(1),o=(t(439),t(436),t(52),t(29),t(22),t(21),t(0)),l=t.n(o),r=t(446),c=t(420),i=t.n(c),s=t(428),b=t.n(s),u=t(445),p=37,d=39;function m(e){var n=e.block,t=e.centered,a=e.changeSelectedValue,o=e.className,r=e.handleKeydown,c=e.style,s=e.values,b=e.selectedValue,u=e.tabRefs;return l.a.createElement("div",{className:t?"tabs--centered":null},l.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:i()("tabs",o,{"tabs--block":n}),style:c},s.map((function(e){var n=e.value,t=e.label;return l.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===n,className:i()("tab-item",{"tab-item--active":b===n}),key:n,ref:function(e){return u.push(e)},onKeyDown:function(e){return r(u,e.target,e)},onFocus:function(){return a(n)},onClick:function(){return a(n)}},t)}))))}function y(e){var n=e.placeholder,t=e.selectedValue,a=e.changeSelectedValue,o=e.size,c=e.values,i=c;if(i[0].group){var s=_.groupBy(i,"group");i=Object.keys(s).map((function(e){return{label:e,options:s[e]}}))}return l.a.createElement(r.a,{className:"react-select-container react-select--"+o,classNamePrefix:"react-select",options:i,isClearable:t,placeholder:n,value:c.find((function(e){return e.value==t})),onChange:function(e){return a(e?e.value:null)}})}n.a=function(e){e.block,e.centered;var n=e.children,t=e.defaultValue,r=e.groupId,c=e.label,i=e.placeholder,s=e.select,h=e.size,g=(e.style,e.values),v=e.urlKey,O=Object(u.a)(),j=O.tabGroupChoices,f=O.setTabGroupChoices,N=Object(o.useState)(t),w=N[0],T=N[1];if(null!=r){var C=j[r];null!=C&&C!==w&&T(C)}var I=function(e){T(e),null!=r&&f(r,e)},x=[],k=function(e,n,t){switch(t.keyCode){case d:!function(e,n){var t=e.indexOf(n)+1;e[t]?e[t].focus():e[0].focus()}(e,n);break;case p:!function(e,n){var t=e.indexOf(n)-1;e[t]?e[t].focus():e[e.length-1].focus()}(e,n)}};return Object(o.useEffect)((function(){if("undefined"!=typeof window&&window.location&&v){var e=b.a.parse(window.location.search);e[v]&&T(e[v])}}),[]),l.a.createElement(l.a.Fragment,null,l.a.createElement("div",{className:"margin-bottom--"+(h||"md")},c&&l.a.createElement("div",{className:"margin-vert--sm"},c),g.length>1&&(s?l.a.createElement(y,Object(a.a)({changeSelectedValue:I,handleKeydown:k,placeholder:i,selectedValue:w,size:h,tabRefs:x},e)):l.a.createElement(m,Object(a.a)({changeSelectedValue:I,handleKeydown:k,selectedValue:w,tabRefs:x},e)))),o.Children.toArray(n).filter((function(e){return e.props.value===w}))[0])}},441:function(e,n,t){"use strict";var a=t(0),o=t.n(a);n.a=function(e){return o.a.createElement(o.a.Fragment,null,e.children)}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[227],{379:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return s})),t.d(n,"metadata",(function(){return b})),t.d(n,"rightToc",(function(){return u})),t.d(n,"default",(function(){return d}));var a=t(1),o=t(9),l=(t(0),t(425)),r=t(437),c=t(444),i=t(424),s={last_modified_on:"2023-08-04",title:"CLI",description:"How to use the Qovery CLI (Command Line Interface)"},b={id:"using-qovery/interface/cli",title:"CLI",description:"How to use the Qovery CLI (Command Line Interface)",source:"@site/docs/using-qovery/interface/cli.md",permalink:"/docs/using-qovery/interface/cli",sidebar:"docs",previous:{title:"Web interface",permalink:"/docs/using-qovery/interface/web-interface"},next:{title:"REST API",permalink:"/docs/using-qovery/interface/rest-api"}},u=[{value:"First usage",id:"first-usage",children:[{value:"Install",id:"install",children:[]},{value:"Sign up",id:"sign-up",children:[]},{value:"Help",id:"help",children:[]}]},{value:"Context",id:"context",children:[{value:"Set New Context",id:"set-new-context",children:[]},{value:"Print Current Context",id:"print-current-context",children:[]}]},{value:"Log",id:"log",children:[{value:"Follow Logs",id:"follow-logs",children:[]}]},{value:"Status",id:"status",children:[]},{value:"Console",id:"console",children:[]},{value:"Shell",id:"shell",children:[]},{value:"Generate API token",id:"generate-api-token",children:[]},{value:"Managing services and environments",id:"managing-services-and-environments",children:[{value:"Environment",id:"environment",children:[]}]},{value:"Managing the Deployment Pipeline",id:"managing-the-deployment-pipeline",children:[{value:"List stages",id:"list-stages",children:[]},{value:"Add a stage",id:"add-a-stage",children:[]},{value:"Modify a stage",id:"modify-a-stage",children:[]},{value:"Delete a stage",id:"delete-a-stage",children:[]},{value:"Change stage for a service",id:"change-stage-for-a-service",children:[]}]},{value:"Support",id:"support",children:[]}],p={rightToc:u};function d(e){var n=e.components,t=Object(o.a)(e,["components"]);return Object(l.b)("wrapper",Object(a.a)({},p,t,{components:n,mdxType:"MDXLayout"}),Object(l.b)(i.a,{type:"success",mdxType:"Alert"},Object(l.b)("p",null,"Use Infrastructure as Code (IaC) with ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"Terraform")," and our ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/interface/rest-api/"}),"REST API")," to manage Qovery and deploy your apps.")),Object(l.b)("p",null,"Qovery provides a very easy to use CLI (Command Line Interface) designed to fit the developer workflow perfectly."),Object(l.b)("hr",null),Object(l.b)("p",null,"The purpose of the CLI is to integrate seamlessly with your development workflow:"),Object(l.b)("ol",null,Object(l.b)("li",{parentName:"ol"},"Write code"),Object(l.b)("li",{parentName:"ol"},"Commit"),Object(l.b)("li",{parentName:"ol"},Object(l.b)("strong",{parentName:"li"},"Qovery")," - deploy a new version of your application"),Object(l.b)("li",{parentName:"ol"},Object(l.b)("strong",{parentName:"li"},"Qovery CLI")," - check the status of your application"),Object(l.b)("li",{parentName:"ol"},Object(l.b)("strong",{parentName:"li"},"Qovery CLI")," - debug your application"),Object(l.b)("li",{parentName:"ol"},"Repeat")),Object(l.b)("h2",{id:"first-usage"},"First usage"),Object(l.b)("h3",{id:"install"},"Install"),Object(l.b)(r.a,{centered:!0,className:"rounded",defaultValue:"linux",placeholder:"Select your OS",select:!1,size:null,values:[{group:"Platforms",label:"Linux",value:"linux"},{group:"Platforms",label:"MacOS",value:"macos"},{group:"Platforms",label:"Windows",value:"windows"},{group:"Platforms",label:"Docker",value:"docker"}],mdxType:"Tabs"},Object(l.b)(c.a,{value:"linux",mdxType:"TabItem"},Object(l.b)(r.a,{centered:!0,className:"rounded",defaultValue:"universal",values:[{label:"*nix",value:"universal"},{label:"Arch Linux",value:"arch"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(l.b)(c.a,{value:"universal",mdxType:"TabItem"},Object(l.b)("p",null,"To download and install Qovery CLI on any Linux distribution:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(l.b)(c.a,{value:"arch",mdxType:"TabItem"},Object(l.b)("p",null,"Qovery is part of ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(l.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(l.b)("p",null,"Install the Qovery CLI on Linux manually by downloading the ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(l.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(l.b)(c.a,{value:"macos",mdxType:"TabItem"},Object(l.b)(r.a,{centered:!0,className:"rounded",defaultValue:"homebrew",values:[{label:"Homebrew",value:"homebrew"},{label:"Script",value:"script"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(l.b)(c.a,{value:"homebrew",mdxType:"TabItem"},Object(l.b)("p",null,"The common solution to install a command line binary on the MacOS is to use ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery brew repository\n$ brew tap Qovery/qovery-cli\n\n# Install the CLI\n$ brew install qovery-cli\n"))),Object(l.b)(c.a,{value:"script",mdxType:"TabItem"},Object(l.b)("p",null,"To download and install Qovery CLI from the command line:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(l.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(l.b)("p",null,"Install the Qovery CLI on Mac OS manually by downloading the ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(l.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(l.b)(c.a,{value:"windows",mdxType:"TabItem"},Object(l.b)(r.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(l.b)(c.a,{value:"scoop",mdxType:"TabItem"},Object(l.b)("p",null,"The classic way to install binaries on Windows is to use ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery bucket\n$ scoop bucket add qovery https://github.com/Qovery/scoop-qovery-cli\n\n# Install the CLI\n$ scoop install qovery-cli\n"))),Object(l.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(l.b)("p",null,"Install the Qovery CLI on Windows manually by downloading the ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to\n",Object(l.b)("inlineCode",{parentName:"p"},"C:\\Windows"),".")))),Object(l.b)(c.a,{value:"docker",mdxType:"TabItem"},Object(l.b)("p",null,"Install Docker on your local machine and run the following command:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Pull and Run the latest Qovery CLI\n$ docker run ghcr.io/qovery/qovery-cli:latest help\n")),Object(l.b)("p",null,"Change ",Object(l.b)("inlineCode",{parentName:"p"},"latest")," by the version you want to use. For example, to use the version 0.58.4, run:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ docker run ghcr.io/qovery/qovery-cli:0.58.4 help\n")),Object(l.b)("p",null,"Note: ",Object(l.b)("inlineCode",{parentName:"p"},"ghcr.io")," is the ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/pkgs/container/qovery-cli"}),"GitHub Container Registry"),"."))),Object(l.b)("h3",{id:"sign-up"},"Sign up"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(l.b)(i.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,"If you are using an environment without access to GUI or a browser, you can use headless authentication instead:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth --headless\n"))),Object(l.b)("p",null,"Your browser window with sign-in options will open."),Object(l.b)("p",{align:"center"},Object(l.b)("img",{src:"/img/qovery_signup.svg",alt:"Qovery Sign-up page"})),Object(l.b)("p",null,Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/apps/qovery/installations/new"}),"Click here")," to authorize Qovery to clone and build your applications."),Object(l.b)("p",{align:"center"},Object(l.b)("img",{src:"/img/github_signup.svg",alt:"Connect Github"})),Object(l.b)("p",null,"Congratulations, you are logged-in."),Object(l.b)("h3",{id:"help"},"Help"),Object(l.b)("p",null,"You can see all the commands available by executing:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery help\n")),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash",metastring:'title="Help output"',title:'"Help','output"':!0}),'$ qovery help\nA Command-line Interface of the Qovery platform\n\nUsage:\n qovery [command]\n\nAvailable Commands:\n application Manage applications\n auth Log in to Qovery\n completion Generate the autocompletion script for the specified shell\n console Opens the application in Qovery Console in your browser\n container Manage containers\n context Manage CLI context\n cronjob Manage cronjobs\n database Manage databases\n env Manage Environment Variables and Secrets\n environment Manage environments\n help Help about any command\n lifecycle Manage lifecycle jobs\n log Print your application logs\n service Manage services\n shell Connect to an application container\n status Print the status of your application\n token Generate an API token\n upgrade Upgrade Qovery CLI to latest version\n version Print installed version of the Qovery CLI\n\nFlags:\n -h, --help help for qovery\n\nUse "qovery [command] --help" for more information about a command.\n')),Object(l.b)("h2",{id:"context"},"Context"),Object(l.b)("p",null,"Context command lets you configure the CLI to work with your chosen application. Before executing other commands, you need first to set up the context.\nThe context is then remembered and used by the CLI. You can configure a new context anytime by running the ",Object(l.b)("inlineCode",{parentName:"p"},"qovery context set")," command."),Object(l.b)("h3",{id:"set-new-context"},"Set New Context"),Object(l.b)("p",null,"To set a new context, type ",Object(l.b)("inlineCode",{parentName:"p"},"qovery context set"),":"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery context set\nQovery: Current context:\nOrganization | Qovery\nProject | test\nEnvironment | development\nApplication | website\n\nQovery: Select new context\nOrganization:\n\u2714 Qovery\nProject:\n\u2714 admin\nEnvironment:\n\u2714 main\nApplication:\n\u2714 app\n\nQovery: New context:\nOrganization | Qovery\nProject | admin\nEnvironment | main\nApplication | app\n")),Object(l.b)("h3",{id:"print-current-context"},"Print Current Context"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery context\nQovery: Current context:\nOrganization | Qovery\nProject | admin\nEnvironment | main\nApplication | app\n\nQovery: You can set a new context using 'qovery context set'.\n")),Object(l.b)("h2",{id:"log"},"Log"),Object(l.b)("p",null,"Log command allows you to display the application logs."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery log\n TIME MESSAGE\n Jul 15 08:46:13.019717 at /usr/src/app/autoFunctions/levels.js:17:16\n Jul 15 08:46:13.019721 at Array.forEach ()\n Jul 15 08:46:13.019724 at Timeout._onTimeout (/usr/src/app/autoFunctions/levels.js:15:14)\n Jul 15 08:46:13.019728 at listOnTimeout (internal/timers.js:557:17)\n # ... the rest of logs\n")),Object(l.b)("p",null,"By default, the last 1000 logs is displayed."),Object(l.b)("h3",{id:"follow-logs"},"Follow Logs"),Object(l.b)("p",null,"To make the CLI follow your logs, use ",Object(l.b)("inlineCode",{parentName:"p"},"-f")," flag:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery log -f\n TIME MESSAGE\n Jul 15 08:46:13.019717 at /usr/src/app/autoFunctions/levels.js:17:16\n Jul 15 08:46:13.019721 at Array.forEach ()\n Jul 15 08:46:13.019724 at Timeout._onTimeout (/usr/src/app/autoFunctions/levels.js:15:14)\n Jul 15 08:46:13.019728 at listOnTimeout (internal/timers.js:557:17)\n # ... the rest of logs\n")),Object(l.b)("p",null,"This will make the CLI follow your application logs and append any new logs till you use ",Object(l.b)("inlineCode",{parentName:"p"},"CTRL+C"),"."),Object(l.b)("h2",{id:"status"},"Status"),Object(l.b)("p",null,"Status command lets you print the basic status of your application."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery status\n15 Jul 21 10:55 CEST\nApplication | Backend\nStatus | RUNNING\n")),Object(l.b)("h2",{id:"console"},"Console"),Object(l.b)("p",null,"Console command quickly opens the Qovery Console in your browser to let you display more information about your application."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery console\nQovery: Opening https://console.qovery.com/platform/organization/your-org/projects/your-proj/environments/your-env/applications/your-app/summary\n")),Object(l.b)("h2",{id:"shell"},"Shell"),Object(l.b)("p",null,"Shell command allows you to open a connection and execute commands directly on the container running application."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell\n/ # ls\nbin media srv\ndev mnt sys\ndocker-entrypoint.d opt tmp\ndocker-entrypoint.sh proc usr\netc root var\nhome run www\nlib sbin\n")),Object(l.b)(i.a,{type:"info",mdxType:"Alert"},"Keep in mind these limitations when using this feature:",Object(l.b)("ul",null,Object(l.b)("li",null,"Install a process reaper as pid one in your container (i.e: dumb-init), as you may leave zoombie process in your container if your shell terminate unproperly (i.e: ctrl+c, cnx restart). This is a known issue with kubernetes exec to leave process alive after attach is closed;"),Object(l.b)("li",null,"if your application is configured to run with more than one instance, you will be able to connect only to the oldest POD running one of your instances;"),Object(l.b)("li",null,"shell is force closed after [1 hour, 10Mb transmitted];"),Object(l.b)("li",null,"we use SH by default. To have auto-completion, start bash."))),Object(l.b)("h2",{id:"generate-api-token"},"Generate API token"),Object(l.b)("p",null,"To use the Qovery API you will need to generate an authentication token. To generate an API token you can install the CLI and type"),Object(l.b)(i.a,{type:"warning",mdxType:"Alert"},Object(l.b)("p",null,"Never share your API token with anyone.")),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery token\n\nQovery: Select organization\nOrganization:\n\u2714 My Organization\nChoose a token name\nToken name: Romaric\nChoose a token description\nToken description: used for Github Actions\nQovery: ---- Never share this authentication token and keep it secure ----\nQovery: qov_4LnEg2wFxxxxxHObGSQ22rjBZZyyyySgyR6Y_2500882691\nQovery: ---- Never share this authentication token and keep it secure ----\n")),Object(l.b)("p",null,"To use your token and list your organizations."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-shell"}),"curl -X GET -H 'Authorization: Token qov_4LnEg2wFxxxxxHObGSQ22rjBZZyyyySgyR6Y_2500882691' https://api.qovery.com/organization\n")),Object(l.b)(i.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,"The token can be used to interact programmatically with our API (directly, via our Terraform Provider etc..).\nIf you get a 424 error while trying to create new applications from one of your git repository, please make sure that the Organization Owner has access to the repository you are configuring for your app.")),Object(l.b)("p",null,"Check out our ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://api-doc.qovery.com"}),"API documentation")),Object(l.b)("h2",{id:"managing-services-and-environments"},"Managing services and environments"),Object(l.b)("p",null,"The CLI allows you to manage and deploy the environment and services within your organization"),Object(l.b)("p",null,"###\xa0application, container, lifecycle, cronjob\nThese commands allow you to manage all these services via the CLI. You can run the following actions on these services:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"cancel: Cancel the service deployment"),Object(l.b)("li",{parentName:"ul"},"delete: Delete a service"),Object(l.b)("li",{parentName:"ul"},"deploy: Deploy a service"),Object(l.b)("li",{parentName:"ul"},"list: List the service of the specified type"),Object(l.b)("li",{parentName:"ul"},"redeploy: Redeploy a service (already deployed before)"),Object(l.b)("li",{parentName:"ul"},"stop: Stop a service")),Object(l.b)("p",null,"Each action allows you to specify additional parameters to define the service you want to modify (you can find them via the --help command) "),Object(l.b)("p",null,"Example: Listing applications and triggering a deployment"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'$ qovery application list\nName | Type | Status | Last Update \nbackend | Application | STOPPED | 2023-02-02 14:48:05.339652 +0000 UTC\nfront-end | Application | STOPPED | 2023-02-09 14:04:38.079792 +0000 UTC\n\n$ qovery application deploy -n "backend"\nDeploying application backend in progress..\n\n$ qovery application list\nName | Type | Status | Last Update \nbackend | Application | RUNNING | 2023-02-13 12:59:23.228231 +0000 UTC\nfront-end | Application | STOPPED | 2023-02-09 14:04:38.079792 +0000 UTC\n')),Object(l.b)("h3",{id:"environment"},"Environment"),Object(l.b)("p",null,"The command ",Object(l.b)("inlineCode",{parentName:"p"},"environment")," allow you to manage a specific environment via the CLI. You can run the following actions on environments:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"cancel: Cancel an environment deployment"),Object(l.b)("li",{parentName:"ul"},"clone: Clone an environment"),Object(l.b)("li",{parentName:"ul"},"delete: Delete an environment"),Object(l.b)("li",{parentName:"ul"},"deploy: Deploy an environment"),Object(l.b)("li",{parentName:"ul"},"list: List environments"),Object(l.b)("li",{parentName:"ul"},"redeploy: Redeploy an environment"),Object(l.b)("li",{parentName:"ul"},"stage: Manage deployment stages"),Object(l.b)("li",{parentName:"ul"},"stop: Stop an environment")),Object(l.b)("p",null,"Each action allows you to specify additional parameters to define the service you want to modify (you can find them via the --help command)"),Object(l.b)("p",null,"Example: Manage deployment stages and triggering deployment"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'~ $ qovery environment stage list\n\n# deployment stage 1: "DATABASE DEFAULT"\nRename me to avoid default/legacy ordering\n\nType | Name\nDATABASE | Redis\nDATABASE | DB\n\n\n# deployment stage 2: "JOB DEFAULT"\nRename me to avoid default/legacy ordering\n\n\n\n\n# deployment stage 3: "CONTAINER DEFAULT"\nRename me to avoid default/legacy ordering\n\nType | Name\nCONTAINER | Rabbitmq\n\n\n# deployment stage 4: "APPLICATION DEFAULT"\nRename me to avoid default/legacy ordering\n\nType | Name\nAPPLICATION | Backend\nAPPLICATION | Frontend\nAPPLICATION | Pablo Backend App\nAPPLICATION | API gateway\n\n~ $ qovery environment deploy\nEnvironment is deploying!\n')),Object(l.b)("h2",{id:"managing-the-deployment-pipeline"},"Managing the Deployment Pipeline"),Object(l.b)("p",null,"In the following sections we will describe how to modify the Deployment Pipeline. "),Object(l.b)("h3",{id:"list-stages"},"List stages"),Object(l.b)("p",null,"You can list all the stages of your environment by using the following command:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage list\n")),Object(l.b)("h3",{id:"add-a-stage"},"Add a stage"),Object(l.b)("p",null,"You can add a new stage by using the following command:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage create -n -d \n")),Object(l.b)("p",null,"Note that the stage will be added at the end of the pipeline (the highest number)"),Object(l.b)("h3",{id:"modify-a-stage"},"Modify a stage"),Object(l.b)("p",null,"You can modify a stage by using the following command:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage edit -n --new-name --new-description \n")),Object(l.b)("h3",{id:"delete-a-stage"},"Delete a stage"),Object(l.b)("p",null,"You can modify a stage by using the following command:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage delete -n \n")),Object(l.b)("h3",{id:"change-stage-for-a-service"},"Change stage for a service"),Object(l.b)("p",null,"You can modify the stage associated to a service by using the following command:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage move -n --stage \n")),Object(l.b)("h2",{id:"support"},"Support"),Object(l.b)("p",null,"Do you have any issues with Qovery CLI? ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/issues"}),"Open an issue"),"."))}d.isMDXComponent=!0},424:function(e,n,t){"use strict";t(426);var a=t(0),o=t.n(a),l=t(423),r=t.n(l);t(132);n.a=function(e){var n=e.children,t=e.classNames,a=e.fill,l=e.icon,c=e.type,i=null;switch(c){case"danger":i="alert-triangle";break;case"success":i="check-circle";break;case"warning":i="alert-triangle";break;default:i="info"}return o.a.createElement("div",{className:r()(t,"alert","alert--"+c,{"alert--fill":a,"alert--icon":!1!==l}),role:"alert"},!1!==l&&o.a.createElement("i",{className:r()("feather","icon-"+(l||i))}),n)}},437:function(e,n,t){"use strict";var a=t(1),o=(t(442),t(439),t(52),t(29),t(22),t(21),t(0)),l=t.n(o),r=t(449),c=t(423),i=t.n(c),s=t(433),b=t.n(s),u=t(448),p=37,d=39;function m(e){var n=e.block,t=e.centered,a=e.changeSelectedValue,o=e.className,r=e.handleKeydown,c=e.style,s=e.values,b=e.selectedValue,u=e.tabRefs;return l.a.createElement("div",{className:t?"tabs--centered":null},l.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:i()("tabs",o,{"tabs--block":n}),style:c},s.map((function(e){var n=e.value,t=e.label;return l.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===n,className:i()("tab-item",{"tab-item--active":b===n}),key:n,ref:function(e){return u.push(e)},onKeyDown:function(e){return r(u,e.target,e)},onFocus:function(){return a(n)},onClick:function(){return a(n)}},t)}))))}function y(e){var n=e.placeholder,t=e.selectedValue,a=e.changeSelectedValue,o=e.size,c=e.values,i=c;if(i[0].group){var s=_.groupBy(i,"group");i=Object.keys(s).map((function(e){return{label:e,options:s[e]}}))}return l.a.createElement(r.a,{className:"react-select-container react-select--"+o,classNamePrefix:"react-select",options:i,isClearable:t,placeholder:n,value:c.find((function(e){return e.value==t})),onChange:function(e){return a(e?e.value:null)}})}n.a=function(e){e.block,e.centered;var n=e.children,t=e.defaultValue,r=e.groupId,c=e.label,i=e.placeholder,s=e.select,h=e.size,g=(e.style,e.values),v=e.urlKey,O=Object(u.a)(),j=O.tabGroupChoices,f=O.setTabGroupChoices,N=Object(o.useState)(t),w=N[0],T=N[1];if(null!=r){var C=j[r];null!=C&&C!==w&&T(C)}var I=function(e){T(e),null!=r&&f(r,e)},x=[],k=function(e,n,t){switch(t.keyCode){case d:!function(e,n){var t=e.indexOf(n)+1;e[t]?e[t].focus():e[0].focus()}(e,n);break;case p:!function(e,n){var t=e.indexOf(n)-1;e[t]?e[t].focus():e[e.length-1].focus()}(e,n)}};return Object(o.useEffect)((function(){if("undefined"!=typeof window&&window.location&&v){var e=b.a.parse(window.location.search);e[v]&&T(e[v])}}),[]),l.a.createElement(l.a.Fragment,null,l.a.createElement("div",{className:"margin-bottom--"+(h||"md")},c&&l.a.createElement("div",{className:"margin-vert--sm"},c),g.length>1&&(s?l.a.createElement(y,Object(a.a)({changeSelectedValue:I,handleKeydown:k,placeholder:i,selectedValue:w,size:h,tabRefs:x},e)):l.a.createElement(m,Object(a.a)({changeSelectedValue:I,handleKeydown:k,selectedValue:w,tabRefs:x},e)))),o.Children.toArray(n).filter((function(e){return e.props.value===w}))[0])}},444:function(e,n,t){"use strict";var a=t(0),o=t.n(a);n.a=function(e){return o.a.createElement(o.a.Fragment,null,e.children)}}}]); \ No newline at end of file diff --git a/d9deea5f.1e918522.js b/d9deea5f.4add985c.js similarity index 97% rename from d9deea5f.1e918522.js rename to d9deea5f.4add985c.js index f414f9cfbf..1817a08c89 100644 --- a/d9deea5f.1e918522.js +++ b/d9deea5f.4add985c.js @@ -1,2 +1,2 @@ -/*! For license information please see d9deea5f.1e918522.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[225],{377:function(n,t,e){"use strict";e.r(t);var r=e(0),u=e.n(r),i=e(442),o=e(513),a=e(427);t.default=function(n){var t=n.metadata.category,e=n.items;return u.a.createElement(i.a,{title:t.title+" Guides",description:"All "+t.title+" guides"},u.a.createElement("header",{className:"hero hero--clean"},u.a.createElement("div",{className:"container"},u.a.createElement("h1",null,t.title," Guides"),t.description&&u.a.createElement("div",{className:"hero--subtitle"},t.description),u.a.createElement("div",null,u.a.createElement(a.a,{to:"/guides"},"View All Guides")))),u.a.createElement("main",{className:"container container--s"},u.a.createElement(o.a,{items:e,staggered:null!=e[0].content.metadata.seriesPosition})))}},420:function(n,t,e){var r;!function(){"use strict";var e={}.hasOwnProperty;function u(){for(var n=[],t=0;t1?arguments[1]:void 0)}}),e(74)("find")},442:function(n,t,e){"use strict";e(454);var r=e(0),u=e.n(r),i=e(455),o=e(440),a=e(1),c=(e(443),e(444),e(456),e(427)),l=e(457),f=e(437),s=e.n(f),v=e(458),h=e.n(v),d=e(433),p=e(420),D=e.n(p),g=e(135),_=e.n(g),m=function(){return u.a.createElement("span",{className:D()(_.a.toggle,_.a.moon)})},y=function(){return u.a.createElement("span",{className:D()(_.a.toggle,_.a.sun)})},b=function(n){var t=Object(d.a)().isClient;return u.a.createElement(h.a,Object(a.a)({disabled:!t,icons:{checked:u.a.createElement(m,null),unchecked:u.a.createElement(y,null)}},n))};function E(){var n=Object(d.a)().siteConfig,t=(void 0===n?{}:n).customFields.metadata.latest_post,e=Date.parse(t.date),r=new Date,u=Math.abs(r-e),i=Math.ceil(u/864e5),o=null;return"undefined"!=typeof window&&(o=new Date(parseInt(window.localStorage.getItem("blogViewedAt")||"0"))),i<30&&(!o||o0&&u.a.createElement("div",{className:"row footer__links"},u.a.createElement("div",{className:"col col--5 footer__col"},u.a.createElement("div",{className:"margin-bottom--md"},u.a.createElement(s.a,{className:"navbar__logo",src:h,alt:"Qovery",width:"150",height:"auto"})),u.a.createElement("div",{className:"margin-bottom--md"},u.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),u.a.createElement("div",null,u.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},u.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",u.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},u.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",u.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},u.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",u.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},u.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),c.map((function(n,t){return u.a.createElement("div",{key:t,className:"col footer__col"},null!=n.title?u.a.createElement("h4",{className:"footer__title"},n.title):null,null!=n.items&&Array.isArray(n.items)&&n.items.length>0?u.a.createElement("ul",{className:"footer__items"},n.items.map((function(n,t){return n.html?u.a.createElement("li",{key:t,className:"footer__item",dangerouslySetInnerHTML:{__html:n.html}}):u.a.createElement("li",{key:n.href||n.to,className:"footer__item"},u.a.createElement(R,n))}))):null)}))),(f||o)&&u.a.createElement("div",{className:"text--center"},f&&f.src&&u.a.createElement("div",{className:"margin-bottom--sm"},f.href?u.a.createElement("a",{href:f.href,target:"_blank",rel:"noopener noreferrer",className:L.a.footerLogoLink},u.a.createElement(z,{alt:f.alt,url:v})):u.a.createElement(z,{alt:f.alt,url:v})),u.a.createElement("small",null,o),u.a.createElement("br",null))))},W=e(459),M=e(460),U=e(3);e(138);t.a=function(n){var t=Object(d.a)().siteConfig,e=void 0===t?{}:t,r=e.favicon,a=(e.tagline,e.title),c=e.themeConfig.image,l=e.url,f=n.children,s=n.title,v=n.noFooter,h=n.description,p=n.image,D=n.keywords,g=(n.permalink,n.version),_=s?s+" | "+a:a,m=p||c,y=l+Object(F.a)(m),b=Object(F.a)(r),E=Object(U.h)(),w=E?"https://docs.qovery.com"+(E.pathname.endsWith("/")?E.pathname:E.pathname+"/"):null;return u.a.createElement(M.a,null,u.a.createElement(W.a,null,u.a.createElement(o.a,null,u.a.createElement("html",{lang:"en"}),u.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),_&&u.a.createElement("title",null,_),_&&u.a.createElement("meta",{property:"og:title",content:_}),r&&u.a.createElement("link",{rel:"shortcut icon",href:b}),h&&u.a.createElement("meta",{name:"description",content:h}),h&&u.a.createElement("meta",{property:"og:description",content:h}),g&&u.a.createElement("meta",{name:"docsearch:version",content:g}),D&&D.length&&u.a.createElement("meta",{name:"keywords",content:D.join(",")}),m&&u.a.createElement("meta",{property:"og:image",content:y}),m&&u.a.createElement("meta",{property:"twitter:image",content:y}),m&&u.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+_}),w&&u.a.createElement("meta",{property:"og:url",content:w}),u.a.createElement("meta",{name:"twitter:card",content:"summary"}),w&&u.a.createElement("link",{rel:"canonical",href:w})),u.a.createElement(i.a,null),u.a.createElement(B,null),u.a.createElement("div",{className:"main-wrapper"},f),!v&&u.a.createElement(T,null)))}},447:function(n,t,e){"use strict";var r=e(9),u=e(0),i=e.n(u),o=e(420),a=e.n(o),c=e(433),l=(e(139),e(140)),f=e.n(l);t.a=function(n){return function(t){var e,u=t.id,o=Object(r.a)(t,["id"]),l=Object(c.a)().siteConfig,s=(l=void 0===l?{}:l).themeConfig,v=(s=void 0===s?{}:s).navbar,h=(v=void 0===v?{}:v).hideOnScroll,d=void 0!==h&&h;return u?i.a.createElement(n,o,i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:a()("anchor",(e={},e[f.a.enhancedAnchor]=!d,e)),id:u}),i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+u,title:"Direct link to heading"},"#"),o.children):i.a.createElement(n,o)}}},448:function(n,t,e){(function(n,r){var u;(function(){var i="Expected a function",o="__lodash_placeholder__",a=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],c="[object Arguments]",l="[object Array]",f="[object Boolean]",s="[object Date]",v="[object Error]",h="[object Function]",d="[object GeneratorFunction]",p="[object Map]",D="[object Number]",g="[object Object]",_="[object RegExp]",m="[object Set]",y="[object String]",b="[object Symbol]",E="[object WeakMap]",w="[object ArrayBuffer]",F="[object DataView]",C="[object Float32Array]",k="[object Float64Array]",A="[object Int8Array]",x="[object Int16Array]",j="[object Int32Array]",O="[object Uint8Array]",N="[object Uint16Array]",B="[object Uint32Array]",I=/\b__p \+= '';/g,S=/\b(__p \+=) '' \+/g,L=/(__e\(.*?\)|\b__t\)) \+\n'';/g,R=/&(?:amp|lt|gt|quot|#39);/g,z=/[&<>"']/g,T=RegExp(R.source),W=RegExp(z.source),M=/<%-([\s\S]+?)%>/g,U=/<%([\s\S]+?)%>/g,P=/<%=([\s\S]+?)%>/g,$=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,q=/^\w*$/,G=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,V=/[\\^$.*+?()[\]{}|]/g,Z=RegExp(V.source),K=/^\s+|\s+$/g,H=/^\s+/,Q=/\s+$/,J=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Y=/\{\n\/\* \[wrapped with (.+)\] \*/,X=/,? & /,nn=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,tn=/\\(\\)?/g,en=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,rn=/\w*$/,un=/^[-+]0x[0-9a-f]+$/i,on=/^0b[01]+$/i,an=/^\[object .+?Constructor\]$/,cn=/^0o[0-7]+$/i,ln=/^(?:0|[1-9]\d*)$/,fn=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,sn=/($^)/,vn=/['\n\r\u2028\u2029\\]/g,hn="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",dn="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",pn="[\\ud800-\\udfff]",Dn="["+dn+"]",gn="["+hn+"]",_n="\\d+",mn="[\\u2700-\\u27bf]",yn="[a-z\\xdf-\\xf6\\xf8-\\xff]",bn="[^\\ud800-\\udfff"+dn+_n+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",En="\\ud83c[\\udffb-\\udfff]",wn="[^\\ud800-\\udfff]",Fn="(?:\\ud83c[\\udde6-\\uddff]){2}",Cn="[\\ud800-\\udbff][\\udc00-\\udfff]",kn="[A-Z\\xc0-\\xd6\\xd8-\\xde]",An="(?:"+yn+"|"+bn+")",xn="(?:"+kn+"|"+bn+")",jn="(?:"+gn+"|"+En+")"+"?",On="[\\ufe0e\\ufe0f]?"+jn+("(?:\\u200d(?:"+[wn,Fn,Cn].join("|")+")[\\ufe0e\\ufe0f]?"+jn+")*"),Nn="(?:"+[mn,Fn,Cn].join("|")+")"+On,Bn="(?:"+[wn+gn+"?",gn,Fn,Cn,pn].join("|")+")",In=RegExp("['\u2019]","g"),Sn=RegExp(gn,"g"),Ln=RegExp(En+"(?="+En+")|"+Bn+On,"g"),Rn=RegExp([kn+"?"+yn+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?="+[Dn,kn,"$"].join("|")+")",xn+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?="+[Dn,kn+An,"$"].join("|")+")",kn+"?"+An+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?",kn+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",_n,Nn].join("|"),"g"),zn=RegExp("[\\u200d\\ud800-\\udfff"+hn+"\\ufe0e\\ufe0f]"),Tn=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Wn=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Mn=-1,Un={};Un[C]=Un[k]=Un[A]=Un[x]=Un[j]=Un[O]=Un["[object Uint8ClampedArray]"]=Un[N]=Un[B]=!0,Un[c]=Un[l]=Un[w]=Un[f]=Un[F]=Un[s]=Un[v]=Un[h]=Un[p]=Un[D]=Un[g]=Un[_]=Un[m]=Un[y]=Un[E]=!1;var Pn={};Pn[c]=Pn[l]=Pn[w]=Pn[F]=Pn[f]=Pn[s]=Pn[C]=Pn[k]=Pn[A]=Pn[x]=Pn[j]=Pn[p]=Pn[D]=Pn[g]=Pn[_]=Pn[m]=Pn[y]=Pn[b]=Pn[O]=Pn["[object Uint8ClampedArray]"]=Pn[N]=Pn[B]=!0,Pn[v]=Pn[h]=Pn[E]=!1;var $n={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},qn=parseFloat,Gn=parseInt,Vn="object"==typeof n&&n&&n.Object===Object&&n,Zn="object"==typeof self&&self&&self.Object===Object&&self,Kn=Vn||Zn||Function("return this")(),Hn=t&&!t.nodeType&&t,Qn=Hn&&"object"==typeof r&&r&&!r.nodeType&&r,Jn=Qn&&Qn.exports===Hn,Yn=Jn&&Vn.process,Xn=function(){try{var n=Qn&&Qn.require&&Qn.require("util").types;return n||Yn&&Yn.binding&&Yn.binding("util")}catch(t){}}(),nt=Xn&&Xn.isArrayBuffer,tt=Xn&&Xn.isDate,et=Xn&&Xn.isMap,rt=Xn&&Xn.isRegExp,ut=Xn&&Xn.isSet,it=Xn&&Xn.isTypedArray;function ot(n,t,e){switch(e.length){case 0:return n.call(t);case 1:return n.call(t,e[0]);case 2:return n.call(t,e[0],e[1]);case 3:return n.call(t,e[0],e[1],e[2])}return n.apply(t,e)}function at(n,t,e,r){for(var u=-1,i=null==n?0:n.length;++u-1}function ht(n,t,e){for(var r=-1,u=null==n?0:n.length;++r-1;);return e}function Lt(n,t){for(var e=n.length;e--&&Et(t,n[e],0)>-1;);return e}function Rt(n,t){for(var e=n.length,r=0;e--;)n[e]===t&&++r;return r}var zt=At({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),Tt=At({"&":"&","<":"<",">":">",'"':""","'":"'"});function Wt(n){return"\\"+$n[n]}function Mt(n){return zn.test(n)}function Ut(n){var t=-1,e=Array(n.size);return n.forEach((function(n,r){e[++t]=[r,n]})),e}function Pt(n,t){return function(e){return n(t(e))}}function $t(n,t){for(var e=-1,r=n.length,u=0,i=[];++e",""":'"',"'":"'"});var Ht=function n(t){var e,r=(t=null==t?Kn:Ht.defaults(Kn.Object(),t,Ht.pick(Kn,Wn))).Array,u=t.Date,hn=t.Error,dn=t.Function,pn=t.Math,Dn=t.Object,gn=t.RegExp,_n=t.String,mn=t.TypeError,yn=r.prototype,bn=dn.prototype,En=Dn.prototype,wn=t["__core-js_shared__"],Fn=bn.toString,Cn=En.hasOwnProperty,kn=0,An=(e=/[^.]+$/.exec(wn&&wn.keys&&wn.keys.IE_PROTO||""))?"Symbol(src)_1."+e:"",xn=En.toString,jn=Fn.call(Dn),On=Kn._,Nn=gn("^"+Fn.call(Cn).replace(V,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Bn=Jn?t.Buffer:void 0,Ln=t.Symbol,zn=t.Uint8Array,$n=Bn?Bn.allocUnsafe:void 0,Vn=Pt(Dn.getPrototypeOf,Dn),Zn=Dn.create,Hn=En.propertyIsEnumerable,Qn=yn.splice,Yn=Ln?Ln.isConcatSpreadable:void 0,Xn=Ln?Ln.iterator:void 0,mt=Ln?Ln.toStringTag:void 0,At=function(){try{var n=Xu(Dn,"defineProperty");return n({},"",{}),n}catch(t){}}(),Qt=t.clearTimeout!==Kn.clearTimeout&&t.clearTimeout,Jt=u&&u.now!==Kn.Date.now&&u.now,Yt=t.setTimeout!==Kn.setTimeout&&t.setTimeout,Xt=pn.ceil,ne=pn.floor,te=Dn.getOwnPropertySymbols,ee=Bn?Bn.isBuffer:void 0,re=t.isFinite,ue=yn.join,ie=Pt(Dn.keys,Dn),oe=pn.max,ae=pn.min,ce=u.now,le=t.parseInt,fe=pn.random,se=yn.reverse,ve=Xu(t,"DataView"),he=Xu(t,"Map"),de=Xu(t,"Promise"),pe=Xu(t,"Set"),De=Xu(t,"WeakMap"),ge=Xu(Dn,"create"),_e=De&&new De,me={},ye=ki(ve),be=ki(he),Ee=ki(de),we=ki(pe),Fe=ki(De),Ce=Ln?Ln.prototype:void 0,ke=Ce?Ce.valueOf:void 0,Ae=Ce?Ce.toString:void 0;function xe(n){if(qo(n)&&!Io(n)&&!(n instanceof Be)){if(n instanceof Ne)return n;if(Cn.call(n,"__wrapped__"))return Ai(n)}return new Ne(n)}var je=function(){function n(){}return function(t){if(!$o(t))return{};if(Zn)return Zn(t);n.prototype=t;var e=new n;return n.prototype=void 0,e}}();function Oe(){}function Ne(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=void 0}function Be(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Ie(n){var t=-1,e=null==n?0:n.length;for(this.clear();++t=t?n:t)),n}function Qe(n,t,e,r,u,i){var o,a=1&t,l=2&t,v=4&t;if(e&&(o=u?e(n,r,u,i):e(n)),void 0!==o)return o;if(!$o(n))return n;var E=Io(n);if(E){if(o=function(n){var t=n.length,e=new n.constructor(t);t&&"string"==typeof n[0]&&Cn.call(n,"index")&&(e.index=n.index,e.input=n.input);return e}(n),!a)return gu(n,o)}else{var I=ei(n),S=I==h||I==d;if(zo(n))return su(n,a);if(I==g||I==c||S&&!u){if(o=l||S?{}:ui(n),!a)return l?function(n,t){return _u(n,ti(n),t)}(n,function(n,t){return n&&_u(t,ba(t),n)}(o,n)):function(n,t){return _u(n,ni(n),t)}(n,Ve(o,n))}else{if(!Pn[I])return u?n:{};o=function(n,t,e){var r=n.constructor;switch(t){case w:return vu(n);case f:case s:return new r(+n);case F:return function(n,t){var e=t?vu(n.buffer):n.buffer;return new n.constructor(e,n.byteOffset,n.byteLength)}(n,e);case C:case k:case A:case x:case j:case O:case"[object Uint8ClampedArray]":case N:case B:return hu(n,e);case p:return new r;case D:case y:return new r(n);case _:return function(n){var t=new n.constructor(n.source,rn.exec(n));return t.lastIndex=n.lastIndex,t}(n);case m:return new r;case b:return u=n,ke?Dn(ke.call(u)):{}}var u}(n,I,a)}}i||(i=new ze);var L=i.get(n);if(L)return L;i.set(n,o),Ho(n)?n.forEach((function(r){o.add(Qe(r,t,e,r,n,i))})):Go(n)&&n.forEach((function(r,u){o.set(u,Qe(r,t,e,u,n,i))}));var R=E?void 0:(v?l?Vu:Gu:l?ba:ya)(n);return ct(R||n,(function(r,u){R&&(r=n[u=r]),$e(o,u,Qe(r,t,e,u,n,i))})),o}function Je(n,t,e){var r=e.length;if(null==n)return!r;for(n=Dn(n);r--;){var u=e[r],i=t[u],o=n[u];if(void 0===o&&!(u in n)||!i(o))return!1}return!0}function Ye(n,t,e){if("function"!=typeof n)throw new mn(i);return mi((function(){n.apply(void 0,e)}),t)}function Xe(n,t,e,r){var u=-1,i=vt,o=!0,a=n.length,c=[],l=t.length;if(!a)return c;e&&(t=dt(t,Nt(e))),r?(i=ht,o=!1):t.length>=200&&(i=It,o=!1,t=new Re(t));n:for(;++u-1},Se.prototype.set=function(n,t){var e=this.__data__,r=qe(e,n);return r<0?(++this.size,e.push([n,t])):e[r][1]=t,this},Le.prototype.clear=function(){this.size=0,this.__data__={hash:new Ie,map:new(he||Se),string:new Ie}},Le.prototype.delete=function(n){var t=Ju(this,n).delete(n);return this.size-=t?1:0,t},Le.prototype.get=function(n){return Ju(this,n).get(n)},Le.prototype.has=function(n){return Ju(this,n).has(n)},Le.prototype.set=function(n,t){var e=Ju(this,n),r=e.size;return e.set(n,t),this.size+=e.size==r?0:1,this},Re.prototype.add=Re.prototype.push=function(n){return this.__data__.set(n,"__lodash_hash_undefined__"),this},Re.prototype.has=function(n){return this.__data__.has(n)},ze.prototype.clear=function(){this.__data__=new Se,this.size=0},ze.prototype.delete=function(n){var t=this.__data__,e=t.delete(n);return this.size=t.size,e},ze.prototype.get=function(n){return this.__data__.get(n)},ze.prototype.has=function(n){return this.__data__.has(n)},ze.prototype.set=function(n,t){var e=this.__data__;if(e instanceof Se){var r=e.__data__;if(!he||r.length<199)return r.push([n,t]),this.size=++e.size,this;e=this.__data__=new Le(r)}return e.set(n,t),this.size=e.size,this};var nr=bu(cr),tr=bu(lr,!0);function er(n,t){var e=!0;return nr(n,(function(n,r,u){return e=!!t(n,r,u)})),e}function rr(n,t,e){for(var r=-1,u=n.length;++r0&&e(a)?t>1?ir(a,t-1,e,r,u):pt(u,a):r||(u[u.length]=a)}return u}var or=Eu(),ar=Eu(!0);function cr(n,t){return n&&or(n,t,ya)}function lr(n,t){return n&&ar(n,t,ya)}function fr(n,t){return st(t,(function(t){return Mo(n[t])}))}function sr(n,t){for(var e=0,r=(t=au(t,n)).length;null!=n&&et}function pr(n,t){return null!=n&&Cn.call(n,t)}function Dr(n,t){return null!=n&&t in Dn(n)}function gr(n,t,e){for(var u=e?ht:vt,i=n[0].length,o=n.length,a=o,c=r(o),l=1/0,f=[];a--;){var s=n[a];a&&t&&(s=dt(s,Nt(t))),l=ae(s.length,l),c[a]=!e&&(t||i>=120&&s.length>=120)?new Re(a&&s):void 0}s=n[0];var v=-1,h=c[0];n:for(;++v=a)return c;var l=e[r];return c*("desc"==l?-1:1)}}return n.index-t.index}(n,t,e)}))}function Ir(n,t,e){for(var r=-1,u=t.length,i={};++r-1;)a!==n&&Qn.call(a,c,1),Qn.call(n,c,1);return n}function Lr(n,t){for(var e=n?t.length:0,r=e-1;e--;){var u=t[e];if(e==r||u!==i){var i=u;oi(u)?Qn.call(n,u,1):Xr(n,u)}}return n}function Rr(n,t){return n+ne(fe()*(t-n+1))}function zr(n,t){var e="";if(!n||t<1||t>9007199254740991)return e;do{t%2&&(e+=n),(t=ne(t/2))&&(n+=n)}while(t);return e}function Tr(n,t){return yi(di(n,t,Va),n+"")}function Wr(n){return We(ja(n))}function Mr(n,t){var e=ja(n);return wi(e,He(t,0,e.length))}function Ur(n,t,e,r){if(!$o(n))return n;for(var u=-1,i=(t=au(t,n)).length,o=i-1,a=n;null!=a&&++ui?0:i+t),(e=e>i?i:e)<0&&(e+=i),i=t>e?0:e-t>>>0,t>>>=0;for(var o=r(i);++u>>1,o=n[i];null!==o&&!Jo(o)&&(e?o<=t:o=200){var l=t?null:zu(n);if(l)return qt(l);o=!1,u=It,c=new Re}else c=t?[]:a;n:for(;++r=r?n:Gr(n,t,e)}var fu=Qt||function(n){return Kn.clearTimeout(n)};function su(n,t){if(t)return n.slice();var e=n.length,r=$n?$n(e):new n.constructor(e);return n.copy(r),r}function vu(n){var t=new n.constructor(n.byteLength);return new zn(t).set(new zn(n)),t}function hu(n,t){var e=t?vu(n.buffer):n.buffer;return new n.constructor(e,n.byteOffset,n.length)}function du(n,t){if(n!==t){var e=void 0!==n,r=null===n,u=n==n,i=Jo(n),o=void 0!==t,a=null===t,c=t==t,l=Jo(t);if(!a&&!l&&!i&&n>t||i&&o&&c&&!a&&!l||r&&o&&c||!e&&c||!u)return 1;if(!r&&!i&&!l&&n1?e[u-1]:void 0,o=u>2?e[2]:void 0;for(i=n.length>3&&"function"==typeof i?(u--,i):void 0,o&&ai(e[0],e[1],o)&&(i=u<3?void 0:i,u=1),t=Dn(t);++r-1?u[i?t[o]:o]:void 0}}function Au(n){return qu((function(t){var e=t.length,r=e,u=Ne.prototype.thru;for(n&&t.reverse();r--;){var o=t[r];if("function"!=typeof o)throw new mn(i);if(u&&!a&&"wrapper"==Ku(o))var a=new Ne([],!0)}for(r=a?r:e;++r1&&m.reverse(),s&&l<_&&(m.length=l),this&&this!==Kn&&this instanceof g&&(C=D||Cu(C)),C.apply(F,m)}}function ju(n,t){return function(e,r){return function(n,t,e,r){return cr(n,(function(n,u,i){t(r,e(n),u,i)})),r}(e,n,t(r),{})}}function Ou(n,t){return function(e,r){var u;if(void 0===e&&void 0===r)return t;if(void 0!==e&&(u=e),void 0!==r){if(void 0===u)return r;"string"==typeof e||"string"==typeof r?(e=Jr(e),r=Jr(r)):(e=Qr(e),r=Qr(r)),u=n(e,r)}return u}}function Nu(n){return qu((function(t){return t=dt(t,Nt(Qu())),Tr((function(e){var r=this;return n(t,(function(n){return ot(n,r,e)}))}))}))}function Bu(n,t){var e=(t=void 0===t?" ":Jr(t)).length;if(e<2)return e?zr(t,n):t;var r=zr(t,Xt(n/Vt(t)));return Mt(t)?lu(Zt(r),0,n).join(""):r.slice(0,n)}function Iu(n){return function(t,e,u){return u&&"number"!=typeof u&&ai(t,e,u)&&(e=u=void 0),t=ea(t),void 0===e?(e=t,t=0):e=ea(e),function(n,t,e,u){for(var i=-1,o=oe(Xt((t-n)/(e||1)),0),a=r(o);o--;)a[u?o:++i]=n,n+=e;return a}(t,e,u=void 0===u?ta))return!1;var l=i.get(n);if(l&&i.get(t))return l==t;var f=-1,s=!0,v=2&e?new Re:void 0;for(i.set(n,t),i.set(t,n);++f-1&&n%1==0&&n1?"& ":"")+t[r],t=t.join(e>2?", ":" "),n.replace(J,"{\n/* [wrapped with "+t+"] */\n")}(r,function(n,t){return ct(a,(function(e){var r="_."+e[0];t&e[1]&&!vt(n,r)&&n.push(r)})),n.sort()}(function(n){var t=n.match(Y);return t?t[1].split(X):[]}(r),e)))}function Ei(n){var t=0,e=0;return function(){var r=ce(),u=16-(r-e);if(e=r,u>0){if(++t>=800)return arguments[0]}else t=0;return n.apply(void 0,arguments)}}function wi(n,t){var e=-1,r=n.length,u=r-1;for(t=void 0===t?r:t;++e1?n[t-1]:void 0;return e="function"==typeof e?(n.pop(),e):void 0,Zi(n,e)}));function no(n){var t=xe(n);return t.__chain__=!0,t}function to(n,t){return t(n)}var eo=qu((function(n){var t=n.length,e=t?n[0]:0,r=this.__wrapped__,u=function(t){return Ke(t,n)};return!(t>1||this.__actions__.length)&&r instanceof Be&&oi(e)?((r=r.slice(e,+e+(t?1:0))).__actions__.push({func:to,args:[u],thisArg:void 0}),new Ne(r,this.__chain__).thru((function(n){return t&&!n.length&&n.push(void 0),n}))):this.thru(u)}));var ro=mu((function(n,t,e){Cn.call(n,e)?++n[e]:Ze(n,e,1)}));var uo=ku(Ni),io=ku(Bi);function oo(n,t){return(Io(n)?ct:nr)(n,Qu(t,3))}function ao(n,t){return(Io(n)?lt:tr)(n,Qu(t,3))}var co=mu((function(n,t,e){Cn.call(n,e)?n[e].push(t):Ze(n,e,[t])}));var lo=Tr((function(n,t,e){var u=-1,i="function"==typeof t,o=Lo(n)?r(n.length):[];return nr(n,(function(n){o[++u]=i?ot(t,n,e):_r(n,t,e)})),o})),fo=mu((function(n,t,e){Ze(n,e,t)}));function so(n,t){return(Io(n)?dt:Ar)(n,Qu(t,3))}var vo=mu((function(n,t,e){n[e?0:1].push(t)}),(function(){return[[],[]]}));var ho=Tr((function(n,t){if(null==n)return[];var e=t.length;return e>1&&ai(n,t[0],t[1])?t=[]:e>2&&ai(t[0],t[1],t[2])&&(t=[t[0]]),Br(n,ir(t,1),[])})),po=Jt||function(){return Kn.Date.now()};function Do(n,t,e){return t=e?void 0:t,Wu(n,128,void 0,void 0,void 0,void 0,t=n&&null==t?n.length:t)}function go(n,t){var e;if("function"!=typeof t)throw new mn(i);return n=ra(n),function(){return--n>0&&(e=t.apply(this,arguments)),n<=1&&(t=void 0),e}}var _o=Tr((function(n,t,e){var r=1;if(e.length){var u=$t(e,Hu(_o));r|=32}return Wu(n,r,t,e,u)})),mo=Tr((function(n,t,e){var r=3;if(e.length){var u=$t(e,Hu(mo));r|=32}return Wu(t,r,n,e,u)}));function yo(n,t,e){var r,u,o,a,c,l,f=0,s=!1,v=!1,h=!0;if("function"!=typeof n)throw new mn(i);function d(t){var e=r,i=u;return r=u=void 0,f=t,a=n.apply(i,e)}function p(n){return f=n,c=mi(g,t),s?d(n):a}function D(n){var e=n-l;return void 0===l||e>=t||e<0||v&&n-f>=o}function g(){var n=po();if(D(n))return _(n);c=mi(g,function(n){var e=t-(n-l);return v?ae(e,o-(n-f)):e}(n))}function _(n){return c=void 0,h&&r?d(n):(r=u=void 0,a)}function m(){var n=po(),e=D(n);if(r=arguments,u=this,l=n,e){if(void 0===c)return p(l);if(v)return fu(c),c=mi(g,t),d(l)}return void 0===c&&(c=mi(g,t)),a}return t=ia(t)||0,$o(e)&&(s=!!e.leading,o=(v="maxWait"in e)?oe(ia(e.maxWait)||0,t):o,h="trailing"in e?!!e.trailing:h),m.cancel=function(){void 0!==c&&fu(c),f=0,r=l=u=c=void 0},m.flush=function(){return void 0===c?a:_(po())},m}var bo=Tr((function(n,t){return Ye(n,1,t)})),Eo=Tr((function(n,t,e){return Ye(n,ia(t)||0,e)}));function wo(n,t){if("function"!=typeof n||null!=t&&"function"!=typeof t)throw new mn(i);var e=function(){var r=arguments,u=t?t.apply(this,r):r[0],i=e.cache;if(i.has(u))return i.get(u);var o=n.apply(this,r);return e.cache=i.set(u,o)||i,o};return e.cache=new(wo.Cache||Le),e}function Fo(n){if("function"!=typeof n)throw new mn(i);return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}wo.Cache=Le;var Co=cu((function(n,t){var e=(t=1==t.length&&Io(t[0])?dt(t[0],Nt(Qu())):dt(ir(t,1),Nt(Qu()))).length;return Tr((function(r){for(var u=-1,i=ae(r.length,e);++u=t})),Bo=mr(function(){return arguments}())?mr:function(n){return qo(n)&&Cn.call(n,"callee")&&!Hn.call(n,"callee")},Io=r.isArray,So=nt?Nt(nt):function(n){return qo(n)&&hr(n)==w};function Lo(n){return null!=n&&Po(n.length)&&!Mo(n)}function Ro(n){return qo(n)&&Lo(n)}var zo=ee||ic,To=tt?Nt(tt):function(n){return qo(n)&&hr(n)==s};function Wo(n){if(!qo(n))return!1;var t=hr(n);return t==v||"[object DOMException]"==t||"string"==typeof n.message&&"string"==typeof n.name&&!Zo(n)}function Mo(n){if(!$o(n))return!1;var t=hr(n);return t==h||t==d||"[object AsyncFunction]"==t||"[object Proxy]"==t}function Uo(n){return"number"==typeof n&&n==ra(n)}function Po(n){return"number"==typeof n&&n>-1&&n%1==0&&n<=9007199254740991}function $o(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function qo(n){return null!=n&&"object"==typeof n}var Go=et?Nt(et):function(n){return qo(n)&&ei(n)==p};function Vo(n){return"number"==typeof n||qo(n)&&hr(n)==D}function Zo(n){if(!qo(n)||hr(n)!=g)return!1;var t=Vn(n);if(null===t)return!0;var e=Cn.call(t,"constructor")&&t.constructor;return"function"==typeof e&&e instanceof e&&Fn.call(e)==jn}var Ko=rt?Nt(rt):function(n){return qo(n)&&hr(n)==_};var Ho=ut?Nt(ut):function(n){return qo(n)&&ei(n)==m};function Qo(n){return"string"==typeof n||!Io(n)&&qo(n)&&hr(n)==y}function Jo(n){return"symbol"==typeof n||qo(n)&&hr(n)==b}var Yo=it?Nt(it):function(n){return qo(n)&&Po(n.length)&&!!Un[hr(n)]};var Xo=Su(kr),na=Su((function(n,t){return n<=t}));function ta(n){if(!n)return[];if(Lo(n))return Qo(n)?Zt(n):gu(n);if(Xn&&n[Xn])return function(n){for(var t,e=[];!(t=n.next()).done;)e.push(t.value);return e}(n[Xn]());var t=ei(n);return(t==p?Ut:t==m?qt:ja)(n)}function ea(n){return n?(n=ia(n))===1/0||n===-1/0?17976931348623157e292*(n<0?-1:1):n==n?n:0:0===n?n:0}function ra(n){var t=ea(n),e=t%1;return t==t?e?t-e:t:0}function ua(n){return n?He(ra(n),0,4294967295):0}function ia(n){if("number"==typeof n)return n;if(Jo(n))return NaN;if($o(n)){var t="function"==typeof n.valueOf?n.valueOf():n;n=$o(t)?t+"":t}if("string"!=typeof n)return 0===n?n:+n;n=n.replace(K,"");var e=on.test(n);return e||cn.test(n)?Gn(n.slice(2),e?2:8):un.test(n)?NaN:+n}function oa(n){return _u(n,ba(n))}function aa(n){return null==n?"":Jr(n)}var ca=yu((function(n,t){if(si(t)||Lo(t))_u(t,ya(t),n);else for(var e in t)Cn.call(t,e)&&$e(n,e,t[e])})),la=yu((function(n,t){_u(t,ba(t),n)})),fa=yu((function(n,t,e,r){_u(t,ba(t),n,r)})),sa=yu((function(n,t,e,r){_u(t,ya(t),n,r)})),va=qu(Ke);var ha=Tr((function(n,t){n=Dn(n);var e=-1,r=t.length,u=r>2?t[2]:void 0;for(u&&ai(t[0],t[1],u)&&(r=1);++e1),t})),_u(n,Vu(n),e),r&&(e=Qe(e,7,Pu));for(var u=t.length;u--;)Xr(e,t[u]);return e}));var Ca=qu((function(n,t){return null==n?{}:function(n,t){return Ir(n,t,(function(t,e){return Da(n,e)}))}(n,t)}));function ka(n,t){if(null==n)return{};var e=dt(Vu(n),(function(n){return[n]}));return t=Qu(t),Ir(n,e,(function(n,e){return t(n,e[0])}))}var Aa=Tu(ya),xa=Tu(ba);function ja(n){return null==n?[]:Bt(n,ya(n))}var Oa=Fu((function(n,t,e){return t=t.toLowerCase(),n+(e?Na(t):t)}));function Na(n){return Wa(aa(n).toLowerCase())}function Ba(n){return(n=aa(n))&&n.replace(fn,zt).replace(Sn,"")}var Ia=Fu((function(n,t,e){return n+(e?"-":"")+t.toLowerCase()})),Sa=Fu((function(n,t,e){return n+(e?" ":"")+t.toLowerCase()})),La=wu("toLowerCase");var Ra=Fu((function(n,t,e){return n+(e?"_":"")+t.toLowerCase()}));var za=Fu((function(n,t,e){return n+(e?" ":"")+Wa(t)}));var Ta=Fu((function(n,t,e){return n+(e?" ":"")+t.toUpperCase()})),Wa=wu("toUpperCase");function Ma(n,t,e){return n=aa(n),void 0===(t=e?void 0:t)?function(n){return Tn.test(n)}(n)?function(n){return n.match(Rn)||[]}(n):function(n){return n.match(nn)||[]}(n):n.match(t)||[]}var Ua=Tr((function(n,t){try{return ot(n,void 0,t)}catch(e){return Wo(e)?e:new hn(e)}})),Pa=qu((function(n,t){return ct(t,(function(t){t=Ci(t),Ze(n,t,_o(n[t],n))})),n}));function $a(n){return function(){return n}}var qa=Au(),Ga=Au(!0);function Va(n){return n}function Za(n){return wr("function"==typeof n?n:Qe(n,1))}var Ka=Tr((function(n,t){return function(e){return _r(e,n,t)}})),Ha=Tr((function(n,t){return function(e){return _r(n,e,t)}}));function Qa(n,t,e){var r=ya(t),u=fr(t,r);null!=e||$o(t)&&(u.length||!r.length)||(e=t,t=n,n=this,u=fr(t,ya(t)));var i=!($o(e)&&"chain"in e&&!e.chain),o=Mo(n);return ct(u,(function(e){var r=t[e];n[e]=r,o&&(n.prototype[e]=function(){var t=this.__chain__;if(i||t){var e=n(this.__wrapped__),u=e.__actions__=gu(this.__actions__);return u.push({func:r,args:arguments,thisArg:n}),e.__chain__=t,e}return r.apply(n,pt([this.value()],arguments))})})),n}function Ja(){}var Ya=Nu(dt),Xa=Nu(ft),nc=Nu(_t);function tc(n){return ci(n)?kt(Ci(n)):function(n){return function(t){return sr(t,n)}}(n)}var ec=Iu(),rc=Iu(!0);function uc(){return[]}function ic(){return!1}var oc=Ou((function(n,t){return n+t}),0),ac=Ru("ceil"),cc=Ou((function(n,t){return n/t}),1),lc=Ru("floor");var fc,sc=Ou((function(n,t){return n*t}),1),vc=Ru("round"),hc=Ou((function(n,t){return n-t}),0);return xe.after=function(n,t){if("function"!=typeof t)throw new mn(i);return n=ra(n),function(){if(--n<1)return t.apply(this,arguments)}},xe.ary=Do,xe.assign=ca,xe.assignIn=la,xe.assignInWith=fa,xe.assignWith=sa,xe.at=va,xe.before=go,xe.bind=_o,xe.bindAll=Pa,xe.bindKey=mo,xe.castArray=function(){if(!arguments.length)return[];var n=arguments[0];return Io(n)?n:[n]},xe.chain=no,xe.chunk=function(n,t,e){t=(e?ai(n,t,e):void 0===t)?1:oe(ra(t),0);var u=null==n?0:n.length;if(!u||t<1)return[];for(var i=0,o=0,a=r(Xt(u/t));iu?0:u+e),(r=void 0===r||r>u?u:ra(r))<0&&(r+=u),r=e>r?0:ua(r);e>>0)?(n=aa(n))&&("string"==typeof t||null!=t&&!Ko(t))&&!(t=Jr(t))&&Mt(n)?lu(Zt(n),0,e):n.split(t,e):[]},xe.spread=function(n,t){if("function"!=typeof n)throw new mn(i);return t=null==t?0:oe(ra(t),0),Tr((function(e){var r=e[t],u=lu(e,0,t);return r&&pt(u,r),ot(n,this,u)}))},xe.tail=function(n){var t=null==n?0:n.length;return t?Gr(n,1,t):[]},xe.take=function(n,t,e){return n&&n.length?Gr(n,0,(t=e||void 0===t?1:ra(t))<0?0:t):[]},xe.takeRight=function(n,t,e){var r=null==n?0:n.length;return r?Gr(n,(t=r-(t=e||void 0===t?1:ra(t)))<0?0:t,r):[]},xe.takeRightWhile=function(n,t){return n&&n.length?tu(n,Qu(t,3),!1,!0):[]},xe.takeWhile=function(n,t){return n&&n.length?tu(n,Qu(t,3)):[]},xe.tap=function(n,t){return t(n),n},xe.throttle=function(n,t,e){var r=!0,u=!0;if("function"!=typeof n)throw new mn(i);return $o(e)&&(r="leading"in e?!!e.leading:r,u="trailing"in e?!!e.trailing:u),yo(n,t,{leading:r,maxWait:t,trailing:u})},xe.thru=to,xe.toArray=ta,xe.toPairs=Aa,xe.toPairsIn=xa,xe.toPath=function(n){return Io(n)?dt(n,Ci):Jo(n)?[n]:gu(Fi(aa(n)))},xe.toPlainObject=oa,xe.transform=function(n,t,e){var r=Io(n),u=r||zo(n)||Yo(n);if(t=Qu(t,4),null==e){var i=n&&n.constructor;e=u?r?new i:[]:$o(n)&&Mo(i)?je(Vn(n)):{}}return(u?ct:cr)(n,(function(n,r,u){return t(e,n,r,u)})),e},xe.unary=function(n){return Do(n,1)},xe.union=$i,xe.unionBy=qi,xe.unionWith=Gi,xe.uniq=function(n){return n&&n.length?Yr(n):[]},xe.uniqBy=function(n,t){return n&&n.length?Yr(n,Qu(t,2)):[]},xe.uniqWith=function(n,t){return t="function"==typeof t?t:void 0,n&&n.length?Yr(n,void 0,t):[]},xe.unset=function(n,t){return null==n||Xr(n,t)},xe.unzip=Vi,xe.unzipWith=Zi,xe.update=function(n,t,e){return null==n?n:nu(n,t,ou(e))},xe.updateWith=function(n,t,e,r){return r="function"==typeof r?r:void 0,null==n?n:nu(n,t,ou(e),r)},xe.values=ja,xe.valuesIn=function(n){return null==n?[]:Bt(n,ba(n))},xe.without=Ki,xe.words=Ma,xe.wrap=function(n,t){return ko(ou(t),n)},xe.xor=Hi,xe.xorBy=Qi,xe.xorWith=Ji,xe.zip=Yi,xe.zipObject=function(n,t){return uu(n||[],t||[],$e)},xe.zipObjectDeep=function(n,t){return uu(n||[],t||[],Ur)},xe.zipWith=Xi,xe.entries=Aa,xe.entriesIn=xa,xe.extend=la,xe.extendWith=fa,Qa(xe,xe),xe.add=oc,xe.attempt=Ua,xe.camelCase=Oa,xe.capitalize=Na,xe.ceil=ac,xe.clamp=function(n,t,e){return void 0===e&&(e=t,t=void 0),void 0!==e&&(e=(e=ia(e))==e?e:0),void 0!==t&&(t=(t=ia(t))==t?t:0),He(ia(n),t,e)},xe.clone=function(n){return Qe(n,4)},xe.cloneDeep=function(n){return Qe(n,5)},xe.cloneDeepWith=function(n,t){return Qe(n,5,t="function"==typeof t?t:void 0)},xe.cloneWith=function(n,t){return Qe(n,4,t="function"==typeof t?t:void 0)},xe.conformsTo=function(n,t){return null==t||Je(n,t,ya(t))},xe.deburr=Ba,xe.defaultTo=function(n,t){return null==n||n!=n?t:n},xe.divide=cc,xe.endsWith=function(n,t,e){n=aa(n),t=Jr(t);var r=n.length,u=e=void 0===e?r:He(ra(e),0,r);return(e-=t.length)>=0&&n.slice(e,u)==t},xe.eq=jo,xe.escape=function(n){return(n=aa(n))&&W.test(n)?n.replace(z,Tt):n},xe.escapeRegExp=function(n){return(n=aa(n))&&Z.test(n)?n.replace(V,"\\$&"):n},xe.every=function(n,t,e){var r=Io(n)?ft:er;return e&&ai(n,t,e)&&(t=void 0),r(n,Qu(t,3))},xe.find=uo,xe.findIndex=Ni,xe.findKey=function(n,t){return yt(n,Qu(t,3),cr)},xe.findLast=io,xe.findLastIndex=Bi,xe.findLastKey=function(n,t){return yt(n,Qu(t,3),lr)},xe.floor=lc,xe.forEach=oo,xe.forEachRight=ao,xe.forIn=function(n,t){return null==n?n:or(n,Qu(t,3),ba)},xe.forInRight=function(n,t){return null==n?n:ar(n,Qu(t,3),ba)},xe.forOwn=function(n,t){return n&&cr(n,Qu(t,3))},xe.forOwnRight=function(n,t){return n&&lr(n,Qu(t,3))},xe.get=pa,xe.gt=Oo,xe.gte=No,xe.has=function(n,t){return null!=n&&ri(n,t,pr)},xe.hasIn=Da,xe.head=Si,xe.identity=Va,xe.includes=function(n,t,e,r){n=Lo(n)?n:ja(n),e=e&&!r?ra(e):0;var u=n.length;return e<0&&(e=oe(u+e,0)),Qo(n)?e<=u&&n.indexOf(t,e)>-1:!!u&&Et(n,t,e)>-1},xe.indexOf=function(n,t,e){var r=null==n?0:n.length;if(!r)return-1;var u=null==e?0:ra(e);return u<0&&(u=oe(r+u,0)),Et(n,t,u)},xe.inRange=function(n,t,e){return t=ea(t),void 0===e?(e=t,t=0):e=ea(e),function(n,t,e){return n>=ae(t,e)&&n=-9007199254740991&&n<=9007199254740991},xe.isSet=Ho,xe.isString=Qo,xe.isSymbol=Jo,xe.isTypedArray=Yo,xe.isUndefined=function(n){return void 0===n},xe.isWeakMap=function(n){return qo(n)&&ei(n)==E},xe.isWeakSet=function(n){return qo(n)&&"[object WeakSet]"==hr(n)},xe.join=function(n,t){return null==n?"":ue.call(n,t)},xe.kebabCase=Ia,xe.last=Ti,xe.lastIndexOf=function(n,t,e){var r=null==n?0:n.length;if(!r)return-1;var u=r;return void 0!==e&&(u=(u=ra(e))<0?oe(r+u,0):ae(u,r-1)),t==t?function(n,t,e){for(var r=e+1;r--;)if(n[r]===t)return r;return r}(n,t,u):bt(n,Ft,u,!0)},xe.lowerCase=Sa,xe.lowerFirst=La,xe.lt=Xo,xe.lte=na,xe.max=function(n){return n&&n.length?rr(n,Va,dr):void 0},xe.maxBy=function(n,t){return n&&n.length?rr(n,Qu(t,2),dr):void 0},xe.mean=function(n){return Ct(n,Va)},xe.meanBy=function(n,t){return Ct(n,Qu(t,2))},xe.min=function(n){return n&&n.length?rr(n,Va,kr):void 0},xe.minBy=function(n,t){return n&&n.length?rr(n,Qu(t,2),kr):void 0},xe.stubArray=uc,xe.stubFalse=ic,xe.stubObject=function(){return{}},xe.stubString=function(){return""},xe.stubTrue=function(){return!0},xe.multiply=sc,xe.nth=function(n,t){return n&&n.length?Nr(n,ra(t)):void 0},xe.noConflict=function(){return Kn._===this&&(Kn._=On),this},xe.noop=Ja,xe.now=po,xe.pad=function(n,t,e){n=aa(n);var r=(t=ra(t))?Vt(n):0;if(!t||r>=t)return n;var u=(t-r)/2;return Bu(ne(u),e)+n+Bu(Xt(u),e)},xe.padEnd=function(n,t,e){n=aa(n);var r=(t=ra(t))?Vt(n):0;return t&&rt){var r=n;n=t,t=r}if(e||n%1||t%1){var u=fe();return ae(n+u*(t-n+qn("1e-"+((u+"").length-1))),t)}return Rr(n,t)},xe.reduce=function(n,t,e){var r=Io(n)?Dt:xt,u=arguments.length<3;return r(n,Qu(t,4),e,u,nr)},xe.reduceRight=function(n,t,e){var r=Io(n)?gt:xt,u=arguments.length<3;return r(n,Qu(t,4),e,u,tr)},xe.repeat=function(n,t,e){return t=(e?ai(n,t,e):void 0===t)?1:ra(t),zr(aa(n),t)},xe.replace=function(){var n=arguments,t=aa(n[0]);return n.length<3?t:t.replace(n[1],n[2])},xe.result=function(n,t,e){var r=-1,u=(t=au(t,n)).length;for(u||(u=1,n=void 0);++r9007199254740991)return[];var e=4294967295,r=ae(n,4294967295);n-=4294967295;for(var u=Ot(r,t=Qu(t));++e=i)return n;var a=e-Vt(r);if(a<1)return r;var c=o?lu(o,0,a).join(""):n.slice(0,a);if(void 0===u)return c+r;if(o&&(a+=c.length-a),Ko(u)){if(n.slice(a).search(u)){var l,f=c;for(u.global||(u=gn(u.source,aa(rn.exec(u))+"g")),u.lastIndex=0;l=u.exec(f);)var s=l.index;c=c.slice(0,void 0===s?a:s)}}else if(n.indexOf(Jr(u),a)!=a){var v=c.lastIndexOf(u);v>-1&&(c=c.slice(0,v))}return c+r},xe.unescape=function(n){return(n=aa(n))&&T.test(n)?n.replace(R,Kt):n},xe.uniqueId=function(n){var t=++kn;return aa(n)+t},xe.upperCase=Ta,xe.upperFirst=Wa,xe.each=oo,xe.eachRight=ao,xe.first=Si,Qa(xe,(fc={},cr(xe,(function(n,t){Cn.call(xe.prototype,t)||(fc[t]=n)})),fc),{chain:!1}),xe.VERSION="4.17.15",ct(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(n){xe[n].placeholder=xe})),ct(["drop","take"],(function(n,t){Be.prototype[n]=function(e){e=void 0===e?1:oe(ra(e),0);var r=this.__filtered__&&!t?new Be(this):this.clone();return r.__filtered__?r.__takeCount__=ae(e,r.__takeCount__):r.__views__.push({size:ae(e,4294967295),type:n+(r.__dir__<0?"Right":"")}),r},Be.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}})),ct(["filter","map","takeWhile"],(function(n,t){var e=t+1,r=1==e||3==e;Be.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:Qu(n,3),type:e}),t.__filtered__=t.__filtered__||r,t}})),ct(["head","last"],(function(n,t){var e="take"+(t?"Right":"");Be.prototype[n]=function(){return this[e](1).value()[0]}})),ct(["initial","tail"],(function(n,t){var e="drop"+(t?"":"Right");Be.prototype[n]=function(){return this.__filtered__?new Be(this):this[e](1)}})),Be.prototype.compact=function(){return this.filter(Va)},Be.prototype.find=function(n){return this.filter(n).head()},Be.prototype.findLast=function(n){return this.reverse().find(n)},Be.prototype.invokeMap=Tr((function(n,t){return"function"==typeof n?new Be(this):this.map((function(e){return _r(e,n,t)}))})),Be.prototype.reject=function(n){return this.filter(Fo(Qu(n)))},Be.prototype.slice=function(n,t){n=ra(n);var e=this;return e.__filtered__&&(n>0||t<0)?new Be(e):(n<0?e=e.takeRight(-n):n&&(e=e.drop(n)),void 0!==t&&(e=(t=ra(t))<0?e.dropRight(-t):e.take(t-n)),e)},Be.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},Be.prototype.toArray=function(){return this.take(4294967295)},cr(Be.prototype,(function(n,t){var e=/^(?:filter|find|map|reject)|While$/.test(t),r=/^(?:head|last)$/.test(t),u=xe[r?"take"+("last"==t?"Right":""):t],i=r||/^find/.test(t);u&&(xe.prototype[t]=function(){var t=this.__wrapped__,o=r?[1]:arguments,a=t instanceof Be,c=o[0],l=a||Io(t),f=function(n){var t=u.apply(xe,pt([n],o));return r&&s?t[0]:t};l&&e&&"function"==typeof c&&1!=c.length&&(a=l=!1);var s=this.__chain__,v=!!this.__actions__.length,h=i&&!s,d=a&&!v;if(!i&&l){t=d?t:new Be(this);var p=n.apply(t,o);return p.__actions__.push({func:to,args:[f],thisArg:void 0}),new Ne(p,s)}return h&&d?n.apply(this,o):(p=this.thru(f),h?r?p.value()[0]:p.value():p)})})),ct(["pop","push","shift","sort","splice","unshift"],(function(n){var t=yn[n],e=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",r=/^(?:pop|shift)$/.test(n);xe.prototype[n]=function(){var n=arguments;if(r&&!this.__chain__){var u=this.value();return t.apply(Io(u)?u:[],n)}return this[e]((function(e){return t.apply(Io(e)?e:[],n)}))}})),cr(Be.prototype,(function(n,t){var e=xe[t];if(e){var r=e.name+"";Cn.call(me,r)||(me[r]=[]),me[r].push({name:t,func:e})}})),me[xu(void 0,2).name]=[{name:"wrapper",func:void 0}],Be.prototype.clone=function(){var n=new Be(this.__wrapped__);return n.__actions__=gu(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=gu(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=gu(this.__views__),n},Be.prototype.reverse=function(){if(this.__filtered__){var n=new Be(this);n.__dir__=-1,n.__filtered__=!0}else(n=this.clone()).__dir__*=-1;return n},Be.prototype.value=function(){var n=this.__wrapped__.value(),t=this.__dir__,e=Io(n),r=t<0,u=e?n.length:0,i=function(n,t,e){var r=-1,u=e.length;for(;++r=this.__values__.length;return{done:n,value:n?void 0:this.__values__[this.__index__++]}},xe.prototype.plant=function(n){for(var t,e=this;e instanceof Oe;){var r=Ai(e);r.__index__=0,r.__values__=void 0,t?u.__wrapped__=r:t=r;var u=r;e=e.__wrapped__}return u.__wrapped__=n,t},xe.prototype.reverse=function(){var n=this.__wrapped__;if(n instanceof Be){var t=n;return this.__actions__.length&&(t=new Be(this)),(t=t.reverse()).__actions__.push({func:to,args:[Pi],thisArg:void 0}),new Ne(t,this.__chain__)}return this.thru(Pi)},xe.prototype.toJSON=xe.prototype.valueOf=xe.prototype.value=function(){return eu(this.__wrapped__,this.__actions__)},xe.prototype.first=xe.prototype.head,Xn&&(xe.prototype[Xn]=function(){return this}),xe}();Kn._=Ht,void 0===(u=function(){return Ht}.call(t,e,t,r))||(r.exports=u)}).call(this)}).call(this,e(76),e(453)(n))},451:function(n,t,e){"use strict";var r=e(0),u=Object(r.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=u},452:function(n,t,e){"use strict";e.d(t,"a",(function(){return i}));e(77),e(470),e(436),e(78);var r=e(472),u=e.n(r);function i(n,t){var e=new u.a;return n.map((function(n){var r=n;return"string"==typeof n&&(r={label:n,permalink:"/blog/tags/"+e.slug(n)}),function(n,t){var e=n.label.split(": ",2),r=e[0],u=e[1],i="primary";switch(t){case"blog":case"guides":i=function(n){switch(n){case"domain":return"blue";case"type":return"pink";default:return"primary"}}(r)}return{category:r,count:n.count,label:n.label,permalink:n.permalink,style:i,value:u}}(r,t)}))}},453:function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},462:function(n,t,e){var r=e(30),u=e(54),i=e(27),o=e(26),a=e(463);n.exports=function(n,t){var e=1==n,c=2==n,l=3==n,f=4==n,s=6==n,v=5==n||s,h=t||a;return function(t,a,d){for(var p,D,g=i(t),_=u(g),m=r(a,d,3),y=o(_.length),b=0,E=e?h(t,y):c?h(t,0):void 0;y>b;b++)if((v||b in _)&&(D=m(p=_[b],b,g),n))if(e)E[b]=D;else if(D)switch(n){case 3:return!0;case 5:return p;case 6:return b;case 2:E.push(p)}else if(f)return!1;return s?-1:l||f?f:E}}},463:function(n,t,e){var r=e(464);n.exports=function(n,t){return new(r(n))(t)}},464:function(n,t,e){var r=e(13),u=e(465),i=e(2)("species");n.exports=function(n){var t;return u(n)&&("function"!=typeof(t=n.constructor)||t!==Array&&!u(t.prototype)||(t=void 0),r(t)&&null===(t=t[i])&&(t=void 0)),void 0===t?Array:t}},465:function(n,t,e){var r=e(23);n.exports=Array.isArray||function(n){return"Array"==r(n)}},471:function(n,t,e){"use strict";var r=e(0),u=e.n(r),i=e(427),o=e(420),a=e.n(o);t.a=function(n){var t=n.count,e=n.label,r=n.permalink,o=n.style,c=n.value,l=n.valueOnly;return u.a.createElement(i.a,{to:r+"/",className:a()("badge","badge--rounded","badge--"+o)},l?c:e,t&&u.a.createElement(u.a.Fragment,null," (",t,")"))}},472:function(n,t,e){var r=e(473);n.exports=a;var u=Object.hasOwnProperty,i=/\s/g,o=/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~\u2019]/g;function a(){if(!(this instanceof a))return new a;this.reset()}function c(n,t){return"string"!=typeof n?"":(t||(n=n.toLowerCase()),n.trim().replace(o,"").replace(r(),"").replace(i,"-"))}a.prototype.slug=function(n,t){for(var e=c(n,!0===t),r=e;u.call(this.occurrences,e);)this.occurrences[r]++,e=r+"-"+this.occurrences[r];return this.occurrences[e]=0,e},a.prototype.reset=function(){this.occurrences=Object.create(null)},a.slug=c},473:function(n,t){n.exports=function(){return/[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD79\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED0\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3]|\uD83E[\uDD10-\uDD18\uDD80-\uDD84\uDDC0]|\uD83C\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uD83C\uDDFE\uD83C[\uDDEA\uDDF9]|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDFC\uD83C[\uDDEB\uDDF8]|\uD83C\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uD83C\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF8\uDDFE\uDDFF]|\uD83C\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uD83C\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uD83C\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uD83C\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uD83C\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uD83C\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uD83C\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uD83C\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uD83C\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uD83C\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uD83C\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uD83C\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uD83C\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uD83C\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uD83C\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uD83C\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|[#\*0-9]\u20E3/g}},477:function(n,t,e){"use strict";var r=e(1),u=e(0),i=e.n(u),o=(e(427),e(471)),a=e(420),c=e.n(a),l=e(452),f=e(141),s=e.n(f);t.a=function(n){var t,e=n.block,u=n.colorProfile,a=n.tags,f=n.valuesOnly,v=Object(l.a)(a,u);return i.a.createElement("div",{className:c()(s.a.tags,(t={},t[s.a.tagsBlock]=e,t))},v.map((function(n,t){return i.a.createElement(o.a,Object(r.a)({key:t,valueOnly:f},n))})))}},513:function(n,t,e){"use strict";e(29),e(22),e(21),e(52);var r=e(0),u=e.n(r),i=(e(425),e(436),e(427)),o=e(437),a=e.n(o),c=e(477),l=e(452),f=e(433),s=e(438);e(142);var v=function(n){var t=n.frontMatter,e=n.metadata,r=(n.isGuidePage,Object(s.a)().isDarkTheme),o=e.categories,v=(e.description,e.permalink),h=(e.readingTime,e.seriesPosition),d=e.tags,p=(t.author_github,t.cover_label),D=(t.last_modified_on,t.title),g=Object(l.a)(d,"guides"),_=g.find((function(n){return"domain"==n.category})),m=_?_.value:"default",y=g.find((function(n){return"language"==n.category})),b=y?y.value:null,E=g.find((function(n){return"framework"==n.category})),w=E?E.value:null,F=g.find((function(n){return"technology"==n.category})),C=F?F.value:null,k=g.find((function(n){return"cloud_provider"==n.category})),A=k?k.value:null,x=g.find((function(n){return"provider"==n.category})),j=x?x.value:null,O=g.find((function(n){return"platform"==n.category})),N=O?O.value:null,B=g.find((function(n){return"source"==n.category})),I=B?B.value:null,S=g.find((function(n){return"sink"==n.category})),L=S?S.value:null,R=Object(f.a)().siteConfig.customFields.metadata,z=R.installation,T=R.sources,W=R.sinks,M=R.languages,U=R.frameworks,P=R.technologies,$=R.cloud_providers,q=R.providers,G=z.platforms,V=N&&G[N],Z=I&&T[I],K=L&&W[L],H=b&&M.find((function(n){return n.name===b})),Q=w&&U.find((function(n){return n.name===w})),J=C&&P.find((function(n){return n.name===C})),Y=A&&$.find((function(n){return n.name===A})),X=j&&q.find((function(n){return n.name===j})),nn=null!==(V||Z),tn=null!=K,en=null;Q?en=r?Q.dark_logo_path:Q.logo_path:J?en=r?J.dark_logo_path:J.logo_path:Y?en=r?Y.dark_logo_path:Y.logo_path:X?en=r?X.dark_logo_path:X.logo_path:H?en=r?H.dark_logo_path:H.logo_path:V?en=V.logo_path:Z&&(en=Z.logo_path);var rn=null;return K&&(rn=K.logo_path),u.a.createElement(i.a,{to:v+"/",className:"guide-item"},u.a.createElement("article",null,u.a.createElement("div",{className:"domain-bg domain-bg--"+m+" domain-bg--hover"},u.a.createElement("header",null,u.a.createElement("div",{className:"category"},o[0].name),u.a.createElement("h2",{title:D},h&&h+". ",p||D)),u.a.createElement("footer",null,en&&u.a.createElement(a.a,{src:en,className:"logo"}),!en&&nn&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),rn&&u.a.createElement(a.a,{src:rn,className:"logo"}),!rn&&tn&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),!en&&!rn&&!nn&&!tn&&u.a.createElement(c.a,{colorProfile:"guides",tags:d}),u.a.createElement("div",{className:"action"},"read now")))))},h=e(447),d=e(448),p=e.n(d),D=e(420),g=e.n(D);e(143);function _(n){var t=n.groupLevel,e=n.items,r=n.large,i=n.staggered,o=p()(e).map((function(n){return n.content.metadata.categories[t-1]})).uniqBy("permalink").sortBy("title").keyBy("permalink").value(),a=p.a.groupBy(e,(function(n){return n.content.metadata.categories[t-1].permalink})),c=Object(h.a)("h"+(t+1));return Object.keys(o).map((function(n,t){var e=a[n],l=o[n];return u.a.createElement("section",{key:t},u.a.createElement(c,{id:n},l.title),l.description&&u.a.createElement("div",{className:"sub-title"},l.description),u.a.createElement(m,{items:e,large:r,staggered:i}))}))}function m(n){var t=n.groupLevel,e=n.items,r=n.large,i=n.staggered;if(t)return u.a.createElement(_,{groupLevel:t,items:e});var o,a=(o=e,p.a.sortBy(o,["content.metadata.seriesPosition",function(n){return n.content.metadata.coverLabel.toLowerCase()}]));return u.a.createElement("div",{className:"guides"},u.a.createElement("div",{className:g()("guide-items",{"guide-items--l":r,"guide-items--staggered":i})},a.map((function(n){var t=n.content;return u.a.createElement(v,{key:t.metadata.permalink,frontMatter:t.frontMatter,metadata:t.metadata,truncated:t.metadata.truncated},u.a.createElement(t,null))}))))}t.a=m}}]); \ No newline at end of file +/*! For license information please see d9deea5f.4add985c.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[228],{380:function(n,t,e){"use strict";e.r(t);var r=e(0),u=e.n(r),i=e(445),o=e(516),a=e(430);t.default=function(n){var t=n.metadata.category,e=n.items;return u.a.createElement(i.a,{title:t.title+" Guides",description:"All "+t.title+" guides"},u.a.createElement("header",{className:"hero hero--clean"},u.a.createElement("div",{className:"container"},u.a.createElement("h1",null,t.title," Guides"),t.description&&u.a.createElement("div",{className:"hero--subtitle"},t.description),u.a.createElement("div",null,u.a.createElement(a.a,{to:"/guides"},"View All Guides")))),u.a.createElement("main",{className:"container container--s"},u.a.createElement(o.a,{items:e,staggered:null!=e[0].content.metadata.seriesPosition})))}},423:function(n,t,e){var r;!function(){"use strict";var e={}.hasOwnProperty;function u(){for(var n=[],t=0;t1?arguments[1]:void 0)}}),e(74)("find")},445:function(n,t,e){"use strict";e(457);var r=e(0),u=e.n(r),i=e(458),o=e(443),a=e(1),c=(e(446),e(447),e(459),e(430)),l=e(460),f=e(440),s=e.n(f),v=e(461),h=e.n(v),d=e(436),p=e(423),D=e.n(p),g=e(135),_=e.n(g),m=function(){return u.a.createElement("span",{className:D()(_.a.toggle,_.a.moon)})},y=function(){return u.a.createElement("span",{className:D()(_.a.toggle,_.a.sun)})},b=function(n){var t=Object(d.a)().isClient;return u.a.createElement(h.a,Object(a.a)({disabled:!t,icons:{checked:u.a.createElement(m,null),unchecked:u.a.createElement(y,null)}},n))};function E(){var n=Object(d.a)().siteConfig,t=(void 0===n?{}:n).customFields.metadata.latest_post,e=Date.parse(t.date),r=new Date,u=Math.abs(r-e),i=Math.ceil(u/864e5),o=null;return"undefined"!=typeof window&&(o=new Date(parseInt(window.localStorage.getItem("blogViewedAt")||"0"))),i<30&&(!o||o0&&u.a.createElement("div",{className:"row footer__links"},u.a.createElement("div",{className:"col col--5 footer__col"},u.a.createElement("div",{className:"margin-bottom--md"},u.a.createElement(s.a,{className:"navbar__logo",src:h,alt:"Qovery",width:"150",height:"auto"})),u.a.createElement("div",{className:"margin-bottom--md"},u.a.createElement("p",null,"Qovery is an Internal Developer Platform Helping 50.000+ Developers and Platform Engineers To Ship Faster.")),u.a.createElement("div",null,u.a.createElement("a",{href:"https://github.com/qovery",target:"_blank"},u.a.createElement("i",{className:"feather icon-github",alt:"Qovery's Github Repo"})),"\xa0\xa0\xa0\xa0",u.a.createElement("a",{href:"https://www.linkedin.com/company/qovery/",target:"_blank"},u.a.createElement("i",{className:"feather icon-rss",alt:"Qovery's Linkedin"})),"\xa0\xa0\xa0\xa0",u.a.createElement("a",{href:"https://twitter.com/qovery_",target:"_blank"},u.a.createElement("i",{className:"feather icon-twitter",alt:"Qovery's Twitter"})),"\xa0\xa0\xa0\xa0",u.a.createElement("a",{href:"https://discord.qovery.com",target:"_blank"},u.a.createElement("i",{className:"feather icon-message-circle",alt:"Qovery's Discord"})))),c.map((function(n,t){return u.a.createElement("div",{key:t,className:"col footer__col"},null!=n.title?u.a.createElement("h4",{className:"footer__title"},n.title):null,null!=n.items&&Array.isArray(n.items)&&n.items.length>0?u.a.createElement("ul",{className:"footer__items"},n.items.map((function(n,t){return n.html?u.a.createElement("li",{key:t,className:"footer__item",dangerouslySetInnerHTML:{__html:n.html}}):u.a.createElement("li",{key:n.href||n.to,className:"footer__item"},u.a.createElement(R,n))}))):null)}))),(f||o)&&u.a.createElement("div",{className:"text--center"},f&&f.src&&u.a.createElement("div",{className:"margin-bottom--sm"},f.href?u.a.createElement("a",{href:f.href,target:"_blank",rel:"noopener noreferrer",className:L.a.footerLogoLink},u.a.createElement(z,{alt:f.alt,url:v})):u.a.createElement(z,{alt:f.alt,url:v})),u.a.createElement("small",null,o),u.a.createElement("br",null))))},W=e(462),M=e(463),U=e(3);e(138);t.a=function(n){var t=Object(d.a)().siteConfig,e=void 0===t?{}:t,r=e.favicon,a=(e.tagline,e.title),c=e.themeConfig.image,l=e.url,f=n.children,s=n.title,v=n.noFooter,h=n.description,p=n.image,D=n.keywords,g=(n.permalink,n.version),_=s?s+" | "+a:a,m=p||c,y=l+Object(F.a)(m),b=Object(F.a)(r),E=Object(U.h)(),w=E?"https://docs.qovery.com"+(E.pathname.endsWith("/")?E.pathname:E.pathname+"/"):null;return u.a.createElement(M.a,null,u.a.createElement(W.a,null,u.a.createElement(o.a,null,u.a.createElement("html",{lang:"en"}),u.a.createElement("meta",{httpEquiv:"x-ua-compatible",content:"ie=edge"}),_&&u.a.createElement("title",null,_),_&&u.a.createElement("meta",{property:"og:title",content:_}),r&&u.a.createElement("link",{rel:"shortcut icon",href:b}),h&&u.a.createElement("meta",{name:"description",content:h}),h&&u.a.createElement("meta",{property:"og:description",content:h}),g&&u.a.createElement("meta",{name:"docsearch:version",content:g}),D&&D.length&&u.a.createElement("meta",{name:"keywords",content:D.join(",")}),m&&u.a.createElement("meta",{property:"og:image",content:y}),m&&u.a.createElement("meta",{property:"twitter:image",content:y}),m&&u.a.createElement("meta",{name:"twitter:image:alt",content:"Image for "+_}),w&&u.a.createElement("meta",{property:"og:url",content:w}),u.a.createElement("meta",{name:"twitter:card",content:"summary"}),w&&u.a.createElement("link",{rel:"canonical",href:w})),u.a.createElement(i.a,null),u.a.createElement(B,null),u.a.createElement("div",{className:"main-wrapper"},f),!v&&u.a.createElement(T,null)))}},450:function(n,t,e){"use strict";var r=e(9),u=e(0),i=e.n(u),o=e(423),a=e.n(o),c=e(436),l=(e(139),e(140)),f=e.n(l);t.a=function(n){return function(t){var e,u=t.id,o=Object(r.a)(t,["id"]),l=Object(c.a)().siteConfig,s=(l=void 0===l?{}:l).themeConfig,v=(s=void 0===s?{}:s).navbar,h=(v=void 0===v?{}:v).hideOnScroll,d=void 0!==h&&h;return u?i.a.createElement(n,o,i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:a()("anchor",(e={},e[f.a.enhancedAnchor]=!d,e)),id:u}),i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+u,title:"Direct link to heading"},"#"),o.children):i.a.createElement(n,o)}}},451:function(n,t,e){(function(n,r){var u;(function(){var i="Expected a function",o="__lodash_placeholder__",a=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],c="[object Arguments]",l="[object Array]",f="[object Boolean]",s="[object Date]",v="[object Error]",h="[object Function]",d="[object GeneratorFunction]",p="[object Map]",D="[object Number]",g="[object Object]",_="[object RegExp]",m="[object Set]",y="[object String]",b="[object Symbol]",E="[object WeakMap]",w="[object ArrayBuffer]",F="[object DataView]",C="[object Float32Array]",k="[object Float64Array]",A="[object Int8Array]",x="[object Int16Array]",j="[object Int32Array]",O="[object Uint8Array]",N="[object Uint16Array]",B="[object Uint32Array]",I=/\b__p \+= '';/g,S=/\b(__p \+=) '' \+/g,L=/(__e\(.*?\)|\b__t\)) \+\n'';/g,R=/&(?:amp|lt|gt|quot|#39);/g,z=/[&<>"']/g,T=RegExp(R.source),W=RegExp(z.source),M=/<%-([\s\S]+?)%>/g,U=/<%([\s\S]+?)%>/g,P=/<%=([\s\S]+?)%>/g,$=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,q=/^\w*$/,G=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,V=/[\\^$.*+?()[\]{}|]/g,Z=RegExp(V.source),K=/^\s+|\s+$/g,H=/^\s+/,Q=/\s+$/,J=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Y=/\{\n\/\* \[wrapped with (.+)\] \*/,X=/,? & /,nn=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,tn=/\\(\\)?/g,en=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,rn=/\w*$/,un=/^[-+]0x[0-9a-f]+$/i,on=/^0b[01]+$/i,an=/^\[object .+?Constructor\]$/,cn=/^0o[0-7]+$/i,ln=/^(?:0|[1-9]\d*)$/,fn=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,sn=/($^)/,vn=/['\n\r\u2028\u2029\\]/g,hn="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",dn="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",pn="[\\ud800-\\udfff]",Dn="["+dn+"]",gn="["+hn+"]",_n="\\d+",mn="[\\u2700-\\u27bf]",yn="[a-z\\xdf-\\xf6\\xf8-\\xff]",bn="[^\\ud800-\\udfff"+dn+_n+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",En="\\ud83c[\\udffb-\\udfff]",wn="[^\\ud800-\\udfff]",Fn="(?:\\ud83c[\\udde6-\\uddff]){2}",Cn="[\\ud800-\\udbff][\\udc00-\\udfff]",kn="[A-Z\\xc0-\\xd6\\xd8-\\xde]",An="(?:"+yn+"|"+bn+")",xn="(?:"+kn+"|"+bn+")",jn="(?:"+gn+"|"+En+")"+"?",On="[\\ufe0e\\ufe0f]?"+jn+("(?:\\u200d(?:"+[wn,Fn,Cn].join("|")+")[\\ufe0e\\ufe0f]?"+jn+")*"),Nn="(?:"+[mn,Fn,Cn].join("|")+")"+On,Bn="(?:"+[wn+gn+"?",gn,Fn,Cn,pn].join("|")+")",In=RegExp("['\u2019]","g"),Sn=RegExp(gn,"g"),Ln=RegExp(En+"(?="+En+")|"+Bn+On,"g"),Rn=RegExp([kn+"?"+yn+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?="+[Dn,kn,"$"].join("|")+")",xn+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?="+[Dn,kn+An,"$"].join("|")+")",kn+"?"+An+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?",kn+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",_n,Nn].join("|"),"g"),zn=RegExp("[\\u200d\\ud800-\\udfff"+hn+"\\ufe0e\\ufe0f]"),Tn=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Wn=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Mn=-1,Un={};Un[C]=Un[k]=Un[A]=Un[x]=Un[j]=Un[O]=Un["[object Uint8ClampedArray]"]=Un[N]=Un[B]=!0,Un[c]=Un[l]=Un[w]=Un[f]=Un[F]=Un[s]=Un[v]=Un[h]=Un[p]=Un[D]=Un[g]=Un[_]=Un[m]=Un[y]=Un[E]=!1;var Pn={};Pn[c]=Pn[l]=Pn[w]=Pn[F]=Pn[f]=Pn[s]=Pn[C]=Pn[k]=Pn[A]=Pn[x]=Pn[j]=Pn[p]=Pn[D]=Pn[g]=Pn[_]=Pn[m]=Pn[y]=Pn[b]=Pn[O]=Pn["[object Uint8ClampedArray]"]=Pn[N]=Pn[B]=!0,Pn[v]=Pn[h]=Pn[E]=!1;var $n={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},qn=parseFloat,Gn=parseInt,Vn="object"==typeof n&&n&&n.Object===Object&&n,Zn="object"==typeof self&&self&&self.Object===Object&&self,Kn=Vn||Zn||Function("return this")(),Hn=t&&!t.nodeType&&t,Qn=Hn&&"object"==typeof r&&r&&!r.nodeType&&r,Jn=Qn&&Qn.exports===Hn,Yn=Jn&&Vn.process,Xn=function(){try{var n=Qn&&Qn.require&&Qn.require("util").types;return n||Yn&&Yn.binding&&Yn.binding("util")}catch(t){}}(),nt=Xn&&Xn.isArrayBuffer,tt=Xn&&Xn.isDate,et=Xn&&Xn.isMap,rt=Xn&&Xn.isRegExp,ut=Xn&&Xn.isSet,it=Xn&&Xn.isTypedArray;function ot(n,t,e){switch(e.length){case 0:return n.call(t);case 1:return n.call(t,e[0]);case 2:return n.call(t,e[0],e[1]);case 3:return n.call(t,e[0],e[1],e[2])}return n.apply(t,e)}function at(n,t,e,r){for(var u=-1,i=null==n?0:n.length;++u-1}function ht(n,t,e){for(var r=-1,u=null==n?0:n.length;++r-1;);return e}function Lt(n,t){for(var e=n.length;e--&&Et(t,n[e],0)>-1;);return e}function Rt(n,t){for(var e=n.length,r=0;e--;)n[e]===t&&++r;return r}var zt=At({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),Tt=At({"&":"&","<":"<",">":">",'"':""","'":"'"});function Wt(n){return"\\"+$n[n]}function Mt(n){return zn.test(n)}function Ut(n){var t=-1,e=Array(n.size);return n.forEach((function(n,r){e[++t]=[r,n]})),e}function Pt(n,t){return function(e){return n(t(e))}}function $t(n,t){for(var e=-1,r=n.length,u=0,i=[];++e",""":'"',"'":"'"});var Ht=function n(t){var e,r=(t=null==t?Kn:Ht.defaults(Kn.Object(),t,Ht.pick(Kn,Wn))).Array,u=t.Date,hn=t.Error,dn=t.Function,pn=t.Math,Dn=t.Object,gn=t.RegExp,_n=t.String,mn=t.TypeError,yn=r.prototype,bn=dn.prototype,En=Dn.prototype,wn=t["__core-js_shared__"],Fn=bn.toString,Cn=En.hasOwnProperty,kn=0,An=(e=/[^.]+$/.exec(wn&&wn.keys&&wn.keys.IE_PROTO||""))?"Symbol(src)_1."+e:"",xn=En.toString,jn=Fn.call(Dn),On=Kn._,Nn=gn("^"+Fn.call(Cn).replace(V,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Bn=Jn?t.Buffer:void 0,Ln=t.Symbol,zn=t.Uint8Array,$n=Bn?Bn.allocUnsafe:void 0,Vn=Pt(Dn.getPrototypeOf,Dn),Zn=Dn.create,Hn=En.propertyIsEnumerable,Qn=yn.splice,Yn=Ln?Ln.isConcatSpreadable:void 0,Xn=Ln?Ln.iterator:void 0,mt=Ln?Ln.toStringTag:void 0,At=function(){try{var n=Xu(Dn,"defineProperty");return n({},"",{}),n}catch(t){}}(),Qt=t.clearTimeout!==Kn.clearTimeout&&t.clearTimeout,Jt=u&&u.now!==Kn.Date.now&&u.now,Yt=t.setTimeout!==Kn.setTimeout&&t.setTimeout,Xt=pn.ceil,ne=pn.floor,te=Dn.getOwnPropertySymbols,ee=Bn?Bn.isBuffer:void 0,re=t.isFinite,ue=yn.join,ie=Pt(Dn.keys,Dn),oe=pn.max,ae=pn.min,ce=u.now,le=t.parseInt,fe=pn.random,se=yn.reverse,ve=Xu(t,"DataView"),he=Xu(t,"Map"),de=Xu(t,"Promise"),pe=Xu(t,"Set"),De=Xu(t,"WeakMap"),ge=Xu(Dn,"create"),_e=De&&new De,me={},ye=ki(ve),be=ki(he),Ee=ki(de),we=ki(pe),Fe=ki(De),Ce=Ln?Ln.prototype:void 0,ke=Ce?Ce.valueOf:void 0,Ae=Ce?Ce.toString:void 0;function xe(n){if(qo(n)&&!Io(n)&&!(n instanceof Be)){if(n instanceof Ne)return n;if(Cn.call(n,"__wrapped__"))return Ai(n)}return new Ne(n)}var je=function(){function n(){}return function(t){if(!$o(t))return{};if(Zn)return Zn(t);n.prototype=t;var e=new n;return n.prototype=void 0,e}}();function Oe(){}function Ne(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=void 0}function Be(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Ie(n){var t=-1,e=null==n?0:n.length;for(this.clear();++t=t?n:t)),n}function Qe(n,t,e,r,u,i){var o,a=1&t,l=2&t,v=4&t;if(e&&(o=u?e(n,r,u,i):e(n)),void 0!==o)return o;if(!$o(n))return n;var E=Io(n);if(E){if(o=function(n){var t=n.length,e=new n.constructor(t);t&&"string"==typeof n[0]&&Cn.call(n,"index")&&(e.index=n.index,e.input=n.input);return e}(n),!a)return gu(n,o)}else{var I=ei(n),S=I==h||I==d;if(zo(n))return su(n,a);if(I==g||I==c||S&&!u){if(o=l||S?{}:ui(n),!a)return l?function(n,t){return _u(n,ti(n),t)}(n,function(n,t){return n&&_u(t,ba(t),n)}(o,n)):function(n,t){return _u(n,ni(n),t)}(n,Ve(o,n))}else{if(!Pn[I])return u?n:{};o=function(n,t,e){var r=n.constructor;switch(t){case w:return vu(n);case f:case s:return new r(+n);case F:return function(n,t){var e=t?vu(n.buffer):n.buffer;return new n.constructor(e,n.byteOffset,n.byteLength)}(n,e);case C:case k:case A:case x:case j:case O:case"[object Uint8ClampedArray]":case N:case B:return hu(n,e);case p:return new r;case D:case y:return new r(n);case _:return function(n){var t=new n.constructor(n.source,rn.exec(n));return t.lastIndex=n.lastIndex,t}(n);case m:return new r;case b:return u=n,ke?Dn(ke.call(u)):{}}var u}(n,I,a)}}i||(i=new ze);var L=i.get(n);if(L)return L;i.set(n,o),Ho(n)?n.forEach((function(r){o.add(Qe(r,t,e,r,n,i))})):Go(n)&&n.forEach((function(r,u){o.set(u,Qe(r,t,e,u,n,i))}));var R=E?void 0:(v?l?Vu:Gu:l?ba:ya)(n);return ct(R||n,(function(r,u){R&&(r=n[u=r]),$e(o,u,Qe(r,t,e,u,n,i))})),o}function Je(n,t,e){var r=e.length;if(null==n)return!r;for(n=Dn(n);r--;){var u=e[r],i=t[u],o=n[u];if(void 0===o&&!(u in n)||!i(o))return!1}return!0}function Ye(n,t,e){if("function"!=typeof n)throw new mn(i);return mi((function(){n.apply(void 0,e)}),t)}function Xe(n,t,e,r){var u=-1,i=vt,o=!0,a=n.length,c=[],l=t.length;if(!a)return c;e&&(t=dt(t,Nt(e))),r?(i=ht,o=!1):t.length>=200&&(i=It,o=!1,t=new Re(t));n:for(;++u-1},Se.prototype.set=function(n,t){var e=this.__data__,r=qe(e,n);return r<0?(++this.size,e.push([n,t])):e[r][1]=t,this},Le.prototype.clear=function(){this.size=0,this.__data__={hash:new Ie,map:new(he||Se),string:new Ie}},Le.prototype.delete=function(n){var t=Ju(this,n).delete(n);return this.size-=t?1:0,t},Le.prototype.get=function(n){return Ju(this,n).get(n)},Le.prototype.has=function(n){return Ju(this,n).has(n)},Le.prototype.set=function(n,t){var e=Ju(this,n),r=e.size;return e.set(n,t),this.size+=e.size==r?0:1,this},Re.prototype.add=Re.prototype.push=function(n){return this.__data__.set(n,"__lodash_hash_undefined__"),this},Re.prototype.has=function(n){return this.__data__.has(n)},ze.prototype.clear=function(){this.__data__=new Se,this.size=0},ze.prototype.delete=function(n){var t=this.__data__,e=t.delete(n);return this.size=t.size,e},ze.prototype.get=function(n){return this.__data__.get(n)},ze.prototype.has=function(n){return this.__data__.has(n)},ze.prototype.set=function(n,t){var e=this.__data__;if(e instanceof Se){var r=e.__data__;if(!he||r.length<199)return r.push([n,t]),this.size=++e.size,this;e=this.__data__=new Le(r)}return e.set(n,t),this.size=e.size,this};var nr=bu(cr),tr=bu(lr,!0);function er(n,t){var e=!0;return nr(n,(function(n,r,u){return e=!!t(n,r,u)})),e}function rr(n,t,e){for(var r=-1,u=n.length;++r0&&e(a)?t>1?ir(a,t-1,e,r,u):pt(u,a):r||(u[u.length]=a)}return u}var or=Eu(),ar=Eu(!0);function cr(n,t){return n&&or(n,t,ya)}function lr(n,t){return n&&ar(n,t,ya)}function fr(n,t){return st(t,(function(t){return Mo(n[t])}))}function sr(n,t){for(var e=0,r=(t=au(t,n)).length;null!=n&&et}function pr(n,t){return null!=n&&Cn.call(n,t)}function Dr(n,t){return null!=n&&t in Dn(n)}function gr(n,t,e){for(var u=e?ht:vt,i=n[0].length,o=n.length,a=o,c=r(o),l=1/0,f=[];a--;){var s=n[a];a&&t&&(s=dt(s,Nt(t))),l=ae(s.length,l),c[a]=!e&&(t||i>=120&&s.length>=120)?new Re(a&&s):void 0}s=n[0];var v=-1,h=c[0];n:for(;++v=a)return c;var l=e[r];return c*("desc"==l?-1:1)}}return n.index-t.index}(n,t,e)}))}function Ir(n,t,e){for(var r=-1,u=t.length,i={};++r-1;)a!==n&&Qn.call(a,c,1),Qn.call(n,c,1);return n}function Lr(n,t){for(var e=n?t.length:0,r=e-1;e--;){var u=t[e];if(e==r||u!==i){var i=u;oi(u)?Qn.call(n,u,1):Xr(n,u)}}return n}function Rr(n,t){return n+ne(fe()*(t-n+1))}function zr(n,t){var e="";if(!n||t<1||t>9007199254740991)return e;do{t%2&&(e+=n),(t=ne(t/2))&&(n+=n)}while(t);return e}function Tr(n,t){return yi(di(n,t,Va),n+"")}function Wr(n){return We(ja(n))}function Mr(n,t){var e=ja(n);return wi(e,He(t,0,e.length))}function Ur(n,t,e,r){if(!$o(n))return n;for(var u=-1,i=(t=au(t,n)).length,o=i-1,a=n;null!=a&&++ui?0:i+t),(e=e>i?i:e)<0&&(e+=i),i=t>e?0:e-t>>>0,t>>>=0;for(var o=r(i);++u>>1,o=n[i];null!==o&&!Jo(o)&&(e?o<=t:o=200){var l=t?null:zu(n);if(l)return qt(l);o=!1,u=It,c=new Re}else c=t?[]:a;n:for(;++r=r?n:Gr(n,t,e)}var fu=Qt||function(n){return Kn.clearTimeout(n)};function su(n,t){if(t)return n.slice();var e=n.length,r=$n?$n(e):new n.constructor(e);return n.copy(r),r}function vu(n){var t=new n.constructor(n.byteLength);return new zn(t).set(new zn(n)),t}function hu(n,t){var e=t?vu(n.buffer):n.buffer;return new n.constructor(e,n.byteOffset,n.length)}function du(n,t){if(n!==t){var e=void 0!==n,r=null===n,u=n==n,i=Jo(n),o=void 0!==t,a=null===t,c=t==t,l=Jo(t);if(!a&&!l&&!i&&n>t||i&&o&&c&&!a&&!l||r&&o&&c||!e&&c||!u)return 1;if(!r&&!i&&!l&&n1?e[u-1]:void 0,o=u>2?e[2]:void 0;for(i=n.length>3&&"function"==typeof i?(u--,i):void 0,o&&ai(e[0],e[1],o)&&(i=u<3?void 0:i,u=1),t=Dn(t);++r-1?u[i?t[o]:o]:void 0}}function Au(n){return qu((function(t){var e=t.length,r=e,u=Ne.prototype.thru;for(n&&t.reverse();r--;){var o=t[r];if("function"!=typeof o)throw new mn(i);if(u&&!a&&"wrapper"==Ku(o))var a=new Ne([],!0)}for(r=a?r:e;++r1&&m.reverse(),s&&l<_&&(m.length=l),this&&this!==Kn&&this instanceof g&&(C=D||Cu(C)),C.apply(F,m)}}function ju(n,t){return function(e,r){return function(n,t,e,r){return cr(n,(function(n,u,i){t(r,e(n),u,i)})),r}(e,n,t(r),{})}}function Ou(n,t){return function(e,r){var u;if(void 0===e&&void 0===r)return t;if(void 0!==e&&(u=e),void 0!==r){if(void 0===u)return r;"string"==typeof e||"string"==typeof r?(e=Jr(e),r=Jr(r)):(e=Qr(e),r=Qr(r)),u=n(e,r)}return u}}function Nu(n){return qu((function(t){return t=dt(t,Nt(Qu())),Tr((function(e){var r=this;return n(t,(function(n){return ot(n,r,e)}))}))}))}function Bu(n,t){var e=(t=void 0===t?" ":Jr(t)).length;if(e<2)return e?zr(t,n):t;var r=zr(t,Xt(n/Vt(t)));return Mt(t)?lu(Zt(r),0,n).join(""):r.slice(0,n)}function Iu(n){return function(t,e,u){return u&&"number"!=typeof u&&ai(t,e,u)&&(e=u=void 0),t=ea(t),void 0===e?(e=t,t=0):e=ea(e),function(n,t,e,u){for(var i=-1,o=oe(Xt((t-n)/(e||1)),0),a=r(o);o--;)a[u?o:++i]=n,n+=e;return a}(t,e,u=void 0===u?ta))return!1;var l=i.get(n);if(l&&i.get(t))return l==t;var f=-1,s=!0,v=2&e?new Re:void 0;for(i.set(n,t),i.set(t,n);++f-1&&n%1==0&&n1?"& ":"")+t[r],t=t.join(e>2?", ":" "),n.replace(J,"{\n/* [wrapped with "+t+"] */\n")}(r,function(n,t){return ct(a,(function(e){var r="_."+e[0];t&e[1]&&!vt(n,r)&&n.push(r)})),n.sort()}(function(n){var t=n.match(Y);return t?t[1].split(X):[]}(r),e)))}function Ei(n){var t=0,e=0;return function(){var r=ce(),u=16-(r-e);if(e=r,u>0){if(++t>=800)return arguments[0]}else t=0;return n.apply(void 0,arguments)}}function wi(n,t){var e=-1,r=n.length,u=r-1;for(t=void 0===t?r:t;++e1?n[t-1]:void 0;return e="function"==typeof e?(n.pop(),e):void 0,Zi(n,e)}));function no(n){var t=xe(n);return t.__chain__=!0,t}function to(n,t){return t(n)}var eo=qu((function(n){var t=n.length,e=t?n[0]:0,r=this.__wrapped__,u=function(t){return Ke(t,n)};return!(t>1||this.__actions__.length)&&r instanceof Be&&oi(e)?((r=r.slice(e,+e+(t?1:0))).__actions__.push({func:to,args:[u],thisArg:void 0}),new Ne(r,this.__chain__).thru((function(n){return t&&!n.length&&n.push(void 0),n}))):this.thru(u)}));var ro=mu((function(n,t,e){Cn.call(n,e)?++n[e]:Ze(n,e,1)}));var uo=ku(Ni),io=ku(Bi);function oo(n,t){return(Io(n)?ct:nr)(n,Qu(t,3))}function ao(n,t){return(Io(n)?lt:tr)(n,Qu(t,3))}var co=mu((function(n,t,e){Cn.call(n,e)?n[e].push(t):Ze(n,e,[t])}));var lo=Tr((function(n,t,e){var u=-1,i="function"==typeof t,o=Lo(n)?r(n.length):[];return nr(n,(function(n){o[++u]=i?ot(t,n,e):_r(n,t,e)})),o})),fo=mu((function(n,t,e){Ze(n,e,t)}));function so(n,t){return(Io(n)?dt:Ar)(n,Qu(t,3))}var vo=mu((function(n,t,e){n[e?0:1].push(t)}),(function(){return[[],[]]}));var ho=Tr((function(n,t){if(null==n)return[];var e=t.length;return e>1&&ai(n,t[0],t[1])?t=[]:e>2&&ai(t[0],t[1],t[2])&&(t=[t[0]]),Br(n,ir(t,1),[])})),po=Jt||function(){return Kn.Date.now()};function Do(n,t,e){return t=e?void 0:t,Wu(n,128,void 0,void 0,void 0,void 0,t=n&&null==t?n.length:t)}function go(n,t){var e;if("function"!=typeof t)throw new mn(i);return n=ra(n),function(){return--n>0&&(e=t.apply(this,arguments)),n<=1&&(t=void 0),e}}var _o=Tr((function(n,t,e){var r=1;if(e.length){var u=$t(e,Hu(_o));r|=32}return Wu(n,r,t,e,u)})),mo=Tr((function(n,t,e){var r=3;if(e.length){var u=$t(e,Hu(mo));r|=32}return Wu(t,r,n,e,u)}));function yo(n,t,e){var r,u,o,a,c,l,f=0,s=!1,v=!1,h=!0;if("function"!=typeof n)throw new mn(i);function d(t){var e=r,i=u;return r=u=void 0,f=t,a=n.apply(i,e)}function p(n){return f=n,c=mi(g,t),s?d(n):a}function D(n){var e=n-l;return void 0===l||e>=t||e<0||v&&n-f>=o}function g(){var n=po();if(D(n))return _(n);c=mi(g,function(n){var e=t-(n-l);return v?ae(e,o-(n-f)):e}(n))}function _(n){return c=void 0,h&&r?d(n):(r=u=void 0,a)}function m(){var n=po(),e=D(n);if(r=arguments,u=this,l=n,e){if(void 0===c)return p(l);if(v)return fu(c),c=mi(g,t),d(l)}return void 0===c&&(c=mi(g,t)),a}return t=ia(t)||0,$o(e)&&(s=!!e.leading,o=(v="maxWait"in e)?oe(ia(e.maxWait)||0,t):o,h="trailing"in e?!!e.trailing:h),m.cancel=function(){void 0!==c&&fu(c),f=0,r=l=u=c=void 0},m.flush=function(){return void 0===c?a:_(po())},m}var bo=Tr((function(n,t){return Ye(n,1,t)})),Eo=Tr((function(n,t,e){return Ye(n,ia(t)||0,e)}));function wo(n,t){if("function"!=typeof n||null!=t&&"function"!=typeof t)throw new mn(i);var e=function(){var r=arguments,u=t?t.apply(this,r):r[0],i=e.cache;if(i.has(u))return i.get(u);var o=n.apply(this,r);return e.cache=i.set(u,o)||i,o};return e.cache=new(wo.Cache||Le),e}function Fo(n){if("function"!=typeof n)throw new mn(i);return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}wo.Cache=Le;var Co=cu((function(n,t){var e=(t=1==t.length&&Io(t[0])?dt(t[0],Nt(Qu())):dt(ir(t,1),Nt(Qu()))).length;return Tr((function(r){for(var u=-1,i=ae(r.length,e);++u=t})),Bo=mr(function(){return arguments}())?mr:function(n){return qo(n)&&Cn.call(n,"callee")&&!Hn.call(n,"callee")},Io=r.isArray,So=nt?Nt(nt):function(n){return qo(n)&&hr(n)==w};function Lo(n){return null!=n&&Po(n.length)&&!Mo(n)}function Ro(n){return qo(n)&&Lo(n)}var zo=ee||ic,To=tt?Nt(tt):function(n){return qo(n)&&hr(n)==s};function Wo(n){if(!qo(n))return!1;var t=hr(n);return t==v||"[object DOMException]"==t||"string"==typeof n.message&&"string"==typeof n.name&&!Zo(n)}function Mo(n){if(!$o(n))return!1;var t=hr(n);return t==h||t==d||"[object AsyncFunction]"==t||"[object Proxy]"==t}function Uo(n){return"number"==typeof n&&n==ra(n)}function Po(n){return"number"==typeof n&&n>-1&&n%1==0&&n<=9007199254740991}function $o(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function qo(n){return null!=n&&"object"==typeof n}var Go=et?Nt(et):function(n){return qo(n)&&ei(n)==p};function Vo(n){return"number"==typeof n||qo(n)&&hr(n)==D}function Zo(n){if(!qo(n)||hr(n)!=g)return!1;var t=Vn(n);if(null===t)return!0;var e=Cn.call(t,"constructor")&&t.constructor;return"function"==typeof e&&e instanceof e&&Fn.call(e)==jn}var Ko=rt?Nt(rt):function(n){return qo(n)&&hr(n)==_};var Ho=ut?Nt(ut):function(n){return qo(n)&&ei(n)==m};function Qo(n){return"string"==typeof n||!Io(n)&&qo(n)&&hr(n)==y}function Jo(n){return"symbol"==typeof n||qo(n)&&hr(n)==b}var Yo=it?Nt(it):function(n){return qo(n)&&Po(n.length)&&!!Un[hr(n)]};var Xo=Su(kr),na=Su((function(n,t){return n<=t}));function ta(n){if(!n)return[];if(Lo(n))return Qo(n)?Zt(n):gu(n);if(Xn&&n[Xn])return function(n){for(var t,e=[];!(t=n.next()).done;)e.push(t.value);return e}(n[Xn]());var t=ei(n);return(t==p?Ut:t==m?qt:ja)(n)}function ea(n){return n?(n=ia(n))===1/0||n===-1/0?17976931348623157e292*(n<0?-1:1):n==n?n:0:0===n?n:0}function ra(n){var t=ea(n),e=t%1;return t==t?e?t-e:t:0}function ua(n){return n?He(ra(n),0,4294967295):0}function ia(n){if("number"==typeof n)return n;if(Jo(n))return NaN;if($o(n)){var t="function"==typeof n.valueOf?n.valueOf():n;n=$o(t)?t+"":t}if("string"!=typeof n)return 0===n?n:+n;n=n.replace(K,"");var e=on.test(n);return e||cn.test(n)?Gn(n.slice(2),e?2:8):un.test(n)?NaN:+n}function oa(n){return _u(n,ba(n))}function aa(n){return null==n?"":Jr(n)}var ca=yu((function(n,t){if(si(t)||Lo(t))_u(t,ya(t),n);else for(var e in t)Cn.call(t,e)&&$e(n,e,t[e])})),la=yu((function(n,t){_u(t,ba(t),n)})),fa=yu((function(n,t,e,r){_u(t,ba(t),n,r)})),sa=yu((function(n,t,e,r){_u(t,ya(t),n,r)})),va=qu(Ke);var ha=Tr((function(n,t){n=Dn(n);var e=-1,r=t.length,u=r>2?t[2]:void 0;for(u&&ai(t[0],t[1],u)&&(r=1);++e1),t})),_u(n,Vu(n),e),r&&(e=Qe(e,7,Pu));for(var u=t.length;u--;)Xr(e,t[u]);return e}));var Ca=qu((function(n,t){return null==n?{}:function(n,t){return Ir(n,t,(function(t,e){return Da(n,e)}))}(n,t)}));function ka(n,t){if(null==n)return{};var e=dt(Vu(n),(function(n){return[n]}));return t=Qu(t),Ir(n,e,(function(n,e){return t(n,e[0])}))}var Aa=Tu(ya),xa=Tu(ba);function ja(n){return null==n?[]:Bt(n,ya(n))}var Oa=Fu((function(n,t,e){return t=t.toLowerCase(),n+(e?Na(t):t)}));function Na(n){return Wa(aa(n).toLowerCase())}function Ba(n){return(n=aa(n))&&n.replace(fn,zt).replace(Sn,"")}var Ia=Fu((function(n,t,e){return n+(e?"-":"")+t.toLowerCase()})),Sa=Fu((function(n,t,e){return n+(e?" ":"")+t.toLowerCase()})),La=wu("toLowerCase");var Ra=Fu((function(n,t,e){return n+(e?"_":"")+t.toLowerCase()}));var za=Fu((function(n,t,e){return n+(e?" ":"")+Wa(t)}));var Ta=Fu((function(n,t,e){return n+(e?" ":"")+t.toUpperCase()})),Wa=wu("toUpperCase");function Ma(n,t,e){return n=aa(n),void 0===(t=e?void 0:t)?function(n){return Tn.test(n)}(n)?function(n){return n.match(Rn)||[]}(n):function(n){return n.match(nn)||[]}(n):n.match(t)||[]}var Ua=Tr((function(n,t){try{return ot(n,void 0,t)}catch(e){return Wo(e)?e:new hn(e)}})),Pa=qu((function(n,t){return ct(t,(function(t){t=Ci(t),Ze(n,t,_o(n[t],n))})),n}));function $a(n){return function(){return n}}var qa=Au(),Ga=Au(!0);function Va(n){return n}function Za(n){return wr("function"==typeof n?n:Qe(n,1))}var Ka=Tr((function(n,t){return function(e){return _r(e,n,t)}})),Ha=Tr((function(n,t){return function(e){return _r(n,e,t)}}));function Qa(n,t,e){var r=ya(t),u=fr(t,r);null!=e||$o(t)&&(u.length||!r.length)||(e=t,t=n,n=this,u=fr(t,ya(t)));var i=!($o(e)&&"chain"in e&&!e.chain),o=Mo(n);return ct(u,(function(e){var r=t[e];n[e]=r,o&&(n.prototype[e]=function(){var t=this.__chain__;if(i||t){var e=n(this.__wrapped__),u=e.__actions__=gu(this.__actions__);return u.push({func:r,args:arguments,thisArg:n}),e.__chain__=t,e}return r.apply(n,pt([this.value()],arguments))})})),n}function Ja(){}var Ya=Nu(dt),Xa=Nu(ft),nc=Nu(_t);function tc(n){return ci(n)?kt(Ci(n)):function(n){return function(t){return sr(t,n)}}(n)}var ec=Iu(),rc=Iu(!0);function uc(){return[]}function ic(){return!1}var oc=Ou((function(n,t){return n+t}),0),ac=Ru("ceil"),cc=Ou((function(n,t){return n/t}),1),lc=Ru("floor");var fc,sc=Ou((function(n,t){return n*t}),1),vc=Ru("round"),hc=Ou((function(n,t){return n-t}),0);return xe.after=function(n,t){if("function"!=typeof t)throw new mn(i);return n=ra(n),function(){if(--n<1)return t.apply(this,arguments)}},xe.ary=Do,xe.assign=ca,xe.assignIn=la,xe.assignInWith=fa,xe.assignWith=sa,xe.at=va,xe.before=go,xe.bind=_o,xe.bindAll=Pa,xe.bindKey=mo,xe.castArray=function(){if(!arguments.length)return[];var n=arguments[0];return Io(n)?n:[n]},xe.chain=no,xe.chunk=function(n,t,e){t=(e?ai(n,t,e):void 0===t)?1:oe(ra(t),0);var u=null==n?0:n.length;if(!u||t<1)return[];for(var i=0,o=0,a=r(Xt(u/t));iu?0:u+e),(r=void 0===r||r>u?u:ra(r))<0&&(r+=u),r=e>r?0:ua(r);e>>0)?(n=aa(n))&&("string"==typeof t||null!=t&&!Ko(t))&&!(t=Jr(t))&&Mt(n)?lu(Zt(n),0,e):n.split(t,e):[]},xe.spread=function(n,t){if("function"!=typeof n)throw new mn(i);return t=null==t?0:oe(ra(t),0),Tr((function(e){var r=e[t],u=lu(e,0,t);return r&&pt(u,r),ot(n,this,u)}))},xe.tail=function(n){var t=null==n?0:n.length;return t?Gr(n,1,t):[]},xe.take=function(n,t,e){return n&&n.length?Gr(n,0,(t=e||void 0===t?1:ra(t))<0?0:t):[]},xe.takeRight=function(n,t,e){var r=null==n?0:n.length;return r?Gr(n,(t=r-(t=e||void 0===t?1:ra(t)))<0?0:t,r):[]},xe.takeRightWhile=function(n,t){return n&&n.length?tu(n,Qu(t,3),!1,!0):[]},xe.takeWhile=function(n,t){return n&&n.length?tu(n,Qu(t,3)):[]},xe.tap=function(n,t){return t(n),n},xe.throttle=function(n,t,e){var r=!0,u=!0;if("function"!=typeof n)throw new mn(i);return $o(e)&&(r="leading"in e?!!e.leading:r,u="trailing"in e?!!e.trailing:u),yo(n,t,{leading:r,maxWait:t,trailing:u})},xe.thru=to,xe.toArray=ta,xe.toPairs=Aa,xe.toPairsIn=xa,xe.toPath=function(n){return Io(n)?dt(n,Ci):Jo(n)?[n]:gu(Fi(aa(n)))},xe.toPlainObject=oa,xe.transform=function(n,t,e){var r=Io(n),u=r||zo(n)||Yo(n);if(t=Qu(t,4),null==e){var i=n&&n.constructor;e=u?r?new i:[]:$o(n)&&Mo(i)?je(Vn(n)):{}}return(u?ct:cr)(n,(function(n,r,u){return t(e,n,r,u)})),e},xe.unary=function(n){return Do(n,1)},xe.union=$i,xe.unionBy=qi,xe.unionWith=Gi,xe.uniq=function(n){return n&&n.length?Yr(n):[]},xe.uniqBy=function(n,t){return n&&n.length?Yr(n,Qu(t,2)):[]},xe.uniqWith=function(n,t){return t="function"==typeof t?t:void 0,n&&n.length?Yr(n,void 0,t):[]},xe.unset=function(n,t){return null==n||Xr(n,t)},xe.unzip=Vi,xe.unzipWith=Zi,xe.update=function(n,t,e){return null==n?n:nu(n,t,ou(e))},xe.updateWith=function(n,t,e,r){return r="function"==typeof r?r:void 0,null==n?n:nu(n,t,ou(e),r)},xe.values=ja,xe.valuesIn=function(n){return null==n?[]:Bt(n,ba(n))},xe.without=Ki,xe.words=Ma,xe.wrap=function(n,t){return ko(ou(t),n)},xe.xor=Hi,xe.xorBy=Qi,xe.xorWith=Ji,xe.zip=Yi,xe.zipObject=function(n,t){return uu(n||[],t||[],$e)},xe.zipObjectDeep=function(n,t){return uu(n||[],t||[],Ur)},xe.zipWith=Xi,xe.entries=Aa,xe.entriesIn=xa,xe.extend=la,xe.extendWith=fa,Qa(xe,xe),xe.add=oc,xe.attempt=Ua,xe.camelCase=Oa,xe.capitalize=Na,xe.ceil=ac,xe.clamp=function(n,t,e){return void 0===e&&(e=t,t=void 0),void 0!==e&&(e=(e=ia(e))==e?e:0),void 0!==t&&(t=(t=ia(t))==t?t:0),He(ia(n),t,e)},xe.clone=function(n){return Qe(n,4)},xe.cloneDeep=function(n){return Qe(n,5)},xe.cloneDeepWith=function(n,t){return Qe(n,5,t="function"==typeof t?t:void 0)},xe.cloneWith=function(n,t){return Qe(n,4,t="function"==typeof t?t:void 0)},xe.conformsTo=function(n,t){return null==t||Je(n,t,ya(t))},xe.deburr=Ba,xe.defaultTo=function(n,t){return null==n||n!=n?t:n},xe.divide=cc,xe.endsWith=function(n,t,e){n=aa(n),t=Jr(t);var r=n.length,u=e=void 0===e?r:He(ra(e),0,r);return(e-=t.length)>=0&&n.slice(e,u)==t},xe.eq=jo,xe.escape=function(n){return(n=aa(n))&&W.test(n)?n.replace(z,Tt):n},xe.escapeRegExp=function(n){return(n=aa(n))&&Z.test(n)?n.replace(V,"\\$&"):n},xe.every=function(n,t,e){var r=Io(n)?ft:er;return e&&ai(n,t,e)&&(t=void 0),r(n,Qu(t,3))},xe.find=uo,xe.findIndex=Ni,xe.findKey=function(n,t){return yt(n,Qu(t,3),cr)},xe.findLast=io,xe.findLastIndex=Bi,xe.findLastKey=function(n,t){return yt(n,Qu(t,3),lr)},xe.floor=lc,xe.forEach=oo,xe.forEachRight=ao,xe.forIn=function(n,t){return null==n?n:or(n,Qu(t,3),ba)},xe.forInRight=function(n,t){return null==n?n:ar(n,Qu(t,3),ba)},xe.forOwn=function(n,t){return n&&cr(n,Qu(t,3))},xe.forOwnRight=function(n,t){return n&&lr(n,Qu(t,3))},xe.get=pa,xe.gt=Oo,xe.gte=No,xe.has=function(n,t){return null!=n&&ri(n,t,pr)},xe.hasIn=Da,xe.head=Si,xe.identity=Va,xe.includes=function(n,t,e,r){n=Lo(n)?n:ja(n),e=e&&!r?ra(e):0;var u=n.length;return e<0&&(e=oe(u+e,0)),Qo(n)?e<=u&&n.indexOf(t,e)>-1:!!u&&Et(n,t,e)>-1},xe.indexOf=function(n,t,e){var r=null==n?0:n.length;if(!r)return-1;var u=null==e?0:ra(e);return u<0&&(u=oe(r+u,0)),Et(n,t,u)},xe.inRange=function(n,t,e){return t=ea(t),void 0===e?(e=t,t=0):e=ea(e),function(n,t,e){return n>=ae(t,e)&&n=-9007199254740991&&n<=9007199254740991},xe.isSet=Ho,xe.isString=Qo,xe.isSymbol=Jo,xe.isTypedArray=Yo,xe.isUndefined=function(n){return void 0===n},xe.isWeakMap=function(n){return qo(n)&&ei(n)==E},xe.isWeakSet=function(n){return qo(n)&&"[object WeakSet]"==hr(n)},xe.join=function(n,t){return null==n?"":ue.call(n,t)},xe.kebabCase=Ia,xe.last=Ti,xe.lastIndexOf=function(n,t,e){var r=null==n?0:n.length;if(!r)return-1;var u=r;return void 0!==e&&(u=(u=ra(e))<0?oe(r+u,0):ae(u,r-1)),t==t?function(n,t,e){for(var r=e+1;r--;)if(n[r]===t)return r;return r}(n,t,u):bt(n,Ft,u,!0)},xe.lowerCase=Sa,xe.lowerFirst=La,xe.lt=Xo,xe.lte=na,xe.max=function(n){return n&&n.length?rr(n,Va,dr):void 0},xe.maxBy=function(n,t){return n&&n.length?rr(n,Qu(t,2),dr):void 0},xe.mean=function(n){return Ct(n,Va)},xe.meanBy=function(n,t){return Ct(n,Qu(t,2))},xe.min=function(n){return n&&n.length?rr(n,Va,kr):void 0},xe.minBy=function(n,t){return n&&n.length?rr(n,Qu(t,2),kr):void 0},xe.stubArray=uc,xe.stubFalse=ic,xe.stubObject=function(){return{}},xe.stubString=function(){return""},xe.stubTrue=function(){return!0},xe.multiply=sc,xe.nth=function(n,t){return n&&n.length?Nr(n,ra(t)):void 0},xe.noConflict=function(){return Kn._===this&&(Kn._=On),this},xe.noop=Ja,xe.now=po,xe.pad=function(n,t,e){n=aa(n);var r=(t=ra(t))?Vt(n):0;if(!t||r>=t)return n;var u=(t-r)/2;return Bu(ne(u),e)+n+Bu(Xt(u),e)},xe.padEnd=function(n,t,e){n=aa(n);var r=(t=ra(t))?Vt(n):0;return t&&rt){var r=n;n=t,t=r}if(e||n%1||t%1){var u=fe();return ae(n+u*(t-n+qn("1e-"+((u+"").length-1))),t)}return Rr(n,t)},xe.reduce=function(n,t,e){var r=Io(n)?Dt:xt,u=arguments.length<3;return r(n,Qu(t,4),e,u,nr)},xe.reduceRight=function(n,t,e){var r=Io(n)?gt:xt,u=arguments.length<3;return r(n,Qu(t,4),e,u,tr)},xe.repeat=function(n,t,e){return t=(e?ai(n,t,e):void 0===t)?1:ra(t),zr(aa(n),t)},xe.replace=function(){var n=arguments,t=aa(n[0]);return n.length<3?t:t.replace(n[1],n[2])},xe.result=function(n,t,e){var r=-1,u=(t=au(t,n)).length;for(u||(u=1,n=void 0);++r9007199254740991)return[];var e=4294967295,r=ae(n,4294967295);n-=4294967295;for(var u=Ot(r,t=Qu(t));++e=i)return n;var a=e-Vt(r);if(a<1)return r;var c=o?lu(o,0,a).join(""):n.slice(0,a);if(void 0===u)return c+r;if(o&&(a+=c.length-a),Ko(u)){if(n.slice(a).search(u)){var l,f=c;for(u.global||(u=gn(u.source,aa(rn.exec(u))+"g")),u.lastIndex=0;l=u.exec(f);)var s=l.index;c=c.slice(0,void 0===s?a:s)}}else if(n.indexOf(Jr(u),a)!=a){var v=c.lastIndexOf(u);v>-1&&(c=c.slice(0,v))}return c+r},xe.unescape=function(n){return(n=aa(n))&&T.test(n)?n.replace(R,Kt):n},xe.uniqueId=function(n){var t=++kn;return aa(n)+t},xe.upperCase=Ta,xe.upperFirst=Wa,xe.each=oo,xe.eachRight=ao,xe.first=Si,Qa(xe,(fc={},cr(xe,(function(n,t){Cn.call(xe.prototype,t)||(fc[t]=n)})),fc),{chain:!1}),xe.VERSION="4.17.15",ct(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(n){xe[n].placeholder=xe})),ct(["drop","take"],(function(n,t){Be.prototype[n]=function(e){e=void 0===e?1:oe(ra(e),0);var r=this.__filtered__&&!t?new Be(this):this.clone();return r.__filtered__?r.__takeCount__=ae(e,r.__takeCount__):r.__views__.push({size:ae(e,4294967295),type:n+(r.__dir__<0?"Right":"")}),r},Be.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}})),ct(["filter","map","takeWhile"],(function(n,t){var e=t+1,r=1==e||3==e;Be.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:Qu(n,3),type:e}),t.__filtered__=t.__filtered__||r,t}})),ct(["head","last"],(function(n,t){var e="take"+(t?"Right":"");Be.prototype[n]=function(){return this[e](1).value()[0]}})),ct(["initial","tail"],(function(n,t){var e="drop"+(t?"":"Right");Be.prototype[n]=function(){return this.__filtered__?new Be(this):this[e](1)}})),Be.prototype.compact=function(){return this.filter(Va)},Be.prototype.find=function(n){return this.filter(n).head()},Be.prototype.findLast=function(n){return this.reverse().find(n)},Be.prototype.invokeMap=Tr((function(n,t){return"function"==typeof n?new Be(this):this.map((function(e){return _r(e,n,t)}))})),Be.prototype.reject=function(n){return this.filter(Fo(Qu(n)))},Be.prototype.slice=function(n,t){n=ra(n);var e=this;return e.__filtered__&&(n>0||t<0)?new Be(e):(n<0?e=e.takeRight(-n):n&&(e=e.drop(n)),void 0!==t&&(e=(t=ra(t))<0?e.dropRight(-t):e.take(t-n)),e)},Be.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},Be.prototype.toArray=function(){return this.take(4294967295)},cr(Be.prototype,(function(n,t){var e=/^(?:filter|find|map|reject)|While$/.test(t),r=/^(?:head|last)$/.test(t),u=xe[r?"take"+("last"==t?"Right":""):t],i=r||/^find/.test(t);u&&(xe.prototype[t]=function(){var t=this.__wrapped__,o=r?[1]:arguments,a=t instanceof Be,c=o[0],l=a||Io(t),f=function(n){var t=u.apply(xe,pt([n],o));return r&&s?t[0]:t};l&&e&&"function"==typeof c&&1!=c.length&&(a=l=!1);var s=this.__chain__,v=!!this.__actions__.length,h=i&&!s,d=a&&!v;if(!i&&l){t=d?t:new Be(this);var p=n.apply(t,o);return p.__actions__.push({func:to,args:[f],thisArg:void 0}),new Ne(p,s)}return h&&d?n.apply(this,o):(p=this.thru(f),h?r?p.value()[0]:p.value():p)})})),ct(["pop","push","shift","sort","splice","unshift"],(function(n){var t=yn[n],e=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",r=/^(?:pop|shift)$/.test(n);xe.prototype[n]=function(){var n=arguments;if(r&&!this.__chain__){var u=this.value();return t.apply(Io(u)?u:[],n)}return this[e]((function(e){return t.apply(Io(e)?e:[],n)}))}})),cr(Be.prototype,(function(n,t){var e=xe[t];if(e){var r=e.name+"";Cn.call(me,r)||(me[r]=[]),me[r].push({name:t,func:e})}})),me[xu(void 0,2).name]=[{name:"wrapper",func:void 0}],Be.prototype.clone=function(){var n=new Be(this.__wrapped__);return n.__actions__=gu(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=gu(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=gu(this.__views__),n},Be.prototype.reverse=function(){if(this.__filtered__){var n=new Be(this);n.__dir__=-1,n.__filtered__=!0}else(n=this.clone()).__dir__*=-1;return n},Be.prototype.value=function(){var n=this.__wrapped__.value(),t=this.__dir__,e=Io(n),r=t<0,u=e?n.length:0,i=function(n,t,e){var r=-1,u=e.length;for(;++r=this.__values__.length;return{done:n,value:n?void 0:this.__values__[this.__index__++]}},xe.prototype.plant=function(n){for(var t,e=this;e instanceof Oe;){var r=Ai(e);r.__index__=0,r.__values__=void 0,t?u.__wrapped__=r:t=r;var u=r;e=e.__wrapped__}return u.__wrapped__=n,t},xe.prototype.reverse=function(){var n=this.__wrapped__;if(n instanceof Be){var t=n;return this.__actions__.length&&(t=new Be(this)),(t=t.reverse()).__actions__.push({func:to,args:[Pi],thisArg:void 0}),new Ne(t,this.__chain__)}return this.thru(Pi)},xe.prototype.toJSON=xe.prototype.valueOf=xe.prototype.value=function(){return eu(this.__wrapped__,this.__actions__)},xe.prototype.first=xe.prototype.head,Xn&&(xe.prototype[Xn]=function(){return this}),xe}();Kn._=Ht,void 0===(u=function(){return Ht}.call(t,e,t,r))||(r.exports=u)}).call(this)}).call(this,e(76),e(456)(n))},454:function(n,t,e){"use strict";var r=e(0),u=Object(r.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=u},455:function(n,t,e){"use strict";e.d(t,"a",(function(){return i}));e(77),e(473),e(439),e(78);var r=e(475),u=e.n(r);function i(n,t){var e=new u.a;return n.map((function(n){var r=n;return"string"==typeof n&&(r={label:n,permalink:"/blog/tags/"+e.slug(n)}),function(n,t){var e=n.label.split(": ",2),r=e[0],u=e[1],i="primary";switch(t){case"blog":case"guides":i=function(n){switch(n){case"domain":return"blue";case"type":return"pink";default:return"primary"}}(r)}return{category:r,count:n.count,label:n.label,permalink:n.permalink,style:i,value:u}}(r,t)}))}},456:function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},465:function(n,t,e){var r=e(30),u=e(54),i=e(27),o=e(26),a=e(466);n.exports=function(n,t){var e=1==n,c=2==n,l=3==n,f=4==n,s=6==n,v=5==n||s,h=t||a;return function(t,a,d){for(var p,D,g=i(t),_=u(g),m=r(a,d,3),y=o(_.length),b=0,E=e?h(t,y):c?h(t,0):void 0;y>b;b++)if((v||b in _)&&(D=m(p=_[b],b,g),n))if(e)E[b]=D;else if(D)switch(n){case 3:return!0;case 5:return p;case 6:return b;case 2:E.push(p)}else if(f)return!1;return s?-1:l||f?f:E}}},466:function(n,t,e){var r=e(467);n.exports=function(n,t){return new(r(n))(t)}},467:function(n,t,e){var r=e(13),u=e(468),i=e(2)("species");n.exports=function(n){var t;return u(n)&&("function"!=typeof(t=n.constructor)||t!==Array&&!u(t.prototype)||(t=void 0),r(t)&&null===(t=t[i])&&(t=void 0)),void 0===t?Array:t}},468:function(n,t,e){var r=e(23);n.exports=Array.isArray||function(n){return"Array"==r(n)}},474:function(n,t,e){"use strict";var r=e(0),u=e.n(r),i=e(430),o=e(423),a=e.n(o);t.a=function(n){var t=n.count,e=n.label,r=n.permalink,o=n.style,c=n.value,l=n.valueOnly;return u.a.createElement(i.a,{to:r+"/",className:a()("badge","badge--rounded","badge--"+o)},l?c:e,t&&u.a.createElement(u.a.Fragment,null," (",t,")"))}},475:function(n,t,e){var r=e(476);n.exports=a;var u=Object.hasOwnProperty,i=/\s/g,o=/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~\u2019]/g;function a(){if(!(this instanceof a))return new a;this.reset()}function c(n,t){return"string"!=typeof n?"":(t||(n=n.toLowerCase()),n.trim().replace(o,"").replace(r(),"").replace(i,"-"))}a.prototype.slug=function(n,t){for(var e=c(n,!0===t),r=e;u.call(this.occurrences,e);)this.occurrences[r]++,e=r+"-"+this.occurrences[r];return this.occurrences[e]=0,e},a.prototype.reset=function(){this.occurrences=Object.create(null)},a.slug=c},476:function(n,t){n.exports=function(){return/[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD79\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED0\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3]|\uD83E[\uDD10-\uDD18\uDD80-\uDD84\uDDC0]|\uD83C\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uD83C\uDDFE\uD83C[\uDDEA\uDDF9]|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDFC\uD83C[\uDDEB\uDDF8]|\uD83C\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uD83C\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF8\uDDFE\uDDFF]|\uD83C\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uD83C\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uD83C\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uD83C\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uD83C\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uD83C\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uD83C\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uD83C\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uD83C\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uD83C\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uD83C\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uD83C\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uD83C\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uD83C\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uD83C\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uD83C\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|[#\*0-9]\u20E3/g}},480:function(n,t,e){"use strict";var r=e(1),u=e(0),i=e.n(u),o=(e(430),e(474)),a=e(423),c=e.n(a),l=e(455),f=e(141),s=e.n(f);t.a=function(n){var t,e=n.block,u=n.colorProfile,a=n.tags,f=n.valuesOnly,v=Object(l.a)(a,u);return i.a.createElement("div",{className:c()(s.a.tags,(t={},t[s.a.tagsBlock]=e,t))},v.map((function(n,t){return i.a.createElement(o.a,Object(r.a)({key:t,valueOnly:f},n))})))}},516:function(n,t,e){"use strict";e(29),e(22),e(21),e(52);var r=e(0),u=e.n(r),i=(e(428),e(439),e(430)),o=e(440),a=e.n(o),c=e(480),l=e(455),f=e(436),s=e(441);e(142);var v=function(n){var t=n.frontMatter,e=n.metadata,r=(n.isGuidePage,Object(s.a)().isDarkTheme),o=e.categories,v=(e.description,e.permalink),h=(e.readingTime,e.seriesPosition),d=e.tags,p=(t.author_github,t.cover_label),D=(t.last_modified_on,t.title),g=Object(l.a)(d,"guides"),_=g.find((function(n){return"domain"==n.category})),m=_?_.value:"default",y=g.find((function(n){return"language"==n.category})),b=y?y.value:null,E=g.find((function(n){return"framework"==n.category})),w=E?E.value:null,F=g.find((function(n){return"technology"==n.category})),C=F?F.value:null,k=g.find((function(n){return"cloud_provider"==n.category})),A=k?k.value:null,x=g.find((function(n){return"provider"==n.category})),j=x?x.value:null,O=g.find((function(n){return"platform"==n.category})),N=O?O.value:null,B=g.find((function(n){return"source"==n.category})),I=B?B.value:null,S=g.find((function(n){return"sink"==n.category})),L=S?S.value:null,R=Object(f.a)().siteConfig.customFields.metadata,z=R.installation,T=R.sources,W=R.sinks,M=R.languages,U=R.frameworks,P=R.technologies,$=R.cloud_providers,q=R.providers,G=z.platforms,V=N&&G[N],Z=I&&T[I],K=L&&W[L],H=b&&M.find((function(n){return n.name===b})),Q=w&&U.find((function(n){return n.name===w})),J=C&&P.find((function(n){return n.name===C})),Y=A&&$.find((function(n){return n.name===A})),X=j&&q.find((function(n){return n.name===j})),nn=null!==(V||Z),tn=null!=K,en=null;Q?en=r?Q.dark_logo_path:Q.logo_path:J?en=r?J.dark_logo_path:J.logo_path:Y?en=r?Y.dark_logo_path:Y.logo_path:X?en=r?X.dark_logo_path:X.logo_path:H?en=r?H.dark_logo_path:H.logo_path:V?en=V.logo_path:Z&&(en=Z.logo_path);var rn=null;return K&&(rn=K.logo_path),u.a.createElement(i.a,{to:v+"/",className:"guide-item"},u.a.createElement("article",null,u.a.createElement("div",{className:"domain-bg domain-bg--"+m+" domain-bg--hover"},u.a.createElement("header",null,u.a.createElement("div",{className:"category"},o[0].name),u.a.createElement("h2",{title:D},h&&h+". ",p||D)),u.a.createElement("footer",null,en&&u.a.createElement(a.a,{src:en,className:"logo"}),!en&&nn&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),rn&&u.a.createElement(a.a,{src:rn,className:"logo"}),!rn&&tn&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),!en&&!rn&&!nn&&!tn&&u.a.createElement(c.a,{colorProfile:"guides",tags:d}),u.a.createElement("div",{className:"action"},"read now")))))},h=e(450),d=e(451),p=e.n(d),D=e(423),g=e.n(D);e(143);function _(n){var t=n.groupLevel,e=n.items,r=n.large,i=n.staggered,o=p()(e).map((function(n){return n.content.metadata.categories[t-1]})).uniqBy("permalink").sortBy("title").keyBy("permalink").value(),a=p.a.groupBy(e,(function(n){return n.content.metadata.categories[t-1].permalink})),c=Object(h.a)("h"+(t+1));return Object.keys(o).map((function(n,t){var e=a[n],l=o[n];return u.a.createElement("section",{key:t},u.a.createElement(c,{id:n},l.title),l.description&&u.a.createElement("div",{className:"sub-title"},l.description),u.a.createElement(m,{items:e,large:r,staggered:i}))}))}function m(n){var t=n.groupLevel,e=n.items,r=n.large,i=n.staggered;if(t)return u.a.createElement(_,{groupLevel:t,items:e});var o,a=(o=e,p.a.sortBy(o,["content.metadata.seriesPosition",function(n){return n.content.metadata.coverLabel.toLowerCase()}]));return u.a.createElement("div",{className:"guides"},u.a.createElement("div",{className:g()("guide-items",{"guide-items--l":r,"guide-items--staggered":i})},a.map((function(n){var t=n.content;return u.a.createElement(v,{key:t.metadata.permalink,frontMatter:t.frontMatter,metadata:t.metadata,truncated:t.metadata.truncated},u.a.createElement(t,null))}))))}t.a=m}}]); \ No newline at end of file diff --git a/d9deea5f.1e918522.js.LICENSE.txt b/d9deea5f.4add985c.js.LICENSE.txt similarity index 100% rename from d9deea5f.1e918522.js.LICENSE.txt rename to d9deea5f.4add985c.js.LICENSE.txt diff --git a/a8a9c166.26c10c96.js b/da253275.da5e2b94.js similarity index 87% rename from a8a9c166.26c10c96.js rename to da253275.da5e2b94.js index ce307132eb..ae9e9b279b 100644 --- a/a8a9c166.26c10c96.js +++ b/da253275.da5e2b94.js @@ -1,2 +1,2 @@ -/*! For license information please see a8a9c166.26c10c96.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[165],{317:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return f}));var r=n(1),o=n(9),a=(n(0),n(422)),i=(n(431),n(426),n(421)),c={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Costs Control",description:"Learn how to keep control of your costs with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Costs Control",description:"Learn how to keep control of your costs with Qovery",permalink:"/guides/advanced/costs-control",readingTime:"1 min read",source:"@site/guides/advanced/costs-control.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Costs Control",truncated:!1,prevItem:{title:"Continuous Integration",permalink:"/guides/advanced/continuous-integration"},nextItem:{title:"Create a blazingly fast REST API in Rust (Part 1/2)",permalink:"/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1"}},s=[{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function f(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},"WIP"),Object(a.b)("h2",{id:"qa"},"Q&A"),Object(a.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}f.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},f=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),f=l(n),d=r,m=f["".concat(i,".").concat(d)]||f[d]||p[d]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:o(u,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),f=l[0],p=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!f&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see da253275.da5e2b94.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[229],{381:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return f}));var r=n(1),o=n(9),a=(n(0),n(425)),i=(n(434),n(429),n(424)),c={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Costs Control",description:"Learn how to keep control of your costs with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Costs Control",description:"Learn how to keep control of your costs with Qovery",permalink:"/guides/advanced/costs-control",readingTime:"1 min read",source:"@site/guides/advanced/costs-control.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Costs Control",truncated:!1,prevItem:{title:"Continuous Integration",permalink:"/guides/advanced/continuous-integration"},nextItem:{title:"Create a blazingly fast REST API in Rust (Part 1/2)",permalink:"/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1"}},s=[{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function f(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},"WIP"),Object(a.b)("h2",{id:"qa"},"Q&A"),Object(a.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}f.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},f=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),f=l(n),d=r,m=f["".concat(i,".").concat(d)]||f[d]||p[d]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:o(u,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),f=l[0],p=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!f&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==f&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/db96bb7d.df1d14cf.js.LICENSE.txt b/da253275.da5e2b94.js.LICENSE.txt similarity index 100% rename from db96bb7d.df1d14cf.js.LICENSE.txt rename to da253275.da5e2b94.js.LICENSE.txt diff --git a/dab3a2be.12f5c1ea.js b/dab3a2be.f6aff845.js similarity index 91% rename from dab3a2be.12f5c1ea.js rename to dab3a2be.f6aff845.js index b9422202b6..670ea3a39f 100644 --- a/dab3a2be.12f5c1ea.js +++ b/dab3a2be.f6aff845.js @@ -1,2 +1,2 @@ -/*! For license information please see dab3a2be.12f5c1ea.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[227],{379:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return c})),t.d(r,"metadata",(function(){return s})),t.d(r,"rightToc",(function(){return l})),t.d(r,"default",(function(){return p}));var n=t(1),a=t(9),o=(t(0),t(422)),i=t(421),c={last_modified_on:"2023-05-20",title:"AWS Secrets Manager",description:"Learn how to configure AWS Secrets Manager"},s={id:"using-qovery/integration/secret-manager/aws-secrets-manager",title:"AWS Secrets Manager",description:"Learn how to configure AWS Secrets Manager",source:"@site/docs/using-qovery/integration/secret-manager/aws-secrets-manager.md",permalink:"/docs/using-qovery/integration/secret-manager/aws-secrets-manager",sidebar:"docs",previous:{title:"Doppler",permalink:"/docs/using-qovery/integration/secret-manager/doppler"},next:{title:"Webhooks",permalink:"/docs/using-qovery/integration/webhook"}},l=[{value:"Setup",id:"setup",children:[{value:"API Keys",id:"api-keys",children:[]},{value:"Assume Roles",id:"assume-roles",children:[]}]}],u={rightToc:l};function p(e){var r=e.components,t=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},u,t,{components:r,mdxType:"MDXLayout"}),Object(o.b)("p",null,"AWS Secrets Manager is a service that helps you protect secrets needed to access your applications, services, and IT resources. The service enables you to easily rotate, manage, and retrieve database credentials, API keys, and other secrets throughout their lifecycle."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"To provide better integration with Qovery - we recommend using AWS Secrets Manager with Doppler. Doppler ease the synchronization of AWS Secrets Manager with Qovery. You can find more information about Doppler and Qovery integration ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/integration/secret-manager/doppler/"}),"here"),".")),Object(o.b)("h2",{id:"setup"},"Setup"),Object(o.b)("h3",{id:"api-keys"},"API Keys"),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"We highly recommend using ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"#assume-roles"}),"Assume Roles")," instead of API Keys.")),Object(o.b)("p",null,"If your applications need to use AWS Secrets Manager with API Keys, you need to add your API Key in ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#create-an-environment-variable"}),"Qovery Secrets Manager"),"."),Object(o.b)("p",null,"Then you can use it in your application as a regular environment variable."),Object(o.b)("h3",{id:"assume-roles"},"Assume Roles"),Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/use-aws-iam-roles-with-qovery/"}),"this guide")," to get assume roles on your Kubernetes cluster. Once it is set up, your application will be able to connect to AWS Secrets Manager using the AWS SDK."))}p.isMDXComponent=!0},420:function(e,r,t){var n;!function(){"use strict";var t={}.hasOwnProperty;function a(){for(var e=[],r=0;r=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=a.a.createContext({}),u=function(e){var r=a.a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},p=function(e){var r=u(e.components);return a.a.createElement(l.Provider,{value:r},e.children)},f={inlineCode:"code",wrapper:function(e){var r=e.children;return a.a.createElement(a.a.Fragment,{},r)}},b=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(t),b=n,d=p["".concat(i,".").concat(b)]||p[b]||f[b]||o;return t?a.a.createElement(d,c({ref:r},l,{components:t})):a.a.createElement(d,c({ref:r},l))}));function d(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var o=t.length,i=new Array(o);i[0]=b;var c={};for(var s in r)hasOwnProperty.call(r,s)&&(c[s]=r[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l1?arguments[1]:void 0,t),s=i>2?arguments[2]:void 0,l=void 0===s?t:a(s,t);l>c;)r[c++]=e;return r}}}]); \ No newline at end of file +/*! For license information please see dab3a2be.f6aff845.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[230],{382:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return c})),t.d(r,"metadata",(function(){return s})),t.d(r,"rightToc",(function(){return l})),t.d(r,"default",(function(){return p}));var n=t(1),a=t(9),o=(t(0),t(425)),i=t(424),c={last_modified_on:"2023-05-20",title:"AWS Secrets Manager",description:"Learn how to configure AWS Secrets Manager"},s={id:"using-qovery/integration/secret-manager/aws-secrets-manager",title:"AWS Secrets Manager",description:"Learn how to configure AWS Secrets Manager",source:"@site/docs/using-qovery/integration/secret-manager/aws-secrets-manager.md",permalink:"/docs/using-qovery/integration/secret-manager/aws-secrets-manager",sidebar:"docs",previous:{title:"Doppler",permalink:"/docs/using-qovery/integration/secret-manager/doppler"},next:{title:"Webhooks",permalink:"/docs/using-qovery/integration/webhook"}},l=[{value:"Setup",id:"setup",children:[{value:"API Keys",id:"api-keys",children:[]},{value:"Assume Roles",id:"assume-roles",children:[]}]}],u={rightToc:l};function p(e){var r=e.components,t=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},u,t,{components:r,mdxType:"MDXLayout"}),Object(o.b)("p",null,"AWS Secrets Manager is a service that helps you protect secrets needed to access your applications, services, and IT resources. The service enables you to easily rotate, manage, and retrieve database credentials, API keys, and other secrets throughout their lifecycle."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"To provide better integration with Qovery - we recommend using AWS Secrets Manager with Doppler. Doppler ease the synchronization of AWS Secrets Manager with Qovery. You can find more information about Doppler and Qovery integration ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/integration/secret-manager/doppler/"}),"here"),".")),Object(o.b)("h2",{id:"setup"},"Setup"),Object(o.b)("h3",{id:"api-keys"},"API Keys"),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"We highly recommend using ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"#assume-roles"}),"Assume Roles")," instead of API Keys.")),Object(o.b)("p",null,"If your applications need to use AWS Secrets Manager with API Keys, you need to add your API Key in ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#create-an-environment-variable"}),"Qovery Secrets Manager"),"."),Object(o.b)("p",null,"Then you can use it in your application as a regular environment variable."),Object(o.b)("h3",{id:"assume-roles"},"Assume Roles"),Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/use-aws-iam-roles-with-qovery/"}),"this guide")," to get assume roles on your Kubernetes cluster. Once it is set up, your application will be able to connect to AWS Secrets Manager using the AWS SDK."))}p.isMDXComponent=!0},423:function(e,r,t){var n;!function(){"use strict";var t={}.hasOwnProperty;function a(){for(var e=[],r=0;r=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=a.a.createContext({}),u=function(e){var r=a.a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},p=function(e){var r=u(e.components);return a.a.createElement(l.Provider,{value:r},e.children)},f={inlineCode:"code",wrapper:function(e){var r=e.children;return a.a.createElement(a.a.Fragment,{},r)}},b=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(t),b=n,d=p["".concat(i,".").concat(b)]||p[b]||f[b]||o;return t?a.a.createElement(d,c({ref:r},l,{components:t})):a.a.createElement(d,c({ref:r},l))}));function d(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var o=t.length,i=new Array(o);i[0]=b;var c={};for(var s in r)hasOwnProperty.call(r,s)&&(c[s]=r[s]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var l=2;l1?arguments[1]:void 0,t),s=i>2?arguments[2]:void 0,l=void 0===s?t:a(s,t);l>c;)r[c++]=e;return r}}}]); \ No newline at end of file diff --git a/dc00a797.d1e63223.js.LICENSE.txt b/dab3a2be.f6aff845.js.LICENSE.txt similarity index 100% rename from dc00a797.d1e63223.js.LICENSE.txt rename to dab3a2be.f6aff845.js.LICENSE.txt diff --git a/db372ba8.532ca542.js b/db372ba8.afb302c4.js similarity index 97% rename from db372ba8.532ca542.js rename to db372ba8.afb302c4.js index 408a290477..05f9917cb4 100644 --- a/db372ba8.532ca542.js +++ b/db372ba8.afb302c4.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[228],{380:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return p})),a.d(t,"metadata",(function(){return d})),a.d(t,"rightToc",(function(){return m})),a.d(t,"default",(function(){return g}));var n=a(1),l=a(9),r=(a(0),a(422)),i=a(431),s=a(434),o=a(441),c=a(421),b=a(426),u=a(429),p={last_modified_on:"2023-04-24",$schema:"/.meta/.schemas/guides.json",title:"Create a blazingly fast REST API in Rust (Part 1/2)",description:"How to create a blazingly fast REST API in Rust, with zero-cost abstraction and very low overhead - Part 1/2",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","language: rust"],hide_pagination:!0},d={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Create a blazingly fast REST API in Rust (Part 1/2)",description:"How to create a blazingly fast REST API in Rust, with zero-cost abstraction and very low overhead - Part 1/2",permalink:"/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1",readingTime:"14 min read",source:"@site/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"language: rust",permalink:"/guides/tags/language-rust"}],title:"Create a blazingly fast REST API in Rust (Part 1/2)",truncated:!1,prevItem:{title:"Costs Control",permalink:"/guides/advanced/costs-control"},nextItem:{title:"Create a Playground Environment on AWS",permalink:"/guides/tutorial/create-a-playground-environment-on-aws"}},m=[{value:"Twitter clone",id:"twitter-clone",children:[{value:"API design",id:"api-design",children:[]}]},{value:"Implementation",id:"implementation",children:[{value:"Actix Web",id:"actix-web",children:[]},{value:"Let's code",id:"lets-code",children:[]},{value:"Validation",id:"validation",children:[]}]},{value:"PostgreSQL",id:"postgresql",children:[{value:"Diesel",id:"diesel",children:[]}]},{value:"Deployment",id:"deployment",children:[{value:"Install Qovery CLI",id:"install-qovery-cli",children:[]},{value:"Sign up",id:"sign-up",children:[]},{value:"Deploying the app",id:"deploying-the-app",children:[]},{value:"Create a new project",id:"create-a-new-project",children:[]},{value:"Create a new environment",id:"create-a-new-environment",children:[]},{value:"Create a new application",id:"create-a-new-application",children:[]},{value:"Deploy a database",id:"deploy-a-database",children:[]},{value:"Configure the connection to the database",id:"configure-the-connection-to-the-database",children:[]}]},{value:"Deploy your application",id:"deploy-your-application",children:[]},{value:"Live test",id:"live-test",children:[]},{value:"What's next",id:"whats-next",children:[]},{value:"Useful resources",id:"useful-resources",children:[]}],h={rightToc:m};function g(e){var t=e.components,a=Object(l.a)(e,["components"]);return Object(r.b)("wrapper",Object(n.a)({},h,a,{components:t,mdxType:"MDXLayout"}),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/rust-lang/www.rust-lang.org/issues/419#issuecomment-443418587"}),"Fast, reliable, productive - Pick three")," | Rust's slogan")),Object(r.b)("p",null,"Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety. Coupled with Actix, I should be able to build a fast REST API elegantly."),Object(r.b)("p",null,"The idea behind this article is to see how performant a Rust API can be. I am going to create an API that saves and reads data from/to a PostgreSQL database."),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,'Most of the Rust REST API tests across the web are "',Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://medium.com/sean3z/rest-api-node-vs-rust-c75aa8c96343"}),"Hello World"),"\" applications. They bench direct API I/O with no payload. It's very far from reality. In the part 2 of this article, I will bench our Rust application with an intensive payload.")),Object(r.b)("p",null,"This article is separate in two parts, in this first part you will learn how to:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Create a blazingly fast REST API in Rust"),Object(r.b)("li",{parentName:"ul"},"Connect it to a PostgreSQL database")),Object(r.b)("p",null,"In the second part, we will compare the performance of our application to a Go application."),Object(r.b)("h2",{id:"twitter-clone"},"Twitter clone"),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.twitter.com"}),"Twitter"),' is a "microblogging" system that allows people to send and receive short posts called tweets.')),Object(r.b)("p",null,"Let's create a small part of the Twitter API to be able to post, read, and like tweets. The goal is to be able to use our Twitter clone with a massive number of simultaneous fake users."),Object(r.b)(b.a,{mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have installed ",Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/rust-lang/cargo"}),"Cargo")," (Rust package manager)"))),Object(r.b)("h3",{id:"api-design"},"API design"),Object(r.b)("p",null,"Our REST API needs to have three endpoints :"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"/tweets"),Object(r.b)("ul",{parentName:"li"},Object(r.b)("li",{parentName:"ul"},"GET: list last 50 tweets"),Object(r.b)("li",{parentName:"ul"},"POST: create a new tweet"))),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"/tweets/:id"),Object(r.b)("ul",{parentName:"li"},Object(r.b)("li",{parentName:"ul"},"GET: find a tweet by its ID"),Object(r.b)("li",{parentName:"ul"},"DELETE: delete a tweet by its ID"))),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"/tweets/:id/likes"),Object(r.b)("ul",{parentName:"li"},Object(r.b)("li",{parentName:"ul"},"GET: list all likes attached to a tweet"),Object(r.b)("li",{parentName:"ul"},"POST: add +1 like to a tweet"),Object(r.b)("li",{parentName:"ul"},"DELETE: add -1 like to a tweet")))),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"For the sake of simplicity, I will not set up a user management service.")),Object(r.b)("h2",{id:"implementation"},"Implementation"),Object(r.b)("p",null,"Even though implementing an HTTP server could be fun, I choose to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://actix.rs/"}),"Actix"),", which is ranked as ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.techempower.com/benchmarks/#section=data-r18&hw=ph&test=fortune"}),"the most performant framework")," ever by ",Object(r.b)("em",{parentName:"p"},"Techempower"),"."),Object(r.b)("h3",{id:"actix-web"},"Actix Web"),Object(r.b)("p",null,"Actix is an actor framework prevalent in the Rust ecosystem. I am using it as an HTTP server to build our REST API."),Object(r.b)("h3",{id:"lets-code"},"Let's code"),Object(r.b)("p",null,"Three files structured our application."),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"main.rs")," to route HTTP requests to the right endpoint"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"tweet.rs")," to handle requests on /tweets"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"like.rs")," to handle requests on /tweets/:id/likes")),Object(r.b)(s.a,{centered:!1,className:"square",defaultValue:"main.rs",select:!1,size:null,values:[{group:"Files",label:"main.rs",value:"main.rs"},{group:"Files",label:"tweet.rs",value:"tweet.rs"},{group:"Files",label:"like.rs",value:"like.rs"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"main.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="main.rs"',title:'"main.rs"'}),'#[actix_rt::main]\nasync fn main() -> io::Result<()> {\n env::set_var("RUST_LOG", "actix_web=debug,actix_server=info");\n env_logger::init();\n\n HttpServer::new(|| {\n App::new()\n // enable logger - always register actix-web Logger middleware last\n .wrap(middleware::Logger::default())\n // register HTTP requests handlers\n .service(tweet::list)\n .service(tweet::get)\n .service(tweet::create)\n .service(tweet::delete)\n .service(like::list)\n .service(like::plus_one)\n .service(like::minus_one)\n })\n .bind("0.0.0.0:9090")?\n .run()\n .await\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/487198ee7b306f36dbab01f40a44345f85387db2/src/main.rs"}),"main.rs source code"))),Object(r.b)(o.a,{value:"tweet.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="tweet.rs"',title:'"tweet.rs"'}),'pub type Tweets = Response;\n\n#[derive(Debug, Deserialize, Serialize)]\npub struct Tweet {\n pub id: String,\n pub created_at: DateTime,\n pub message: String,\n pub likes: Vec,\n}\n\nimpl Tweet {\n pub fn new(message: String) -> Self {\n Self {\n id: Uuid::new_v4().to_string(),\n created_at: Utc::now(),\n message,\n likes: vec![],\n }\n }\n}\n\n#[derive(Debug, Deserialize, Serialize)]\npub struct TweetRequest {\n pub message: Option,\n}\n\nimpl TweetRequest {\n pub fn to_tweet(&self) -> Option {\n match &self.message {\n Some(message) => Some(Tweet::new(message.to_string())),\n None => None,\n }\n }\n}\n\n/// list 50 last tweets `/tweets`\n#[get("/tweets")]\npub async fn list() -> HttpResponse {\n // TODO find the last 50 tweets and return them\n\n let tweets = Tweets { results: vec![] };\n\n HttpResponse::Ok()\n .content_type(APPLICATION_JSON)\n .json(tweets)\n}\n\n/// create a tweet `/tweets`\n#[post("/tweets")]\npub async fn create(tweet_req: Json) -> HttpResponse {\n HttpResponse::Created()\n .content_type(APPLICATION_JSON)\n .json(tweet_req.to_tweet())\n}\n\n/// find a tweet by its id `/tweets/{id}`\n#[get("/tweets/{id}")]\npub async fn get(path: Path<(String,)>) -> HttpResponse {\n // TODO find tweet a tweet by ID and return it\n let found_tweet: Option = None;\n\n match found_tweet {\n Some(tweet) => HttpResponse::Ok()\n .content_type(APPLICATION_JSON)\n .json(tweet),\n None => HttpResponse::NoContent()\n .content_type(APPLICATION_JSON)\n .await\n .unwrap(),\n }\n}\n\n/// delete a tweet by its id `/tweets/{id}`\n#[delete("/tweets/{id}")]\npub async fn delete(path: Path<(String,)>) -> HttpResponse {\n // TODO delete tweet by ID\n // in any case return status 204\n\n HttpResponse::NoContent()\n .content_type(APPLICATION_JSON)\n .await\n .unwrap()\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/487198ee7b306f36dbab01f40a44345f85387db2/src/tweet.rs"}),"tweet.rs source code"))),Object(r.b)(o.a,{value:"like.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="like.rs"',title:'"like.rs"'}),'pub type Likes = Response;\n\n#[derive(Debug, Deserialize, Serialize)]\npub struct Like {\n pub id: String,\n pub created_at: DateTime,\n}\n\nimpl Like {\n pub fn new() -> Self {\n Self {\n id: Uuid::new_v4().to_string(),\n created_at: Utc::now(),\n }\n }\n}\n\n/// list last 50 likes from a tweet `/tweets/{id}/likes`\n#[get("/tweets/{id}/likes")]\npub async fn list(path: Path<(String,)>) -> HttpResponse {\n // TODO find likes by tweet ID and return them\n let likes = Likes { results: vec![] };\n\n HttpResponse::Ok()\n .content_type(APPLICATION_JSON)\n .json(likes)\n}\n\n/// add one like to a tweet `/tweets/{id}/likes`\n#[post("/tweets/{id}/likes")]\npub async fn plus_one(path: Path<(String,)>) -> HttpResponse {\n // TODO add one like to a tweet\n let like = Like::new();\n\n HttpResponse::Created()\n .content_type(APPLICATION_JSON)\n .json(like)\n}\n\n/// remove one like from a tweet `/tweets/{id}/likes`\n#[delete("/tweets/{id}/likes")]\npub async fn minus_one(path: Path<(String,)>) -> HttpResponse {\n // TODO remove one like to a tweet\n HttpResponse::NoContent()\n .content_type(APPLICATION_JSON)\n .await\n .unwrap()\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/487198ee7b306f36dbab01f40a44345f85387db2/src/like.rs"}),"like.rs source code")))),Object(r.b)("p",null,"With only these three files, our application is ready to receive HTTP requests. In a couple of lines, we have a fully operational application. Actix takes care of the low level boilerplate for us."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="Annotation"',title:'"Annotation"'}),'#[get("/tweets")]\n')),Object(r.b)("p",null,"Annotation is a very convenient way to bind a route to the right path."),Object(r.b)("h3",{id:"validation"},"Validation"),Object(r.b)("p",null,"Let's run our application:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="Run our application"',title:'"Run',our:!0,'application"':!0}),"# Go inside the root project directory\n$ cd twitter-clone-rust\n\n# Run the application\n$ cargo run\n")),Object(r.b)("p",null,"And validate that each endpoint with no errors:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="Curl commands to test our API"',title:'"Curl',commands:!0,to:!0,test:!0,our:!0,'API"':!0}),'# list tweets\ncurl http://localhost:9090/tweets\n\n# get a tweet (return status code: 204 because there is no tweet)\ncurl http://localhost:9090/tweets/abc\n\n# create a tweet\ncurl -X POST -d \'{"message": "This is a tweet"}\' -H "Content-type: application/json" http://localhost:9090/tweets\n\n# delete a tweet (return status code: 204 in any case)\ncurl -X DELETE http://localhost:9090/tweets/abc\n\n# list likes from a tweet\ncurl http://localhost:9090/tweets/abc/likes\n\n# add one like to a tweet\ncurl -X POST http://localhost:9090/tweets/abc/likes\n\n# remove one like to a tweet\ncurl -X DELETE http://localhost:9090/tweets/abc/likes\n')),Object(r.b)("p",null,"At this stage, our application works without any database. Let's go more in-depth and connect it to PostgreSQL."),Object(r.b)("h2",{id:"postgresql"},"PostgreSQL"),Object(r.b)("h3",{id:"diesel"},"Diesel"),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://diesel.rs/"}),"Diesel")," is the most popular ORM in Rust to connect to a ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.postgresql.org"}),"PostgreSQL")," database. Combined with Actix, it's a perfect fit to persist in our data. Let's see how we can make that happen. However, Diesel does not support ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/tokio-rs/tokio"}),"tokio")," (the asynchronous engine behind Actix), so we have to run it in separate threads using the web::block function, which offloads blocking code (like Diesel's) to do not block the server's thread."),Object(r.b)(c.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Read the Diesel ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"http://diesel.rs/guides/getting-started/"}),"Getting started")," to generate tables configurations.")),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="schema.rs"',title:'"schema.rs"'}),"table! {\n likes (id) {\n id -> Uuid,\n created_at -> Timestamp,\n tweet_id -> Uuid,\n }\n}\n\ntable! {\n tweets (id) {\n id -> Uuid,\n created_at -> Timestamp,\n message -> Text,\n }\n}\n\njoinable!(likes -> tweets (tweet_id));\n\nallow_tables_to_appear_in_same_query!(\n likes,\n tweets,\n);\n")),Object(r.b)("p",null,"Diesel uses a macro ",Object(r.b)("inlineCode",{parentName:"p"},"table!...")," and an internal DSL to declare the structure of our tables. There is no magic here. The code is compiled and statically linked at the compilation."),Object(r.b)(s.a,{centered:!1,className:"square",defaultValue:"main.rs",select:!1,size:null,values:[{group:"Files",label:"main.rs",value:"main.rs"},{group:"Files",label:"tweet.rs",value:"tweet.rs"},{group:"Files",label:"like.rs",value:"like.rs"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"main.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="main.rs" {6-11,15-16}',title:'"main.rs"',"{6-11,15-16}":!0}),'#[actix_rt::main]\nasync fn main() -> io::Result<()> {\n env::set_var("RUST_LOG", "actix_web=debug,actix_server=info");\n env_logger::init();\n\n // set up database connection pool\n let database_url = env::var("DATABASE_URL").expect("DATABASE_URL");\n let manager = ConnectionManager::::new(database_url);\n let pool = r2d2::Pool::builder()\n .build(manager)\n .expect("Failed to create pool");\n\n HttpServer::new(move || {\n App::new()\n // Set up DB pool to be used with web::Data extractor\n .data(pool.clone())\n // enable logger - always register actix-web Logger middleware last\n .wrap(middleware::Logger::default())\n // register HTTP requests handlers\n .service(tweet::list)\n .service(tweet::get)\n .service(tweet::create)\n .service(tweet::delete)\n .service(like::list)\n .service(like::plus_one)\n .service(like::minus_one)\n })\n .bind("0.0.0.0:9090")?\n .run()\n .await\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/master/src/main.rs"}),"main.rs source code"))),Object(r.b)(o.a,{value:"tweet.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="tweet.rs"',title:'"tweet.rs"'}),"//...\nfn list_tweets(total_tweets: i64, conn: &DBPooledConnection) -> Result {\n use crate::schema::tweets::dsl::*;\n\n let _tweets = match tweets\n .order(created_at.desc())\n .limit(total_tweets)\n .load::(conn)\n {\n Ok(tws) => tws,\n Err(_) => vec![],\n };\n\n Ok(Tweets {\n results: _tweets\n .into_iter()\n .map(|t| t.to_tweet())\n .collect::>(),\n })\n}\n\nfn find_tweet(_id: Uuid, conn: &DBPooledConnection) -> Result {\n use crate::schema::tweets::dsl::*;\n\n let res = tweets.filter(id.eq(_id)).load::(conn);\n match res {\n Ok(tweets_db) => match tweets_db.first() {\n Some(tweet_db) => Ok(tweet_db.to_tweet()),\n _ => Err(Error::NotFound),\n },\n Err(err) => Err(err),\n }\n}\n\nfn create_tweet(tweet: Tweet, conn: &DBPooledConnection) -> Result {\n use crate::schema::tweets::dsl::*;\n\n let tweet_db = tweet.to_tweet_db();\n let _ = diesel::insert_into(tweets).values(&tweet_db).execute(conn);\n\n Ok(tweet_db.to_tweet())\n}\n\nfn delete_tweet(_id: Uuid, conn: &DBPooledConnection) -> Result<(), Error> {\n use crate::schema::tweets::dsl::*;\n\n let res = diesel::delete(tweets.filter(id.eq(_id))).execute(conn);\n match res {\n Ok(_) => Ok(()),\n Err(err) => Err(err),\n }\n}\n//...\n")),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/master/src/tweet.rs"}),"tweet.rs source code"))),Object(r.b)(o.a,{value:"like.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="like.rs"',title:'"like.rs"'}),"//...\npub fn list_likes(_tweet_id: Uuid, conn: &DBPooledConnection) -> Result {\n use crate::schema::likes::dsl::*;\n\n let _likes: Vec = match likes\n .filter(tweet_id.eq(_tweet_id))\n .order(created_at.desc())\n .load::(conn)\n {\n Ok(lks) => lks,\n Err(_) => vec![],\n };\n\n Ok(Likes {\n results: _likes\n .into_iter()\n .map(|l| l.to_like())\n .collect::>(),\n })\n}\n\npub fn create_like(_tweet_id: Uuid, conn: &DBPooledConnection) -> Result {\n use crate::schema::likes::dsl::*;\n\n let like = Like::new();\n let _ = diesel::insert_into(likes)\n .values(like.to_like_db(_tweet_id))\n .execute(conn);\n\n Ok(like)\n}\n\npub fn delete_like(_tweet_id: Uuid, conn: &DBPooledConnection) -> Result<(), Error> {\n use crate::schema::likes::dsl::*;\n\n let _likes = list_likes(_tweet_id, conn);\n\n let like = match &_likes {\n Ok(_likes) if !_likes.results.is_empty() => _likes.results.first(),\n _ => None,\n };\n\n if like.is_none() {\n return Ok(());\n }\n\n let like_id = Uuid::from_str(like.unwrap().id.as_str()).unwrap();\n\n let res = diesel::delete(likes.filter(id.eq(like_id))).execute(conn);\n match res {\n Ok(_) => Ok(()),\n Err(err) => Err(err),\n }\n}\n//...\n")),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/master/src/like.rs"}),"like.rs source code")))),Object(r.b)("h2",{id:"deployment"},"Deployment"),Object(r.b)("p",null,"Qovery is going to help you to deploy your application in a few seconds. Let's deploy our Twitter Clone now."),Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"web",placeholder:"Select your interface",select:!1,size:null,values:[{group:"Interfaces",label:"Web",value:"web"},{group:"Interfaces",label:"CLI",value:"cli"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"web",mdxType:"TabItem"},Object(r.b)("li",null,Object(r.b)("p",null,"Sign in to the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web interface"),"."),Object(r.b)("p",{align:"center"},Object(r.b)("a",{href:"https://onboarding.qovery.com/"},Object(r.b)("img",{src:"/img/Qovery_Sign_Up_Page.jpg",alt:"Qovery Sign-up page"}))))),Object(r.b)(o.a,{value:"cli",mdxType:"TabItem"},Object(r.b)("li",null,Object(r.b)("h3",{id:"install-qovery-cli"},"Install Qovery CLI"),Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"linux",placeholder:"Select your OS",select:!1,size:null,values:[{group:"Platforms",label:"Linux",value:"linux"},{group:"Platforms",label:"MacOS",value:"macos"},{group:"Platforms",label:"Windows",value:"windows"},{group:"Platforms",label:"Docker",value:"docker"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"linux",mdxType:"TabItem"},Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"universal",values:[{label:"*nix",value:"universal"},{label:"Arch Linux",value:"arch"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"universal",mdxType:"TabItem"},Object(r.b)("p",null,"To download and install Qovery CLI on any Linux distribution:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(r.b)(o.a,{value:"arch",mdxType:"TabItem"},Object(r.b)("p",null,"Qovery is part of ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(r.b)(o.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Linux manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(r.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(r.b)(o.a,{value:"macos",mdxType:"TabItem"},Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"homebrew",values:[{label:"Homebrew",value:"homebrew"},{label:"Script",value:"script"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"homebrew",mdxType:"TabItem"},Object(r.b)("p",null,"The common solution to install a command line binary on the MacOS is to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery brew repository\n$ brew tap Qovery/qovery-cli\n\n# Install the CLI\n$ brew install qovery-cli\n"))),Object(r.b)(o.a,{value:"script",mdxType:"TabItem"},Object(r.b)("p",null,"To download and install Qovery CLI from the command line:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(r.b)(o.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Mac OS manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(r.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(r.b)(o.a,{value:"windows",mdxType:"TabItem"},Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"scoop",mdxType:"TabItem"},Object(r.b)("p",null,"The classic way to install binaries on Windows is to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery bucket\n$ scoop bucket add qovery https://github.com/Qovery/scoop-qovery-cli\n\n# Install the CLI\n$ scoop install qovery-cli\n"))),Object(r.b)(o.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Windows manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to\n",Object(r.b)("inlineCode",{parentName:"p"},"C:\\Windows"),".")))),Object(r.b)(o.a,{value:"docker",mdxType:"TabItem"},Object(r.b)("p",null,"Install Docker on your local machine and run the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Pull and Run the latest Qovery CLI\n$ docker run ghcr.io/qovery/qovery-cli:latest help\n")),Object(r.b)("p",null,"Change ",Object(r.b)("inlineCode",{parentName:"p"},"latest")," by the version you want to use. For example, to use the version 0.58.4, run:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ docker run ghcr.io/qovery/qovery-cli:0.58.4 help\n")),Object(r.b)("p",null,"Note: ",Object(r.b)("inlineCode",{parentName:"p"},"ghcr.io")," is the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/pkgs/container/qovery-cli"}),"GitHub Container Registry"),".")))),Object(r.b)("li",null,Object(r.b)("h3",{id:"sign-up"},"Sign up"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"If you are using an environment without access to GUI or a browser, you can use headless authentication instead:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth --headless\n"))),Object(r.b)("p",null,"Your browser window with sign-in options will open."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/qovery_signup.svg",alt:"Qovery Sign-up page"})),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/apps/qovery/installations/new"}),"Click here")," to authorize Qovery to clone and build your applications."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/github_signup.svg",alt:"Connect Github"})),Object(r.b)("p",null,"Congratulations, you are logged-in.")))),Object(r.b)("h3",{id:"deploying-the-app"},"Deploying the app"),Object(r.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,Object(r.b)("h3",{id:"create-a-new-project"},"Create a new project"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/heroku/heroku-2.png",alt:"Migrate from Heroku"}))),Object(r.b)("li",null,Object(r.b)("h3",{id:"create-a-new-environment"},"Create a new environment"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/heroku/heroku-3.png",alt:"Migrate from Heroku"}))),Object(r.b)("li",null,Object(r.b)("h3",{id:"create-a-new-application"},"Create a new application"),Object(r.b)("p",null,"To follow the guide, ",Object(r.b)("a",{href:"https://github.com/evoxmusic/twitter-clone-rust"},"you can fork and use our repository")),Object(r.b)("p",null,"Use the forked repository (and branch ",Object(r.b)("strong",{parentName:"p"},"master"),") while creating the application in the repository field:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/rust/rust.png",alt:"Migrate from Heroku"}))),Object(r.b)("li",null,Object(r.b)("p",null,"After the application is created: "),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Navigate application settings"),Object(r.b)("li",{parentName:"ul"},"Select ",Object(r.b)("strong",{parentName:"li"},"Port")),Object(r.b)("li",{parentName:"ul"},"Add port ",Object(r.b)("strong",{parentName:"li"},"9090"))),Object(r.b)("p",{align:"left"},Object(r.b)("img",{src:"/img/micro/micros-1.png",alt:"Microservices"}))),Object(r.b)("li",null,Object(r.b)("h3",{id:"deploy-a-database"},"Deploy a database"),Object(r.b)("p",null,"Create and deploy a new database"),Object(r.b)(c.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Name the database ",Object(r.b)("strong",{parentName:"p"},"my-pql-db")," to follow the guide flawlessly")),Object(r.b)("p",null,"To learn how to do it, you can ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"follow this guide"))),Object(r.b)("li",null,Object(r.b)("h3",{id:"configure-the-connection-to-the-database"},"Configure the connection to the database"),Object(r.b)("p",null,"In application overview, open the ",Object(r.b)("strong",{parentName:"p"},"Variables")," tab"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/open-env-var.png",alt:"Open Variable"})),Object(r.b)("p",null,"Configure the alias for each built_in environment variable to match the one required within your code"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/alias.png",alt:"Env Var Alias"})),Object(r.b)("p",null,"Have a look at ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-a-database"}),"this section")," to know more on how to connect to a database.")),Object(r.b)("h2",{id:"deploy-your-application"},"Deploy your application"),Object(r.b)("p",null,"All you have to do now is to navigate to your application and click ",Object(r.b)("strong",{parentName:"p"},"Deploy")," button"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/heroku/heroku-1.png",alt:"Deploy App"})),Object(r.b)("p",null,"That's it. Watch the status and wait till the app is deployed."))),Object(r.b)("p",null,"Congratulations, you have deployed your application!"),Object(r.b)("h2",{id:"live-test"},"Live test"),Object(r.b)("p",null,"To open the application in your browser, click on ",Object(r.b)("strong",{parentName:"p"},"Action")," and ",Object(r.b)("strong",{parentName:"p"},"Open")," buttons in your application overview:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/deploy-env-1.png",alt:"Open App"})),Object(r.b)("p",null,"Then, we can test it with the following CURL commands (replace the app URL with your own):"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="Curl commands to test our deployed API"',title:'"Curl',commands:!0,to:!0,test:!0,our:!0,deployed:!0,'API"':!0}),'# create a tweet\ncurl -X POST -d \'{"message": "This is a tweet"}\' -H "Content-type: application/json" https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets\n\n# list tweets\ncurl https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets\n\n# get a tweet\ncurl https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets/\n\n# list likes from a tweet\ncurl https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets//likes\n\n# add one like to a tweet\ncurl -X POST https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets//likes\n\n# remove one like to a tweet\ncurl -X DELETE https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets//likes\n\n# delete a tweet\ncurl -X DELETE https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets/\n')),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/setting-custom-domain/"}),"add your custom domain"))),Object(r.b)("h2",{id:"whats-next"},"What's next"),Object(r.b)("p",null,"In this first part we saw how to create a Rust API with Actix and Diesel. In the second part we will compare its performance with a Go application to see which one is the most performant."),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Special thanks to ",Object(r.b)("a",Object(n.a)({parentName:"strong"},{href:"https://twitter.com/imjasonmiller"}),"Jason")," and ",Object(r.b)("a",Object(n.a)({parentName:"strong"},{href:"https://twitter.com/doctor_code"}),"Kokou")," for your reviews")),Object(r.b)("h2",{id:"useful-resources"},"Useful resources"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/evoxmusic/twitter-clone-rust"}),"Source code"))),Object(r.b)("p",null,"Do you want to know more about Rust?"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://blog.rust-lang.org/inside-rust/"}),"A great blog to follow along with Rust development")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.youtube.com/channel/UC_iD0xppBwwsrM9DegC5cQQ"}),"Jon Gjengset")," - PhD student at MIT in distributed systems and Rust live-coder"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://doc.rust-lang.org/book/"}),"The Rust programming language book")," (Free)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.youtube.com/watch?v=j_4sadjjWh8"}),"My first service in Rust")," (French video - Fran\xe7ois T.)")),Object(r.b)(u.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}g.isMDXComponent=!0},421:function(e,t,a){"use strict";a(423);var n=a(0),l=a.n(n),r=a(420),i=a.n(r);a(132);t.a=function(e){var t=e.children,a=e.classNames,n=e.fill,r=e.icon,s=e.type,o=null;switch(s){case"danger":o="alert-triangle";break;case"success":o="check-circle";break;case"warning":o="alert-triangle";break;default:o="info"}return l.a.createElement("div",{className:i()(a,"alert","alert--"+s,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&l.a.createElement("i",{className:i()("feather","icon-"+(r||o))}),t)}},425:function(e,t,a){var n=a(28).f,l=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in l||a(10)&&n(l,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var n=a(0),l=a.n(n),r=a(421);t.a=function(e){var t=e.children,a=e.name;return l.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},l.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},427:function(e,t,a){"use strict";var n=a(1),l=a(0),r=a.n(l),i=a(39),s=a(430),o=a(20),c=a.n(o);t.a=function(e){var t,a=e.to,o=e.href,b=a||o,u=Object(s.a)(b),p=Object(l.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(l.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?r.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var a,n;d&&e&&u&&(a=e,n=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:b})):r.a.createElement("a",Object(n.a)({},e,{href:b}))}},429:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=a(427),i=a(420),s=a.n(i);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,i=e.leftIcon,o=e.rightIcon,c=e.size,b=e.target,u=e.to,p=s()("jump-to","jump-to--"+c,a),d=l.a.createElement("div",{className:"jump-to--inner"},l.a.createElement("div",{className:"jump-to--inner-2"},i&&l.a.createElement("div",{className:"jump-to--left"},l.a.createElement("i",{className:"feather icon-"+i})),l.a.createElement("div",{className:"jump-to--main"},n?l.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),l.a.createElement("div",{className:"jump-to--right"},l.a.createElement("i",{className:"feather icon-"+(o||"chevron-right")+" arrow"}))));return b?l.a.createElement("a",{href:u,target:b,className:p},d):l.a.createElement(r.a,{to:u,className:p},d)}},430:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},431:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(420),a(428)),i=a.n(r);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,r=e.hideFeedbackQuestion,s="undefined"!=typeof window?window.location:null,o={title:"Tutorial on "+s+" failed",body:"The tutorial on:\n\n"+s+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},c="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(o),b=Object(n.useState)(null),u=b[0],p=b[1];return l.a.createElement("div",{className:"steps steps--h"+a},t,!r&&!u&&l.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",l.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",l.a.createElement("a",{href:c,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&l.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",l.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},434:function(e,t,a){"use strict";var n=a(1),l=(a(439),a(436),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),i=a(446),s=a(420),o=a.n(s),c=a(428),b=a.n(c),u=a(445),p=37,d=39;function m(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,l=e.className,i=e.handleKeydown,s=e.style,c=e.values,b=e.selectedValue,u=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:o()("tabs",l,{"tabs--block":t}),style:s},c.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:o()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return i(u,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function h(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,l=e.size,s=e.values,o=s;if(o[0].group){var c=_.groupBy(o,"group");o=Object.keys(c).map((function(e){return{label:e,options:c[e]}}))}return r.a.createElement(i.a,{className:"react-select-container react-select--"+l,classNamePrefix:"react-select",options:o,isClearable:a,placeholder:t,value:s.find((function(e){return e.value==a})),onChange:function(e){return n(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,a=e.defaultValue,i=e.groupId,s=e.label,o=e.placeholder,c=e.select,g=e.size,w=(e.style,e.values),O=e.urlKey,j=Object(u.a)(),v=j.tabGroupChoices,f=j.setTabGroupChoices,y=Object(l.useState)(a),k=y[0],N=y[1];if(null!=i){var T=v[i];null!=T&&T!==k&&N(T)}var _=function(e){N(e),null!=i&&f(i,e)},I=[],x=function(e,t,a){switch(a.keyCode){case d:!function(e,t){var a=e.indexOf(t)+1;e[a]?e[a].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var a=e.indexOf(t)-1;e[a]?e[a].focus():e[e.length-1].focus()}(e,t)}};return Object(l.useEffect)((function(){if("undefined"!=typeof window&&window.location&&O){var e=b.a.parse(window.location.search);e[O]&&N(e[O])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(g||"md")},s&&r.a.createElement("div",{className:"margin-vert--sm"},s),w.length>1&&(c?r.a.createElement(h,Object(n.a)({changeSelectedValue:_,handleKeydown:x,placeholder:o,selectedValue:k,size:g,tabRefs:I},e)):r.a.createElement(m,Object(n.a)({changeSelectedValue:_,handleKeydown:x,selectedValue:k,tabRefs:I},e)))),l.Children.toArray(t).filter((function(e){return e.props.value===k}))[0])}},441:function(e,t,a){"use strict";var n=a(0),l=a.n(n);t.a=function(e){return l.a.createElement(l.a.Fragment,null,e.children)}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[231],{383:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return p})),a.d(t,"metadata",(function(){return d})),a.d(t,"rightToc",(function(){return m})),a.d(t,"default",(function(){return g}));var n=a(1),l=a(9),r=(a(0),a(425)),i=a(434),s=a(437),o=a(444),c=a(424),b=a(429),u=a(431),p={last_modified_on:"2023-04-24",$schema:"/.meta/.schemas/guides.json",title:"Create a blazingly fast REST API in Rust (Part 1/2)",description:"How to create a blazingly fast REST API in Rust, with zero-cost abstraction and very low overhead - Part 1/2",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","language: rust"],hide_pagination:!0},d={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Create a blazingly fast REST API in Rust (Part 1/2)",description:"How to create a blazingly fast REST API in Rust, with zero-cost abstraction and very low overhead - Part 1/2",permalink:"/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1",readingTime:"14 min read",source:"@site/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"language: rust",permalink:"/guides/tags/language-rust"}],title:"Create a blazingly fast REST API in Rust (Part 1/2)",truncated:!1,prevItem:{title:"Costs Control",permalink:"/guides/advanced/costs-control"},nextItem:{title:"Create a Playground Environment on AWS",permalink:"/guides/tutorial/create-a-playground-environment-on-aws"}},m=[{value:"Twitter clone",id:"twitter-clone",children:[{value:"API design",id:"api-design",children:[]}]},{value:"Implementation",id:"implementation",children:[{value:"Actix Web",id:"actix-web",children:[]},{value:"Let's code",id:"lets-code",children:[]},{value:"Validation",id:"validation",children:[]}]},{value:"PostgreSQL",id:"postgresql",children:[{value:"Diesel",id:"diesel",children:[]}]},{value:"Deployment",id:"deployment",children:[{value:"Install Qovery CLI",id:"install-qovery-cli",children:[]},{value:"Sign up",id:"sign-up",children:[]},{value:"Deploying the app",id:"deploying-the-app",children:[]},{value:"Create a new project",id:"create-a-new-project",children:[]},{value:"Create a new environment",id:"create-a-new-environment",children:[]},{value:"Create a new application",id:"create-a-new-application",children:[]},{value:"Deploy a database",id:"deploy-a-database",children:[]},{value:"Configure the connection to the database",id:"configure-the-connection-to-the-database",children:[]}]},{value:"Deploy your application",id:"deploy-your-application",children:[]},{value:"Live test",id:"live-test",children:[]},{value:"What's next",id:"whats-next",children:[]},{value:"Useful resources",id:"useful-resources",children:[]}],h={rightToc:m};function g(e){var t=e.components,a=Object(l.a)(e,["components"]);return Object(r.b)("wrapper",Object(n.a)({},h,a,{components:t,mdxType:"MDXLayout"}),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/rust-lang/www.rust-lang.org/issues/419#issuecomment-443418587"}),"Fast, reliable, productive - Pick three")," | Rust's slogan")),Object(r.b)("p",null,"Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety. Coupled with Actix, I should be able to build a fast REST API elegantly."),Object(r.b)("p",null,"The idea behind this article is to see how performant a Rust API can be. I am going to create an API that saves and reads data from/to a PostgreSQL database."),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,'Most of the Rust REST API tests across the web are "',Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://medium.com/sean3z/rest-api-node-vs-rust-c75aa8c96343"}),"Hello World"),"\" applications. They bench direct API I/O with no payload. It's very far from reality. In the part 2 of this article, I will bench our Rust application with an intensive payload.")),Object(r.b)("p",null,"This article is separate in two parts, in this first part you will learn how to:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Create a blazingly fast REST API in Rust"),Object(r.b)("li",{parentName:"ul"},"Connect it to a PostgreSQL database")),Object(r.b)("p",null,"In the second part, we will compare the performance of our application to a Go application."),Object(r.b)("h2",{id:"twitter-clone"},"Twitter clone"),Object(r.b)("blockquote",null,Object(r.b)("p",{parentName:"blockquote"},Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.twitter.com"}),"Twitter"),' is a "microblogging" system that allows people to send and receive short posts called tweets.')),Object(r.b)("p",null,"Let's create a small part of the Twitter API to be able to post, read, and like tweets. The goal is to be able to use our Twitter clone with a massive number of simultaneous fake users."),Object(r.b)(b.a,{mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have installed ",Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/rust-lang/cargo"}),"Cargo")," (Rust package manager)"))),Object(r.b)("h3",{id:"api-design"},"API design"),Object(r.b)("p",null,"Our REST API needs to have three endpoints :"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"/tweets"),Object(r.b)("ul",{parentName:"li"},Object(r.b)("li",{parentName:"ul"},"GET: list last 50 tweets"),Object(r.b)("li",{parentName:"ul"},"POST: create a new tweet"))),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"/tweets/:id"),Object(r.b)("ul",{parentName:"li"},Object(r.b)("li",{parentName:"ul"},"GET: find a tweet by its ID"),Object(r.b)("li",{parentName:"ul"},"DELETE: delete a tweet by its ID"))),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"/tweets/:id/likes"),Object(r.b)("ul",{parentName:"li"},Object(r.b)("li",{parentName:"ul"},"GET: list all likes attached to a tweet"),Object(r.b)("li",{parentName:"ul"},"POST: add +1 like to a tweet"),Object(r.b)("li",{parentName:"ul"},"DELETE: add -1 like to a tweet")))),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"For the sake of simplicity, I will not set up a user management service.")),Object(r.b)("h2",{id:"implementation"},"Implementation"),Object(r.b)("p",null,"Even though implementing an HTTP server could be fun, I choose to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://actix.rs/"}),"Actix"),", which is ranked as ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.techempower.com/benchmarks/#section=data-r18&hw=ph&test=fortune"}),"the most performant framework")," ever by ",Object(r.b)("em",{parentName:"p"},"Techempower"),"."),Object(r.b)("h3",{id:"actix-web"},"Actix Web"),Object(r.b)("p",null,"Actix is an actor framework prevalent in the Rust ecosystem. I am using it as an HTTP server to build our REST API."),Object(r.b)("h3",{id:"lets-code"},"Let's code"),Object(r.b)("p",null,"Three files structured our application."),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"main.rs")," to route HTTP requests to the right endpoint"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"tweet.rs")," to handle requests on /tweets"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"like.rs")," to handle requests on /tweets/:id/likes")),Object(r.b)(s.a,{centered:!1,className:"square",defaultValue:"main.rs",select:!1,size:null,values:[{group:"Files",label:"main.rs",value:"main.rs"},{group:"Files",label:"tweet.rs",value:"tweet.rs"},{group:"Files",label:"like.rs",value:"like.rs"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"main.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="main.rs"',title:'"main.rs"'}),'#[actix_rt::main]\nasync fn main() -> io::Result<()> {\n env::set_var("RUST_LOG", "actix_web=debug,actix_server=info");\n env_logger::init();\n\n HttpServer::new(|| {\n App::new()\n // enable logger - always register actix-web Logger middleware last\n .wrap(middleware::Logger::default())\n // register HTTP requests handlers\n .service(tweet::list)\n .service(tweet::get)\n .service(tweet::create)\n .service(tweet::delete)\n .service(like::list)\n .service(like::plus_one)\n .service(like::minus_one)\n })\n .bind("0.0.0.0:9090")?\n .run()\n .await\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/487198ee7b306f36dbab01f40a44345f85387db2/src/main.rs"}),"main.rs source code"))),Object(r.b)(o.a,{value:"tweet.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="tweet.rs"',title:'"tweet.rs"'}),'pub type Tweets = Response;\n\n#[derive(Debug, Deserialize, Serialize)]\npub struct Tweet {\n pub id: String,\n pub created_at: DateTime,\n pub message: String,\n pub likes: Vec,\n}\n\nimpl Tweet {\n pub fn new(message: String) -> Self {\n Self {\n id: Uuid::new_v4().to_string(),\n created_at: Utc::now(),\n message,\n likes: vec![],\n }\n }\n}\n\n#[derive(Debug, Deserialize, Serialize)]\npub struct TweetRequest {\n pub message: Option,\n}\n\nimpl TweetRequest {\n pub fn to_tweet(&self) -> Option {\n match &self.message {\n Some(message) => Some(Tweet::new(message.to_string())),\n None => None,\n }\n }\n}\n\n/// list 50 last tweets `/tweets`\n#[get("/tweets")]\npub async fn list() -> HttpResponse {\n // TODO find the last 50 tweets and return them\n\n let tweets = Tweets { results: vec![] };\n\n HttpResponse::Ok()\n .content_type(APPLICATION_JSON)\n .json(tweets)\n}\n\n/// create a tweet `/tweets`\n#[post("/tweets")]\npub async fn create(tweet_req: Json) -> HttpResponse {\n HttpResponse::Created()\n .content_type(APPLICATION_JSON)\n .json(tweet_req.to_tweet())\n}\n\n/// find a tweet by its id `/tweets/{id}`\n#[get("/tweets/{id}")]\npub async fn get(path: Path<(String,)>) -> HttpResponse {\n // TODO find tweet a tweet by ID and return it\n let found_tweet: Option = None;\n\n match found_tweet {\n Some(tweet) => HttpResponse::Ok()\n .content_type(APPLICATION_JSON)\n .json(tweet),\n None => HttpResponse::NoContent()\n .content_type(APPLICATION_JSON)\n .await\n .unwrap(),\n }\n}\n\n/// delete a tweet by its id `/tweets/{id}`\n#[delete("/tweets/{id}")]\npub async fn delete(path: Path<(String,)>) -> HttpResponse {\n // TODO delete tweet by ID\n // in any case return status 204\n\n HttpResponse::NoContent()\n .content_type(APPLICATION_JSON)\n .await\n .unwrap()\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/487198ee7b306f36dbab01f40a44345f85387db2/src/tweet.rs"}),"tweet.rs source code"))),Object(r.b)(o.a,{value:"like.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="like.rs"',title:'"like.rs"'}),'pub type Likes = Response;\n\n#[derive(Debug, Deserialize, Serialize)]\npub struct Like {\n pub id: String,\n pub created_at: DateTime,\n}\n\nimpl Like {\n pub fn new() -> Self {\n Self {\n id: Uuid::new_v4().to_string(),\n created_at: Utc::now(),\n }\n }\n}\n\n/// list last 50 likes from a tweet `/tweets/{id}/likes`\n#[get("/tweets/{id}/likes")]\npub async fn list(path: Path<(String,)>) -> HttpResponse {\n // TODO find likes by tweet ID and return them\n let likes = Likes { results: vec![] };\n\n HttpResponse::Ok()\n .content_type(APPLICATION_JSON)\n .json(likes)\n}\n\n/// add one like to a tweet `/tweets/{id}/likes`\n#[post("/tweets/{id}/likes")]\npub async fn plus_one(path: Path<(String,)>) -> HttpResponse {\n // TODO add one like to a tweet\n let like = Like::new();\n\n HttpResponse::Created()\n .content_type(APPLICATION_JSON)\n .json(like)\n}\n\n/// remove one like from a tweet `/tweets/{id}/likes`\n#[delete("/tweets/{id}/likes")]\npub async fn minus_one(path: Path<(String,)>) -> HttpResponse {\n // TODO remove one like to a tweet\n HttpResponse::NoContent()\n .content_type(APPLICATION_JSON)\n .await\n .unwrap()\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/487198ee7b306f36dbab01f40a44345f85387db2/src/like.rs"}),"like.rs source code")))),Object(r.b)("p",null,"With only these three files, our application is ready to receive HTTP requests. In a couple of lines, we have a fully operational application. Actix takes care of the low level boilerplate for us."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="Annotation"',title:'"Annotation"'}),'#[get("/tweets")]\n')),Object(r.b)("p",null,"Annotation is a very convenient way to bind a route to the right path."),Object(r.b)("h3",{id:"validation"},"Validation"),Object(r.b)("p",null,"Let's run our application:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="Run our application"',title:'"Run',our:!0,'application"':!0}),"# Go inside the root project directory\n$ cd twitter-clone-rust\n\n# Run the application\n$ cargo run\n")),Object(r.b)("p",null,"And validate that each endpoint with no errors:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="Curl commands to test our API"',title:'"Curl',commands:!0,to:!0,test:!0,our:!0,'API"':!0}),'# list tweets\ncurl http://localhost:9090/tweets\n\n# get a tweet (return status code: 204 because there is no tweet)\ncurl http://localhost:9090/tweets/abc\n\n# create a tweet\ncurl -X POST -d \'{"message": "This is a tweet"}\' -H "Content-type: application/json" http://localhost:9090/tweets\n\n# delete a tweet (return status code: 204 in any case)\ncurl -X DELETE http://localhost:9090/tweets/abc\n\n# list likes from a tweet\ncurl http://localhost:9090/tweets/abc/likes\n\n# add one like to a tweet\ncurl -X POST http://localhost:9090/tweets/abc/likes\n\n# remove one like to a tweet\ncurl -X DELETE http://localhost:9090/tweets/abc/likes\n')),Object(r.b)("p",null,"At this stage, our application works without any database. Let's go more in-depth and connect it to PostgreSQL."),Object(r.b)("h2",{id:"postgresql"},"PostgreSQL"),Object(r.b)("h3",{id:"diesel"},"Diesel"),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://diesel.rs/"}),"Diesel")," is the most popular ORM in Rust to connect to a ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.postgresql.org"}),"PostgreSQL")," database. Combined with Actix, it's a perfect fit to persist in our data. Let's see how we can make that happen. However, Diesel does not support ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/tokio-rs/tokio"}),"tokio")," (the asynchronous engine behind Actix), so we have to run it in separate threads using the web::block function, which offloads blocking code (like Diesel's) to do not block the server's thread."),Object(r.b)(c.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Read the Diesel ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"http://diesel.rs/guides/getting-started/"}),"Getting started")," to generate tables configurations.")),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="schema.rs"',title:'"schema.rs"'}),"table! {\n likes (id) {\n id -> Uuid,\n created_at -> Timestamp,\n tweet_id -> Uuid,\n }\n}\n\ntable! {\n tweets (id) {\n id -> Uuid,\n created_at -> Timestamp,\n message -> Text,\n }\n}\n\njoinable!(likes -> tweets (tweet_id));\n\nallow_tables_to_appear_in_same_query!(\n likes,\n tweets,\n);\n")),Object(r.b)("p",null,"Diesel uses a macro ",Object(r.b)("inlineCode",{parentName:"p"},"table!...")," and an internal DSL to declare the structure of our tables. There is no magic here. The code is compiled and statically linked at the compilation."),Object(r.b)(s.a,{centered:!1,className:"square",defaultValue:"main.rs",select:!1,size:null,values:[{group:"Files",label:"main.rs",value:"main.rs"},{group:"Files",label:"tweet.rs",value:"tweet.rs"},{group:"Files",label:"like.rs",value:"like.rs"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"main.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="main.rs" {6-11,15-16}',title:'"main.rs"',"{6-11,15-16}":!0}),'#[actix_rt::main]\nasync fn main() -> io::Result<()> {\n env::set_var("RUST_LOG", "actix_web=debug,actix_server=info");\n env_logger::init();\n\n // set up database connection pool\n let database_url = env::var("DATABASE_URL").expect("DATABASE_URL");\n let manager = ConnectionManager::::new(database_url);\n let pool = r2d2::Pool::builder()\n .build(manager)\n .expect("Failed to create pool");\n\n HttpServer::new(move || {\n App::new()\n // Set up DB pool to be used with web::Data extractor\n .data(pool.clone())\n // enable logger - always register actix-web Logger middleware last\n .wrap(middleware::Logger::default())\n // register HTTP requests handlers\n .service(tweet::list)\n .service(tweet::get)\n .service(tweet::create)\n .service(tweet::delete)\n .service(like::list)\n .service(like::plus_one)\n .service(like::minus_one)\n })\n .bind("0.0.0.0:9090")?\n .run()\n .await\n}\n')),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/master/src/main.rs"}),"main.rs source code"))),Object(r.b)(o.a,{value:"tweet.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="tweet.rs"',title:'"tweet.rs"'}),"//...\nfn list_tweets(total_tweets: i64, conn: &DBPooledConnection) -> Result {\n use crate::schema::tweets::dsl::*;\n\n let _tweets = match tweets\n .order(created_at.desc())\n .limit(total_tweets)\n .load::(conn)\n {\n Ok(tws) => tws,\n Err(_) => vec![],\n };\n\n Ok(Tweets {\n results: _tweets\n .into_iter()\n .map(|t| t.to_tweet())\n .collect::>(),\n })\n}\n\nfn find_tweet(_id: Uuid, conn: &DBPooledConnection) -> Result {\n use crate::schema::tweets::dsl::*;\n\n let res = tweets.filter(id.eq(_id)).load::(conn);\n match res {\n Ok(tweets_db) => match tweets_db.first() {\n Some(tweet_db) => Ok(tweet_db.to_tweet()),\n _ => Err(Error::NotFound),\n },\n Err(err) => Err(err),\n }\n}\n\nfn create_tweet(tweet: Tweet, conn: &DBPooledConnection) -> Result {\n use crate::schema::tweets::dsl::*;\n\n let tweet_db = tweet.to_tweet_db();\n let _ = diesel::insert_into(tweets).values(&tweet_db).execute(conn);\n\n Ok(tweet_db.to_tweet())\n}\n\nfn delete_tweet(_id: Uuid, conn: &DBPooledConnection) -> Result<(), Error> {\n use crate::schema::tweets::dsl::*;\n\n let res = diesel::delete(tweets.filter(id.eq(_id))).execute(conn);\n match res {\n Ok(_) => Ok(()),\n Err(err) => Err(err),\n }\n}\n//...\n")),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/master/src/tweet.rs"}),"tweet.rs source code"))),Object(r.b)(o.a,{value:"like.rs",mdxType:"TabItem"},Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-rust",metastring:'title="like.rs"',title:'"like.rs"'}),"//...\npub fn list_likes(_tweet_id: Uuid, conn: &DBPooledConnection) -> Result {\n use crate::schema::likes::dsl::*;\n\n let _likes: Vec = match likes\n .filter(tweet_id.eq(_tweet_id))\n .order(created_at.desc())\n .load::(conn)\n {\n Ok(lks) => lks,\n Err(_) => vec![],\n };\n\n Ok(Likes {\n results: _likes\n .into_iter()\n .map(|l| l.to_like())\n .collect::>(),\n })\n}\n\npub fn create_like(_tweet_id: Uuid, conn: &DBPooledConnection) -> Result {\n use crate::schema::likes::dsl::*;\n\n let like = Like::new();\n let _ = diesel::insert_into(likes)\n .values(like.to_like_db(_tweet_id))\n .execute(conn);\n\n Ok(like)\n}\n\npub fn delete_like(_tweet_id: Uuid, conn: &DBPooledConnection) -> Result<(), Error> {\n use crate::schema::likes::dsl::*;\n\n let _likes = list_likes(_tweet_id, conn);\n\n let like = match &_likes {\n Ok(_likes) if !_likes.results.is_empty() => _likes.results.first(),\n _ => None,\n };\n\n if like.is_none() {\n return Ok(());\n }\n\n let like_id = Uuid::from_str(like.unwrap().id.as_str()).unwrap();\n\n let res = diesel::delete(likes.filter(id.eq(like_id))).execute(conn);\n match res {\n Ok(_) => Ok(()),\n Err(err) => Err(err),\n }\n}\n//...\n")),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/evoxmusic/twitter-clone-rust/blob/master/src/like.rs"}),"like.rs source code")))),Object(r.b)("h2",{id:"deployment"},"Deployment"),Object(r.b)("p",null,"Qovery is going to help you to deploy your application in a few seconds. Let's deploy our Twitter Clone now."),Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"web",placeholder:"Select your interface",select:!1,size:null,values:[{group:"Interfaces",label:"Web",value:"web"},{group:"Interfaces",label:"CLI",value:"cli"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"web",mdxType:"TabItem"},Object(r.b)("li",null,Object(r.b)("p",null,"Sign in to the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web interface"),"."),Object(r.b)("p",{align:"center"},Object(r.b)("a",{href:"https://onboarding.qovery.com/"},Object(r.b)("img",{src:"/img/Qovery_Sign_Up_Page.jpg",alt:"Qovery Sign-up page"}))))),Object(r.b)(o.a,{value:"cli",mdxType:"TabItem"},Object(r.b)("li",null,Object(r.b)("h3",{id:"install-qovery-cli"},"Install Qovery CLI"),Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"linux",placeholder:"Select your OS",select:!1,size:null,values:[{group:"Platforms",label:"Linux",value:"linux"},{group:"Platforms",label:"MacOS",value:"macos"},{group:"Platforms",label:"Windows",value:"windows"},{group:"Platforms",label:"Docker",value:"docker"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"linux",mdxType:"TabItem"},Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"universal",values:[{label:"*nix",value:"universal"},{label:"Arch Linux",value:"arch"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"universal",mdxType:"TabItem"},Object(r.b)("p",null,"To download and install Qovery CLI on any Linux distribution:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(r.b)(o.a,{value:"arch",mdxType:"TabItem"},Object(r.b)("p",null,"Qovery is part of ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(r.b)(o.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Linux manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(r.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(r.b)(o.a,{value:"macos",mdxType:"TabItem"},Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"homebrew",values:[{label:"Homebrew",value:"homebrew"},{label:"Script",value:"script"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"homebrew",mdxType:"TabItem"},Object(r.b)("p",null,"The common solution to install a command line binary on the MacOS is to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery brew repository\n$ brew tap Qovery/qovery-cli\n\n# Install the CLI\n$ brew install qovery-cli\n"))),Object(r.b)(o.a,{value:"script",mdxType:"TabItem"},Object(r.b)("p",null,"To download and install Qovery CLI from the command line:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(r.b)(o.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Mac OS manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(r.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(r.b)(o.a,{value:"windows",mdxType:"TabItem"},Object(r.b)(s.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(r.b)(o.a,{value:"scoop",mdxType:"TabItem"},Object(r.b)("p",null,"The classic way to install binaries on Windows is to use ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery bucket\n$ scoop bucket add qovery https://github.com/Qovery/scoop-qovery-cli\n\n# Install the CLI\n$ scoop install qovery-cli\n"))),Object(r.b)(o.a,{value:"manual",mdxType:"TabItem"},Object(r.b)("p",null,"Install the Qovery CLI on Windows manually by downloading the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to\n",Object(r.b)("inlineCode",{parentName:"p"},"C:\\Windows"),".")))),Object(r.b)(o.a,{value:"docker",mdxType:"TabItem"},Object(r.b)("p",null,"Install Docker on your local machine and run the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Pull and Run the latest Qovery CLI\n$ docker run ghcr.io/qovery/qovery-cli:latest help\n")),Object(r.b)("p",null,"Change ",Object(r.b)("inlineCode",{parentName:"p"},"latest")," by the version you want to use. For example, to use the version 0.58.4, run:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ docker run ghcr.io/qovery/qovery-cli:0.58.4 help\n")),Object(r.b)("p",null,"Note: ",Object(r.b)("inlineCode",{parentName:"p"},"ghcr.io")," is the ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/pkgs/container/qovery-cli"}),"GitHub Container Registry"),".")))),Object(r.b)("li",null,Object(r.b)("h3",{id:"sign-up"},"Sign up"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"If you are using an environment without access to GUI or a browser, you can use headless authentication instead:"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth --headless\n"))),Object(r.b)("p",null,"Your browser window with sign-in options will open."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/qovery_signup.svg",alt:"Qovery Sign-up page"})),Object(r.b)("p",null,Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"https://github.com/apps/qovery/installations/new"}),"Click here")," to authorize Qovery to clone and build your applications."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/github_signup.svg",alt:"Connect Github"})),Object(r.b)("p",null,"Congratulations, you are logged-in.")))),Object(r.b)("h3",{id:"deploying-the-app"},"Deploying the app"),Object(r.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,Object(r.b)("h3",{id:"create-a-new-project"},"Create a new project"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/heroku/heroku-2.png",alt:"Migrate from Heroku"}))),Object(r.b)("li",null,Object(r.b)("h3",{id:"create-a-new-environment"},"Create a new environment"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/heroku/heroku-3.png",alt:"Migrate from Heroku"}))),Object(r.b)("li",null,Object(r.b)("h3",{id:"create-a-new-application"},"Create a new application"),Object(r.b)("p",null,"To follow the guide, ",Object(r.b)("a",{href:"https://github.com/evoxmusic/twitter-clone-rust"},"you can fork and use our repository")),Object(r.b)("p",null,"Use the forked repository (and branch ",Object(r.b)("strong",{parentName:"p"},"master"),") while creating the application in the repository field:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/rust/rust.png",alt:"Migrate from Heroku"}))),Object(r.b)("li",null,Object(r.b)("p",null,"After the application is created: "),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Navigate application settings"),Object(r.b)("li",{parentName:"ul"},"Select ",Object(r.b)("strong",{parentName:"li"},"Port")),Object(r.b)("li",{parentName:"ul"},"Add port ",Object(r.b)("strong",{parentName:"li"},"9090"))),Object(r.b)("p",{align:"left"},Object(r.b)("img",{src:"/img/micro/micros-1.png",alt:"Microservices"}))),Object(r.b)("li",null,Object(r.b)("h3",{id:"deploy-a-database"},"Deploy a database"),Object(r.b)("p",null,"Create and deploy a new database"),Object(r.b)(c.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Name the database ",Object(r.b)("strong",{parentName:"p"},"my-pql-db")," to follow the guide flawlessly")),Object(r.b)("p",null,"To learn how to do it, you can ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"follow this guide"))),Object(r.b)("li",null,Object(r.b)("h3",{id:"configure-the-connection-to-the-database"},"Configure the connection to the database"),Object(r.b)("p",null,"In application overview, open the ",Object(r.b)("strong",{parentName:"p"},"Variables")," tab"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/open-env-var.png",alt:"Open Variable"})),Object(r.b)("p",null,"Configure the alias for each built_in environment variable to match the one required within your code"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/alias.png",alt:"Env Var Alias"})),Object(r.b)("p",null,"Have a look at ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-a-database"}),"this section")," to know more on how to connect to a database.")),Object(r.b)("h2",{id:"deploy-your-application"},"Deploy your application"),Object(r.b)("p",null,"All you have to do now is to navigate to your application and click ",Object(r.b)("strong",{parentName:"p"},"Deploy")," button"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/heroku/heroku-1.png",alt:"Deploy App"})),Object(r.b)("p",null,"That's it. Watch the status and wait till the app is deployed."))),Object(r.b)("p",null,"Congratulations, you have deployed your application!"),Object(r.b)("h2",{id:"live-test"},"Live test"),Object(r.b)("p",null,"To open the application in your browser, click on ",Object(r.b)("strong",{parentName:"p"},"Action")," and ",Object(r.b)("strong",{parentName:"p"},"Open")," buttons in your application overview:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/deploy-env-1.png",alt:"Open App"})),Object(r.b)("p",null,"Then, we can test it with the following CURL commands (replace the app URL with your own):"),Object(r.b)("pre",null,Object(r.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash",metastring:'title="Curl commands to test our deployed API"',title:'"Curl',commands:!0,to:!0,test:!0,our:!0,deployed:!0,'API"':!0}),'# create a tweet\ncurl -X POST -d \'{"message": "This is a tweet"}\' -H "Content-type: application/json" https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets\n\n# list tweets\ncurl https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets\n\n# get a tweet\ncurl https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets/\n\n# list likes from a tweet\ncurl https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets//likes\n\n# add one like to a tweet\ncurl -X POST https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets//likes\n\n# remove one like to a tweet\ncurl -X DELETE https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets//likes\n\n# delete a tweet\ncurl -X DELETE https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets/\n')),Object(r.b)(c.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can ",Object(r.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/setting-custom-domain/"}),"add your custom domain"))),Object(r.b)("h2",{id:"whats-next"},"What's next"),Object(r.b)("p",null,"In this first part we saw how to create a Rust API with Actix and Diesel. In the second part we will compare its performance with a Go application to see which one is the most performant."),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Special thanks to ",Object(r.b)("a",Object(n.a)({parentName:"strong"},{href:"https://twitter.com/imjasonmiller"}),"Jason")," and ",Object(r.b)("a",Object(n.a)({parentName:"strong"},{href:"https://twitter.com/doctor_code"}),"Kokou")," for your reviews")),Object(r.b)("h2",{id:"useful-resources"},"Useful resources"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/evoxmusic/twitter-clone-rust"}),"Source code"))),Object(r.b)("p",null,"Do you want to know more about Rust?"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://blog.rust-lang.org/inside-rust/"}),"A great blog to follow along with Rust development")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.youtube.com/channel/UC_iD0xppBwwsrM9DegC5cQQ"}),"Jon Gjengset")," - PhD student at MIT in distributed systems and Rust live-coder"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://doc.rust-lang.org/book/"}),"The Rust programming language book")," (Free)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.youtube.com/watch?v=j_4sadjjWh8"}),"My first service in Rust")," (French video - Fran\xe7ois T.)")),Object(r.b)(u.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}g.isMDXComponent=!0},424:function(e,t,a){"use strict";a(426);var n=a(0),l=a.n(n),r=a(423),i=a.n(r);a(132);t.a=function(e){var t=e.children,a=e.classNames,n=e.fill,r=e.icon,s=e.type,o=null;switch(s){case"danger":o="alert-triangle";break;case"success":o="check-circle";break;case"warning":o="alert-triangle";break;default:o="info"}return l.a.createElement("div",{className:i()(a,"alert","alert--"+s,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&l.a.createElement("i",{className:i()("feather","icon-"+(r||o))}),t)}},428:function(e,t,a){var n=a(28).f,l=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in l||a(10)&&n(l,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var n=a(0),l=a.n(n),r=a(424);t.a=function(e){var t=e.children,a=e.name;return l.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},l.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},430:function(e,t,a){"use strict";var n=a(1),l=a(0),r=a.n(l),i=a(39),s=a(432),o=a(20),c=a.n(o);t.a=function(e){var t,a=e.to,o=e.href,b=a||o,u=Object(s.a)(b),p=Object(l.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(l.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?r.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var a,n;d&&e&&u&&(a=e,n=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:b})):r.a.createElement("a",Object(n.a)({},e,{href:b}))}},431:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=a(430),i=a(423),s=a.n(i);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,i=e.leftIcon,o=e.rightIcon,c=e.size,b=e.target,u=e.to,p=s()("jump-to","jump-to--"+c,a),d=l.a.createElement("div",{className:"jump-to--inner"},l.a.createElement("div",{className:"jump-to--inner-2"},i&&l.a.createElement("div",{className:"jump-to--left"},l.a.createElement("i",{className:"feather icon-"+i})),l.a.createElement("div",{className:"jump-to--main"},n?l.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),l.a.createElement("div",{className:"jump-to--right"},l.a.createElement("i",{className:"feather icon-"+(o||"chevron-right")+" arrow"}))));return b?l.a.createElement("a",{href:u,target:b,className:p},d):l.a.createElement(r.a,{to:u,className:p},d)}},432:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},434:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(423),a(433)),i=a.n(r);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,r=e.hideFeedbackQuestion,s="undefined"!=typeof window?window.location:null,o={title:"Tutorial on "+s+" failed",body:"The tutorial on:\n\n"+s+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},c="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(o),b=Object(n.useState)(null),u=b[0],p=b[1];return l.a.createElement("div",{className:"steps steps--h"+a},t,!r&&!u&&l.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",l.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",l.a.createElement("a",{href:c,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&l.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",l.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},437:function(e,t,a){"use strict";var n=a(1),l=(a(442),a(439),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),i=a(449),s=a(423),o=a.n(s),c=a(433),b=a.n(c),u=a(448),p=37,d=39;function m(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,l=e.className,i=e.handleKeydown,s=e.style,c=e.values,b=e.selectedValue,u=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:o()("tabs",l,{"tabs--block":t}),style:s},c.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:o()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return i(u,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function h(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,l=e.size,s=e.values,o=s;if(o[0].group){var c=_.groupBy(o,"group");o=Object.keys(c).map((function(e){return{label:e,options:c[e]}}))}return r.a.createElement(i.a,{className:"react-select-container react-select--"+l,classNamePrefix:"react-select",options:o,isClearable:a,placeholder:t,value:s.find((function(e){return e.value==a})),onChange:function(e){return n(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,a=e.defaultValue,i=e.groupId,s=e.label,o=e.placeholder,c=e.select,g=e.size,w=(e.style,e.values),O=e.urlKey,j=Object(u.a)(),v=j.tabGroupChoices,f=j.setTabGroupChoices,y=Object(l.useState)(a),k=y[0],N=y[1];if(null!=i){var T=v[i];null!=T&&T!==k&&N(T)}var _=function(e){N(e),null!=i&&f(i,e)},I=[],x=function(e,t,a){switch(a.keyCode){case d:!function(e,t){var a=e.indexOf(t)+1;e[a]?e[a].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var a=e.indexOf(t)-1;e[a]?e[a].focus():e[e.length-1].focus()}(e,t)}};return Object(l.useEffect)((function(){if("undefined"!=typeof window&&window.location&&O){var e=b.a.parse(window.location.search);e[O]&&N(e[O])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(g||"md")},s&&r.a.createElement("div",{className:"margin-vert--sm"},s),w.length>1&&(c?r.a.createElement(h,Object(n.a)({changeSelectedValue:_,handleKeydown:x,placeholder:o,selectedValue:k,size:g,tabRefs:I},e)):r.a.createElement(m,Object(n.a)({changeSelectedValue:_,handleKeydown:x,selectedValue:k,tabRefs:I},e)))),l.Children.toArray(t).filter((function(e){return e.props.value===k}))[0])}},444:function(e,t,a){"use strict";var n=a(0),l=a.n(n);t.a=function(e){return l.a.createElement(l.a.Fragment,null,e.children)}}}]); \ No newline at end of file diff --git a/db96bb7d.df1d14cf.js b/db96bb7d.ae36dcb6.js similarity index 95% rename from db96bb7d.df1d14cf.js rename to db96bb7d.ae36dcb6.js index 8b7fad9716..95a6cb1839 100644 --- a/db96bb7d.df1d14cf.js +++ b/db96bb7d.ae36dcb6.js @@ -1,2 +1,2 @@ -/*! For license information please see db96bb7d.df1d14cf.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[229],{381:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return b}));var r=n(1),o=n(9),a=(n(0),n(422)),i=n(421),l=n(431),c={last_modified_on:"2023-09-27",title:"Deployment Rule",description:"Learn how to configure the lifecycle of your Environments"},u={id:"using-qovery/configuration/deployment-rule",title:"Deployment Rule",description:"Learn how to configure the lifecycle of your Environments",source:"@site/docs/using-qovery/configuration/deployment-rule.md",permalink:"/docs/using-qovery/configuration/deployment-rule",sidebar:"docs",previous:{title:"Object Storage",permalink:"/docs/using-qovery/configuration/object-storage"},next:{title:"User Account",permalink:"/docs/using-qovery/configuration/user-account"}},s=[{value:"Why using Deployment Rule?",id:"why-using-deployment-rule",children:[{value:"Cloud cost optimization",id:"cloud-cost-optimization",children:[]},{value:"Time optimization",id:"time-optimization",children:[]},{value:"Examples",id:"examples",children:[]}]},{value:"Rule Levels",id:"rule-levels",children:[]},{value:"Project Deployment Rules",id:"project-deployment-rules",children:[{value:"Project Rules Configuration",id:"project-rules-configuration",children:[]},{value:"Matching rule definition",id:"matching-rule-definition",children:[]},{value:"Setup to apply - General",id:"setup-to-apply---general",children:[]},{value:"Setup to apply - Start & stop",id:"setup-to-apply---start--stop",children:[]},{value:"Rules priority",id:"rules-priority",children:[]}]},{value:"Environment Deployment Rules",id:"environment-deployment-rules",children:[]}],p={rightToc:s};function b(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"A ",Object(a.b)("strong",{parentName:"p"},"Deployment Rules")," lets you configure the lifecycle of your ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environments"),"."),Object(a.b)("h2",{id:"why-using-deployment-rule"},"Why using Deployment Rule?"),Object(a.b)("h3",{id:"cloud-cost-optimization"},"Cloud cost optimization"),Object(a.b)("p",null,"Using the Deployment Rules is a good practice to drastically ",Object(a.b)("strong",{parentName:"p"},"reduce your cost"),". Indeed, Qovery knows how to optimize your Cloud resources\nwhen your applications are not running. Then you can expect to reduce your Cloud cost up to 60% by using the ",Object(a.b)("strong",{parentName:"p"},"Deployment Rules"),"."),Object(a.b)("h3",{id:"time-optimization"},"Time optimization"),Object(a.b)("p",null,"Configuring your environments, managing, starting, shutting down all takes valuable time from your developers. Deployment Rules allow you\nto declaratively set up how your resources should be used, let Qovery do the dirty job, allowing your employees to focus on important things."),Object(a.b)("h3",{id:"examples"},"Examples"),Object(a.b)("h4",{id:"shutting-down-environments"},"Shutting down environments"),Object(a.b)("p",null,"Developers in your company work from 9-to-5, five days a week. During the weekend, at night, and of the working hours, keeping all development environments running\nmay be a huge expense that gives you no benefits. "),Object(a.b)("p",null,"Deployment Rules address this problem very effectively - all you need to do is to define when you need your environments to be running,\nand let us handle the rest. Qovery will start and stop your services for you to make sure your cloud spending is optimized and wise."),Object(a.b)("h4",{id:"using-cheaper-cloud-providers"},"Using cheaper cloud providers"),Object(a.b)("p",null,"Running your development environments on expensive cloud providers might not be the best way to spend your money. Deployment Rules allow you to deploy\nyour development environments to a cheaper cloud account while still keeping your production using the most reliable services provided by the more expensive cloud provider."),Object(a.b)("h2",{id:"rule-levels"},"Rule Levels"),Object(a.b)("p",null,"You can set up your Rules at ",Object(a.b)("strong",{parentName:"p"},"Project")," and ",Object(a.b)("strong",{parentName:"p"},"Environment")," levels. Rules set up at the Project level will be automatically applied to ",Object(a.b)("strong",{parentName:"p"},"newly created")," Environments you target in the rule.\nIf, however, the default settings applied by the Project level rule does not meet your needs, you are allowed to override the settings at the Environment level later on."),Object(a.b)("h2",{id:"project-deployment-rules"},"Project Deployment Rules"),Object(a.b)("p",null,"Declaring deployment rules at the project level allows you to apply reasonable defaults to all newly created environments. After a new environment within a project is created, rules from the Project are applied to the Environment. However, to keep things flexible, Qovery allows you to override the rules after environment creation at the Environment level, in Environment settings."),Object(a.b)("h3",{id:"project-rules-configuration"},"Project Rules Configuration"),Object(a.b)(l.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Navigate to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(a.b)("li",null,Object(a.b)("p",null,"Select your project")),Object(a.b)("li",null,Object(a.b)("p",null,"In the environment list, select the tab ",Object(a.b)("strong",{parentName:"p"},"Deployment Rule")," and click ",Object(a.b)("strong",{parentName:"p"},"Add Rule")," button:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/deployment_rule/deployment_rules_project.png",alt:"Deployment Rules Project"}))),Object(a.b)("li",null,Object(a.b)("h3",{id:"matching-rule-definition"},"Matching rule definition"),Object(a.b)("p",null,"You will have to provide a rule name, description and a ",Object(a.b)("strong",{parentName:"p"},"matching condition"),"."),Object(a.b)("h4",{id:"matching-condition---environment-name"},"Matching Condition - Environment Name"),Object(a.b)("p",null,"This field allows you to specify which environments should be affected by the given deployment rule, based on their name."),Object(a.b)("p",null,"You can either enter the full environment name or use ",Object(a.b)("strong",{parentName:"p"},"Wildcards"),"."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Wildcards")),Object(a.b)("p",null,"Wildcards allows you to build regular expression to match the name of the environments you want your deployment rule to target. "),Object(a.b)("p",null,"You can use the following characters to specify your rule."),Object(a.b)("table",null,Object(a.b)("thead",{parentName:"table"},Object(a.b)("tr",{parentName:"thead"},Object(a.b)("th",Object(r.a)({parentName:"tr"},{align:"center"}),"wildcard"),Object(a.b)("th",Object(r.a)({parentName:"tr"},{align:"center"}),"behavior"),Object(a.b)("th",Object(r.a)({parentName:"tr"},{align:"center"}),"will match"))),Object(a.b)("tbody",{parentName:"table"},Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"?"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"Any one character"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"A", "B", "c", "z", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"??"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"Any two characters"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"AA", "AZ", "zz", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"???"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"Any three characters"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"Jet", "AAA", "ccc", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"*"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"Any characters"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"apple", "APPLE", "A100", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"*th"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'Ends in "th"'),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"bath", "fourth", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"c*"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'Starts with "c"'),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"Cat", "CAB", "cindy", "candy", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"?*"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"At least one character"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"a", "b", "ab", "ABCD", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"???-??"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"5 characters with hypen"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"ABC-99","100-ZT", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),Object(a.b)("em",{parentName:"td"},"xyz")),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'Contains "xyz"'),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"code is XYZ", "100-XYZ", "XyZ90", etc.')))),Object(a.b)("p",null,"For example, the rule ",Object(a.b)("inlineCode",{parentName:"p"},"Prod_Env_*")," will target the environment named:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("inlineCode",{parentName:"li"},"Prod_Env_1")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("inlineCode",{parentName:"li"},"Prod_Env_feature"))),Object(a.b)("p",null,"But will not target the environment named: ",Object(a.b)("inlineCode",{parentName:"p"},"Staging_Env_1")),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,'If you want to apply a rule to the preview envirionments, use the rule "',"[PR]",'*" (since every preview environment name will start with "',"[PR]",'")')),Object(a.b)("h3",{id:"setup-to-apply---general"},"Setup to apply - General"),Object(a.b)("h4",{id:"mode"},"Mode"),Object(a.b)("p",null,"Selecting Mode allows you to labelize the environment. "),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"To learn more about the environment modes, take a look to the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"docs.using-qovery.configuration.environment#type-of-environment"}),"Type of environments")," section.")),Object(a.b)("h4",{id:"cluster"},"Cluster"),Object(a.b)("p",null,"Selecting the cluster allows you to control to which cluster your environments in the project will be deployed to."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Example use cases")),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"deploy your development environments on a more cost effective cluster"),Object(a.b)("li",{parentName:"ul"},"deploy your environments in multiple regions")),Object(a.b)("h3",{id:"setup-to-apply---start--stop"},"Setup to apply - Start & stop"),Object(a.b)("h4",{id:"start--stop"},"Start & Stop"),Object(a.b)("p",null,"The start and stop section allow you to precisely set up when the environments inside the project should be deployed and cleaned up."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Use cases examples")),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"shut down your development environments during the weekend"),Object(a.b)("li",{parentName:"ul"},"deploy additional environments during peak hours")),Object(a.b)("br",null)))),Object(a.b)("h3",{id:"rules-priority"},"Rules priority"),Object(a.b)("p",null,"Since you can define several rules, it is possible that an environment is targeted by more than one of them.\nIn order to define which rule applies first to your new environments, you can reorder the list of rules in the deployment setting window.\nStarting from the top, the rules are ranked from highest to lowest priority. "),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/deployment_rule/ordering_deployment_rule.png",alt:"Reorder priority rules"})),Object(a.b)("h2",{id:"environment-deployment-rules"},"Environment Deployment Rules"),Object(a.b)("p",null,"Setting up Deployment Rules at the Enviornment level allows you to make all necessary adjustments applied by your default rules from the Project level."),Object(a.b)("p",null,"Have a look at ","[this section]","[docs.using-qovery.configuration.environment#deployment-rule]","] to know more."))}b.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},p=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return n?o.a.createElement(m,l({ref:t},u,{components:n})):o.a.createElement(m,l({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:r,i[1]=l;for(var u=2;u1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,u=void 0===c?n:o(c,n);u>l;)t[l++]=e;return t}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,c={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(c),s=Object(r.useState)(null),p=s[0],b=s[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see db96bb7d.ae36dcb6.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[232],{384:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return b}));var r=n(1),o=n(9),a=(n(0),n(425)),i=n(424),l=n(434),c={last_modified_on:"2023-09-27",title:"Deployment Rule",description:"Learn how to configure the lifecycle of your Environments"},u={id:"using-qovery/configuration/deployment-rule",title:"Deployment Rule",description:"Learn how to configure the lifecycle of your Environments",source:"@site/docs/using-qovery/configuration/deployment-rule.md",permalink:"/docs/using-qovery/configuration/deployment-rule",sidebar:"docs",previous:{title:"Object Storage",permalink:"/docs/using-qovery/configuration/object-storage"},next:{title:"User Account",permalink:"/docs/using-qovery/configuration/user-account"}},s=[{value:"Why using Deployment Rule?",id:"why-using-deployment-rule",children:[{value:"Cloud cost optimization",id:"cloud-cost-optimization",children:[]},{value:"Time optimization",id:"time-optimization",children:[]},{value:"Examples",id:"examples",children:[]}]},{value:"Rule Levels",id:"rule-levels",children:[]},{value:"Project Deployment Rules",id:"project-deployment-rules",children:[{value:"Project Rules Configuration",id:"project-rules-configuration",children:[]},{value:"Matching rule definition",id:"matching-rule-definition",children:[]},{value:"Setup to apply - General",id:"setup-to-apply---general",children:[]},{value:"Setup to apply - Start & stop",id:"setup-to-apply---start--stop",children:[]},{value:"Rules priority",id:"rules-priority",children:[]}]},{value:"Environment Deployment Rules",id:"environment-deployment-rules",children:[]}],p={rightToc:s};function b(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"A ",Object(a.b)("strong",{parentName:"p"},"Deployment Rules")," lets you configure the lifecycle of your ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environments"),"."),Object(a.b)("h2",{id:"why-using-deployment-rule"},"Why using Deployment Rule?"),Object(a.b)("h3",{id:"cloud-cost-optimization"},"Cloud cost optimization"),Object(a.b)("p",null,"Using the Deployment Rules is a good practice to drastically ",Object(a.b)("strong",{parentName:"p"},"reduce your cost"),". Indeed, Qovery knows how to optimize your Cloud resources\nwhen your applications are not running. Then you can expect to reduce your Cloud cost up to 60% by using the ",Object(a.b)("strong",{parentName:"p"},"Deployment Rules"),"."),Object(a.b)("h3",{id:"time-optimization"},"Time optimization"),Object(a.b)("p",null,"Configuring your environments, managing, starting, shutting down all takes valuable time from your developers. Deployment Rules allow you\nto declaratively set up how your resources should be used, let Qovery do the dirty job, allowing your employees to focus on important things."),Object(a.b)("h3",{id:"examples"},"Examples"),Object(a.b)("h4",{id:"shutting-down-environments"},"Shutting down environments"),Object(a.b)("p",null,"Developers in your company work from 9-to-5, five days a week. During the weekend, at night, and of the working hours, keeping all development environments running\nmay be a huge expense that gives you no benefits. "),Object(a.b)("p",null,"Deployment Rules address this problem very effectively - all you need to do is to define when you need your environments to be running,\nand let us handle the rest. Qovery will start and stop your services for you to make sure your cloud spending is optimized and wise."),Object(a.b)("h4",{id:"using-cheaper-cloud-providers"},"Using cheaper cloud providers"),Object(a.b)("p",null,"Running your development environments on expensive cloud providers might not be the best way to spend your money. Deployment Rules allow you to deploy\nyour development environments to a cheaper cloud account while still keeping your production using the most reliable services provided by the more expensive cloud provider."),Object(a.b)("h2",{id:"rule-levels"},"Rule Levels"),Object(a.b)("p",null,"You can set up your Rules at ",Object(a.b)("strong",{parentName:"p"},"Project")," and ",Object(a.b)("strong",{parentName:"p"},"Environment")," levels. Rules set up at the Project level will be automatically applied to ",Object(a.b)("strong",{parentName:"p"},"newly created")," Environments you target in the rule.\nIf, however, the default settings applied by the Project level rule does not meet your needs, you are allowed to override the settings at the Environment level later on."),Object(a.b)("h2",{id:"project-deployment-rules"},"Project Deployment Rules"),Object(a.b)("p",null,"Declaring deployment rules at the project level allows you to apply reasonable defaults to all newly created environments. After a new environment within a project is created, rules from the Project are applied to the Environment. However, to keep things flexible, Qovery allows you to override the rules after environment creation at the Environment level, in Environment settings."),Object(a.b)("h3",{id:"project-rules-configuration"},"Project Rules Configuration"),Object(a.b)(l.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Navigate to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(a.b)("li",null,Object(a.b)("p",null,"Select your project")),Object(a.b)("li",null,Object(a.b)("p",null,"In the environment list, select the tab ",Object(a.b)("strong",{parentName:"p"},"Deployment Rule")," and click ",Object(a.b)("strong",{parentName:"p"},"Add Rule")," button:"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/deployment_rule/deployment_rules_project.png",alt:"Deployment Rules Project"}))),Object(a.b)("li",null,Object(a.b)("h3",{id:"matching-rule-definition"},"Matching rule definition"),Object(a.b)("p",null,"You will have to provide a rule name, description and a ",Object(a.b)("strong",{parentName:"p"},"matching condition"),"."),Object(a.b)("h4",{id:"matching-condition---environment-name"},"Matching Condition - Environment Name"),Object(a.b)("p",null,"This field allows you to specify which environments should be affected by the given deployment rule, based on their name."),Object(a.b)("p",null,"You can either enter the full environment name or use ",Object(a.b)("strong",{parentName:"p"},"Wildcards"),"."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Wildcards")),Object(a.b)("p",null,"Wildcards allows you to build regular expression to match the name of the environments you want your deployment rule to target. "),Object(a.b)("p",null,"You can use the following characters to specify your rule."),Object(a.b)("table",null,Object(a.b)("thead",{parentName:"table"},Object(a.b)("tr",{parentName:"thead"},Object(a.b)("th",Object(r.a)({parentName:"tr"},{align:"center"}),"wildcard"),Object(a.b)("th",Object(r.a)({parentName:"tr"},{align:"center"}),"behavior"),Object(a.b)("th",Object(r.a)({parentName:"tr"},{align:"center"}),"will match"))),Object(a.b)("tbody",{parentName:"table"},Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"?"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"Any one character"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"A", "B", "c", "z", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"??"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"Any two characters"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"AA", "AZ", "zz", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"???"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"Any three characters"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"Jet", "AAA", "ccc", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"*"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"Any characters"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"apple", "APPLE", "A100", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"*th"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'Ends in "th"'),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"bath", "fourth", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"c*"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'Starts with "c"'),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"Cat", "CAB", "cindy", "candy", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"?*"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"At least one character"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"a", "b", "ab", "ABCD", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"???-??"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),"5 characters with hypen"),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"ABC-99","100-ZT", etc.')),Object(a.b)("tr",{parentName:"tbody"},Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),Object(a.b)("em",{parentName:"td"},"xyz")),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'Contains "xyz"'),Object(a.b)("td",Object(r.a)({parentName:"tr"},{align:"center"}),'"code is XYZ", "100-XYZ", "XyZ90", etc.')))),Object(a.b)("p",null,"For example, the rule ",Object(a.b)("inlineCode",{parentName:"p"},"Prod_Env_*")," will target the environment named:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("inlineCode",{parentName:"li"},"Prod_Env_1")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("inlineCode",{parentName:"li"},"Prod_Env_feature"))),Object(a.b)("p",null,"But will not target the environment named: ",Object(a.b)("inlineCode",{parentName:"p"},"Staging_Env_1")),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,'If you want to apply a rule to the preview envirionments, use the rule "',"[PR]",'*" (since every preview environment name will start with "',"[PR]",'")')),Object(a.b)("h3",{id:"setup-to-apply---general"},"Setup to apply - General"),Object(a.b)("h4",{id:"mode"},"Mode"),Object(a.b)("p",null,"Selecting Mode allows you to labelize the environment. "),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"To learn more about the environment modes, take a look to the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"docs.using-qovery.configuration.environment#type-of-environment"}),"Type of environments")," section.")),Object(a.b)("h4",{id:"cluster"},"Cluster"),Object(a.b)("p",null,"Selecting the cluster allows you to control to which cluster your environments in the project will be deployed to."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Example use cases")),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"deploy your development environments on a more cost effective cluster"),Object(a.b)("li",{parentName:"ul"},"deploy your environments in multiple regions")),Object(a.b)("h3",{id:"setup-to-apply---start--stop"},"Setup to apply - Start & stop"),Object(a.b)("h4",{id:"start--stop"},"Start & Stop"),Object(a.b)("p",null,"The start and stop section allow you to precisely set up when the environments inside the project should be deployed and cleaned up."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Use cases examples")),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"shut down your development environments during the weekend"),Object(a.b)("li",{parentName:"ul"},"deploy additional environments during peak hours")),Object(a.b)("br",null)))),Object(a.b)("h3",{id:"rules-priority"},"Rules priority"),Object(a.b)("p",null,"Since you can define several rules, it is possible that an environment is targeted by more than one of them.\nIn order to define which rule applies first to your new environments, you can reorder the list of rules in the deployment setting window.\nStarting from the top, the rules are ranked from highest to lowest priority. "),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/deployment_rule/ordering_deployment_rule.png",alt:"Reorder priority rules"})),Object(a.b)("h2",{id:"environment-deployment-rules"},"Environment Deployment Rules"),Object(a.b)("p",null,"Setting up Deployment Rules at the Enviornment level allows you to make all necessary adjustments applied by your default rules from the Project level."),Object(a.b)("p",null,"Have a look at ","[this section]","[docs.using-qovery.configuration.environment#deployment-rule]","] to know more."))}b.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},p=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return n?o.a.createElement(m,l({ref:t},u,{components:n})):o.a.createElement(m,l({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:r,i[1]=l;for(var u=2;u1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,u=void 0===c?n:o(c,n);u>l;)t[l++]=e;return t}},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,c={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(c),s=Object(r.useState)(null),p=s[0],b=s[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/de0a75d9.2096bbbe.js.LICENSE.txt b/db96bb7d.ae36dcb6.js.LICENSE.txt similarity index 100% rename from de0a75d9.2096bbbe.js.LICENSE.txt rename to db96bb7d.ae36dcb6.js.LICENSE.txt diff --git a/dbe0f891.e28c81f6.js b/dbe0f891.4ce1fcf6.js similarity index 73% rename from dbe0f891.e28c81f6.js rename to dbe0f891.4ce1fcf6.js index 43e9f908e7..162af00b45 100644 --- a/dbe0f891.e28c81f6.js +++ b/dbe0f891.4ce1fcf6.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[230],{382:function(a){a.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"language-kotlin","name":"language: kotlin","count":1,"permalink":"/guides/tags/language-kotlin"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[233],{385:function(a){a.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"language-kotlin","name":"language: kotlin","count":1,"permalink":"/guides/tags/language-kotlin"}')}}]); \ No newline at end of file diff --git a/dc00a797.d1e63223.js b/dc00a797.16ee6cdf.js similarity index 93% rename from dc00a797.d1e63223.js rename to dc00a797.16ee6cdf.js index 5db95bc957..5545dbe5ed 100644 --- a/dc00a797.d1e63223.js +++ b/dc00a797.16ee6cdf.js @@ -1,2 +1,2 @@ -/*! For license information please see dc00a797.d1e63223.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[231],{383:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),o=(n(0),n(422)),l=n(431),c=(n(429),n(421)),i=(n(426),{last_modified_on:"2023-11-25",title:"Clusters",description:"Learn how to configure your Kubernetes clusters on Qovery"}),s={id:"using-qovery/configuration/clusters",title:"Clusters",description:"Learn how to configure your Kubernetes clusters on Qovery",source:"@site/docs/using-qovery/configuration/clusters.md",permalink:"/docs/using-qovery/configuration/clusters",sidebar:"docs",previous:{title:"API Token",permalink:"/docs/using-qovery/configuration/organization/api-token"},next:{title:"Cloud Service Provider",permalink:"/docs/using-qovery/configuration/cloud-service-provider"}},u=[{value:"What is a cluster?",id:"what-is-a-cluster",children:[]},{value:"Why do I need a cluster?",id:"why-do-i-need-a-cluster",children:[]},{value:"What are the different instance types available when creating a cluster?",id:"what-are-the-different-instance-types-available-when-creating-a-cluster",children:[]},{value:"How does Qovery handle cluster updates and upgrades?",id:"how-does-qovery-handle-cluster-updates-and-upgrades",children:[]},{value:"What do you do when a vulnerability is found?",id:"what-do-you-do-when-a-vulnerability-is-found",children:[]},{value:"Managing your Clusters with Qovery",id:"managing-your-clusters-with-qovery",children:[{value:"Creating a Cluster",id:"creating-a-cluster",children:[]},{value:"Managing your Cluster Settings",id:"managing-your-cluster-settings",children:[]},{value:"Performing Actions on your Clusters",id:"performing-actions-on-your-clusters",children:[]}]},{value:"Logs",id:"logs",children:[]},{value:"Generating an SSH Key for Your Cluster",id:"generating-an-ssh-key-for-your-cluster",children:[]},{value:"Use custom domain and wildcard TLS for the whole cluster (beta)",id:"use-custom-domain-and-wildcard-tls-for-the-whole-cluster-beta",children:[]},{value:"Cleaning up a Cluster from your AWS Account",id:"cleaning-up-a-cluster-from-your-aws-account",children:[]}],b={rightToc:u};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are looking to install Qovery on your Kubernetes cluster, please refer to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/provider/guide-kubernetes/"}),"this guide"),".")),Object(o.b)("p",null,"This section brings you answers to all the questions our users usually ask about clusters:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#what-is-a-cluster"}),"What is a cluster?")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#why-do-i-need-a-cluster"}),"Why do I need a cluster?")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#what-are-the-different-instance-types-available-when-creating-a-cluster"}),"What are the different instance types available when creating a cluster?")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#how-does-qovery-handle-cluster-updates-and-upgrades"}),"How does Qovery handle cluster updates and upgrades?")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"How do I set up a cluster?")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#managing-your-cluster-settings"}),"How do I update my cluster settings?"))),Object(o.b)("h3",{id:"what-is-a-cluster"},"What is a cluster?"),Object(o.b)("p",null,"At Qovery, when we refer to cluster, we mean ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://kubernetes.io/"}),"Kubernetes")," cluster. A Kubernetes cluster is a collection of node machines that allows you to run containerized applications. It is usually made up of:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Pods"),": think of a pod as one instance of your application. Pods are the smallest deployable objects in Kubernetes, and they are hosted by worker nodes."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Worker Nodes"),": worker nodes essentially run your applications and workloads. When you create a cluster from your Qovery Console, it generates the set up of worker nodes (also called \u201cinstances\u201d, \u201cEC2 instances\u201d for AWS users, or \u201cdroplets\u201d for DigitalOcean users).\nQovery allows you to define worker nodes settings, so that you end up deploying the right type of instances on your infrastructure based on your CPU, memory, storage and network performance needs."),Object(o.b)("li",{parentName:"ul"},"a ",Object(o.b)("strong",{parentName:"li"},"Control Plane")," (or ",Object(o.b)("strong",{parentName:"li"},"Master Node"),"): the control plane manages the worker nodes. Since we deploy managed Kubernetes services, the control plane is handled exclusively by your cloud provider, and left untouched by Qovery.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/cluster-overview.jpg",alt:"Application"})),Object(o.b)("p",null,"For more information on Kubernetes clusters, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://kubernetes.io/docs/concepts/overview/components/"}),"the Kubernetes documentation"),"."),Object(o.b)("h3",{id:"why-do-i-need-a-cluster"},"Why do I need a cluster?"),Object(o.b)("p",null,"Qovery is built on top of Kubernetes, which means we need Kubernetes clusters to be able to deploy and run your applications."),Object(o.b)("p",null,"Thanks to clusters, you can easily deploy several (and many) instances of the same application, so that if one fails, the others can instantly take over. Also, clusters can auto-scale, meaning that the number of worker nodes in a cluster can automatically go up or down as traffic fluctuates on your application(s), thus ensuring high availability and performance. Clusters are also extremely useful ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/blog/how-to-isolate-your-production-from-staging-with-kubernetes"}),"to isolate your production environment from your staging environment"),"."),Object(o.b)("p",null,"In short, through the use of clusters, Kubernetes provides you with a resilient, flexible and powerful infrastructure, fit for production environment needs and requirements. And with the help of Qovery, setting up and maintaining your Kubernetes clusters has never been easier."),Object(o.b)("p",null,"Qovery allows you to create and manage two types of clusters:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null})),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"th"},"Managed K8S ")),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"th"}," BETA - Single EC2 (K3s)")))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Description")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"A multi-node Kubernetes cluster managed by your cloud provider (EKS, Kapsule etc..)"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"K3s Cluster running on a single EC2 instance (single-node) ",Object(o.b)("strong",{parentName:"td"},"Available only on AWS and still in BETA"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Usage")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Hosting professional applications in production (resilient, scalable and powerful infrastructure). Scalable staging / preview / dev environments"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Hobby projects, trying out Qovery, ephemeral environments deployment")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Cloud provider cost")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Starting from 200$/month, based on the chosen instance type"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"starting from 20$/month, based on the chosen instance type")))),Object(o.b)("br",null),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Single EC2 (K3s) is still in BETA phase and has the following limitations",Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You can\u2019t access the historical logs and thus you can access your application logs only if it's running (Since we don\u2019t have loki installed)"),Object(o.b)("li",{parentName:"ul"},"No public accessibility for DB container (we do not manage the public DNS entry for db). We will work on it in the upcoming weeks, in the meantime we will write a guide on how to connect to the DB via the ssh key / kubeconf"),Object(o.b)("li",{parentName:"ul"},"You can configure only 1 instance per application. Thus you can\u2019t change the number of instances nor activate the sticky session feature"),Object(o.b)("li",{parentName:"ul"},"Stop instance feature not ready YET"),Object(o.b)("li",{parentName:"ul"},"You can\u2019t change the cluster settings without a service downtime since we kill the instance and we spawn a new one"),Object(o.b)("li",{parentName:"ul"},"We do not manage YET the external storage"),Object(o.b)("li",{parentName:"ul"},"We do not support YET the VPC setting"),Object(o.b)("li",{parentName:"ul"},"If you want to connect via SSH, you can't get YET the instance hostname directly in the Qovery console, you need to get it from the AWS console"))),Object(o.b)("br",null),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"K3s clusters are ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-availability-zones"}),"deployed on one AWS availability zone"),". Therefore, if a network or power disruption happens on the availability zone where your K3s instance is running, your applications will no longer be available until it is solved."),Object(o.b)("p",null,"This is why we do not recommend installing K3s clusters to run professional applications in a production environment.")),Object(o.b)("h3",{id:"what-are-the-different-instance-types-available-when-creating-a-cluster"},"What are the different instance types available when creating a cluster?"),Object(o.b)("p",null,"The range of instance types available at cluster creation depends on your cloud provider:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"AWS offers over 400 instance types. You can ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://aws.amazon.com/ec2/instance-types/"}),"view their details on the official AWS website"),", as well as ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://aws.amazon.com/ec2/pricing/on-demand/"}),"their pricing"),"."),Object(o.b)("li",{parentName:"ul"},"Scaleway also offers a wide range of instance types, ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.scaleway.com/en/pricing/"}),"whose details and pricing you can view on the official Scaleway website"),".")),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Qovery supports only instance types having an x86_64 or ARM architecture.")),Object(o.b)("h4",{id:"what-is-the-default-cluster"},"What is the default cluster?"),Object(o.b)("p",null,"The default cluster is the first cluster you installed in your organization."),Object(o.b)("p",null,"When you create a new environment and leave the ",Object(o.b)("inlineCode",{parentName:"p"},"mode")," and ",Object(o.b)("inlineCode",{parentName:"p"},"cluster")," parameters set to the value ",Object(o.b)("inlineCode",{parentName:"p"},"Automatic"),", your environment is deployed to:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"the cluster defined in one of ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/deployment-rule/#environment-deployment-rules"}),"your project rules"),","),Object(o.b)("li",{parentName:"ul"},"or to the default cluster if no project rule applies.")),Object(o.b)("p",null,"For more information on deployment rules, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/project/"}),"Project"),"."),Object(o.b)("h3",{id:"how-does-qovery-handle-cluster-updates-and-upgrades"},"How does Qovery handle cluster updates and upgrades?"),Object(o.b)("p",null,"As far as cluster updates and upgrades to a newer version of Kubernetes are concerned, our Qovery engineering team handles everything in due time, so you don\u2019t even need to think about it!"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"You may notice that Qovery does not provide you with the latest Kubernetes version offered by your cloud provider. This is due to the high amount of testing we need to perform to ensure smooth upgrades with no interruptions for your applications. Our priority is always to guarantee you maximum uptime.")),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Please ",Object(o.b)("strong",{parentName:"p"},"DO NOT")," upgrade the cluster version by yourself from the cloud provider console."),Object(o.b)("p",null,"That's the whole point of Qovery, we manage this task for you so you don't have to bother.\nIf you did update by mistake, then you need to reach to Qovery team in order to get some help."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Proceeding with a cluster version upgrade outside of Qovery will prevent any future update on this cluster")," and might be irreversible preventing Qovery from properly deploying on this cluster. Most importantly will expose you to some unknown / untested areas which can put your application stability at risks.")),Object(o.b)("p",null,"Usually, we work on a given upgrade for one month of intensive testing on our end in order to make sure everything will be smooth for you. Once we are pretty confident our stack is stable, we move on with the following steps which last approximately 3 weeks:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Notify users about new version coming in approximatively 1 month before"),Object(o.b)("li",{parentName:"ol"},"Upgrade clusters for a handful of beta-tester customers (1 week)"),Object(o.b)("li",{parentName:"ol"},"Upgrade all non-production flagged clusters (1-2 week(s))"),Object(o.b)("li",{parentName:"ol"},"Upgrade all clusters")),Object(o.b)("p",null,"If, somehow the planning or timeframe for the upgrade is clashing with your business needs, you will be able to contact us so we can arrange the best timeframe for you."),Object(o.b)("h3",{id:"what-do-you-do-when-a-vulnerability-is-found"},"What do you do when a vulnerability is found?"),Object(o.b)("p",null,"Security is our main concern. When a vulnerability is found, here are the actions that we take:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"We quickly identify how significant is the impact of the vulnerability."),Object(o.b)("li",{parentName:"ol"},"We look at how we can solve or mitigate the vulnerability."),Object(o.b)("li",{parentName:"ol"},"We transparently communicate with our customers about the vulnerability to help them take the right actions.")),Object(o.b)("h2",{id:"managing-your-clusters-with-qovery"},"Managing your Clusters with Qovery"),Object(o.b)("p",null,"From the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),", you can manage the settings of the clusters you want to run on your infrastructure. The clusters are then created (or updated) by the cloud provider that hosts them."),Object(o.b)("h3",{id:"creating-a-cluster"},"Creating a Cluster"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"To install a cluster, Qovery needs a set of credentials to access your cloud provider account (example: AWS secret_access_key and access_key_id). If this is the first time you are installing a cluster with Qovery, have a look at this guide on how to get the credentials: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"here for AWS"),", ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/scaleway/#connect-your-scaleway-account"}),"here for Scaleway"),".")),Object(o.b)("p",null,"To create a cluster:"),Object(o.b)(l.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Open your ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"On the left menu bar, click on the Cluster page:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/cluster_section_access.png",alt:"Cluster Access"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Click ",Object(o.b)("inlineCode",{parentName:"p"},"Add Cluster"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/add-cluster-button.png",alt:"Add Cluster Button"}))),Object(o.b)("li",null,Object(o.b)("p",null,"In the ",Object(o.b)("inlineCode",{parentName:"p"},"Create Cluster")," window enter:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Cluster name"),": enter the name of your choice for your cluster."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Description"),": enter a description to identify better your cluster."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Production cluster"),": select this option if your cluster will be used for production."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Cloud provider"),": select your cloud provider."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Region"),": select the geographical area in which you want your cluster to be hosted."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Credentials"),": select one of the existing cloud provider credentials or add a new one by clicking on ",Object(o.b)("inlineCode",{parentName:"li"},"New Credentials"),". In the New credentials window, add the credentials that you have generated on your cloud provider console (",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"Procedure for AWS account"),", ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cloud-service-provider/scaleway/#connect-your-scaleway-account"}),"Procedure for Scaleway account"),"). Added credentials can be used later to create and manage additional cluster.")),Object(o.b)("p",null,"To confirm, click ",Object(o.b)("inlineCode",{parentName:"p"},"Next"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"In the ",Object(o.b)("inlineCode",{parentName:"p"},"Set Resources")," window, select:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Cluster"),": select the cluster type to use. Please refer to this section for ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#why-do-i-need-a-cluster"}),"more information"),"."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Instance type"),": select the type of ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#what-is-a-cluster"}),"worker nodes")," you want to deploy to your cluster:"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Disk size"),": select the size of the disks to be attached to your cluster instances (to locally store container images etc..). Setting available only on AWS."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Node auto-scaling"),": define the minimum and the maximum number of worker nodes that your cluster can run. The lowest number is the number of worker nodes running on your infrastructure at any time, while the highest number is the maximum number of worker nodes that can automatically be deployed as traffic grows. Please note that a minimum of 3 worker nodes is required to deploy your EKS cluster.")),Object(o.b)("br",null),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Instance type selection from your Qovery Console has direct consequences on your cloud provider\u2019s bill. While Qovery allows you to switch to a different instance type whenever you want, it is your sole responsibility to keep an eye on your infrastructure costs, especially when you want to upsize.",Object(o.b)("p",null,"Please be aware that changing the instance type or disk size might cause a downtime for your service."),Object(o.b)("p",null,"For more information on the instance types provided by each cloud provider and their associated pricing, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#what-are-the-different-instance-types-available-when-creating-a-cluster"}),"What are the different instance types available when creating a cluster?")),Object(o.b)("p",null,"Also, before downsizing, you need to ensure that your applications will still have enough resources to run correctly.")),Object(o.b)("br",null),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"At the bottom of the window, you can see an estimate of the cost associated with the selected instance type.")),Object(o.b)("p",null,"To confirm, click ",Object(o.b)("inlineCode",{parentName:"p"},"Next"),".")),Object(o.b)("li",null,Object(o.b)("p",null,Object(o.b)("em",{parentName:"p"},"(Only for AWS K8S Clusters)")," In the ",Object(o.b)("inlineCode",{parentName:"p"},"Features")," window, select the features you want to enable on your cluster."),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"For more information, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#features"}),"Features"),"."))),Object(o.b)("li",null,Object(o.b)("p",null,Object(o.b)("em",{parentName:"p"},"(Only for Single EC2 K3S Clusters)")," In the ",Object(o.b)("inlineCode",{parentName:"p"},"Set SSH Key")," window:"),Object(o.b)("p",null,"The SSH key enables you (or Qovery on your behalf) to freely manage your cluster. For information on how to generate an SSH key, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#generating-an-ssh-key-for-your-cluster"}),"Generating an SSH Key for Your Cluster"),"."),Object(o.b)("p",null,"You can add an SSH key to your cluster settings later, however it is recommended to do it at cluster creation to avoid downtime.")),Object(o.b)("li",null,Object(o.b)("p",null,"In the ",Object(o.b)("inlineCode",{parentName:"p"},"Ready to install your cluster")," window, check that the services needed to install your cluster are correct."),Object(o.b)("p",null,"You can now press the ",Object(o.b)("inlineCode",{parentName:"p"},"Create and Install")," button."),Object(o.b)("p",null,"Your cluster is now displayed in your organization settings, featuring the ",Object(o.b)("inlineCode",{parentName:"p"},"Installing...")," status (orange status). Once your cluster is properly installed, its status turns to green and you will be able to deploy your applications on it.")))),Object(o.b)("h3",{id:"managing-your-cluster-settings"},"Managing your Cluster Settings"),Object(o.b)("p",null,"To manage the settings of an existing cluster:"),Object(o.b)(l.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Open your ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"On the left menu bar, click on the Cluster page:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/cluster_section_access.png",alt:"Cluster Access"}))),Object(o.b)("li",null,Object(o.b)("p",null,"To access your cluster settings, click on the wheel button:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/cluster_settings.png",alt:"Display Cluster Settings"}))))),Object(o.b)("p",null,"Below you can find a description of each section"),Object(o.b)("h4",{id:"general"},"General"),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"General")," tab allows you to define high-level information on your cluster:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Item"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Cluster Name"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"To edit the name of your cluster.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"To enter or edit the description of your cluster.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Production Cluster"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"To enter or edit the production flag of your cluster.")))),Object(o.b)("h4",{id:"credentials"},"Credentials"),Object(o.b)("p",null,"Here you can manage here the cloud provider credentials associated with your cluster."),Object(o.b)("p",null,"If you need to change the credentials:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"generate a new set of credentials on your cloud provider(",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"Procedure for AWS account"),", ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cloud-service-provider/scaleway/#connect-your-scaleway-account"}),"Procedure for Scaleway account"),")"),Object(o.b)("li",{parentName:"ul"},'create the new credential on the Qovery by opening the drop-down and selecting "New Credentials"')),Object(o.b)("p",null,"In the two dedicated fields, enter the credentials you created on your cloud provider account:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Account Provider"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Field Labels"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"AWS"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("inlineCode",{parentName:"td"},"Access Key")," and ",Object(o.b)("inlineCode",{parentName:"td"},"Secret Access Key"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Scaleway"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("inlineCode",{parentName:"td"},"Scaleway Access Key")," and ",Object(o.b)("inlineCode",{parentName:"td"},"Scaleway Project ID"))))),Object(o.b)("p",null,"Once created and associated, you need to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#updating-a-cluster"}),"updating your cluster")," to apply the change."),Object(o.b)("h4",{id:"resources"},"Resources"),Object(o.b)("p",null,"Qovery allows you to modify the resources allocated for your cluster:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"In the ",Object(o.b)("inlineCode",{parentName:"li"},"Instance type")," dropdown menu, select the type of ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#what-is-a-cluster"}),"worker node(s)")," you want to deploy to your cluster."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("em",{parentName:"li"},"(AWS users only)")," In the ",Object(o.b)("inlineCode",{parentName:"li"},"Node disk size (GB)")," field, enter the disk capacity you want to allocate to your worker node(s) (meaning how much data, in gigabytes, you want each worker node to be able to hold)."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("em",{parentName:"li"},"(EKS users only)")," On the ",Object(o.b)("inlineCode",{parentName:"li"},"Nodes auto-scaling"),", define the range of worker nodes you want to deploy to your cluster.")),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Instance type selection from your Qovery Console has direct consequences on your cloud provider\u2019s bill. While Qovery allows you to switch to a different instance type whenever you want, it is your sole responsibility to keep an eye on your infrastructure costs, especially when you want to upsize.",Object(o.b)("p",null,"For more information on the instance types provided by each cloud provider and their associated pricing, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#what-are-the-different-instance-types-available-when-creating-a-cluster"}),"What are the different instance types available when creating a cluster?"))),Object(o.b)("br",null),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"The lowest number is the number of worker nodes running on your infrastructure at any time, while the highest number is the maximum number of worker nodes that can automatically be deployed as traffic grows."),Object(o.b)("p",null,"Please note that a minimum of 3 worker nodes is required to deploy your ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"EKS cluster"),"."),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"K3s clusters")," can only have one node.")),Object(o.b)("h4",{id:"features"},"Features"),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"Features")," tab in your cluster settings allows you to check if the ",Object(o.b)("strong",{parentName:"p"},"Static IP")," and ",Object(o.b)("strong",{parentName:"p"},"Custom VPC subnet")," features are enabled on your cluster. The enabled features cannot be changed after the creation of the cluster."),Object(o.b)("h5",{id:"static-ip"},"Static IP"),Object(o.b)("p",null,"The ",Object(o.b)("strong",{parentName:"p"},"Static IP")," feature is currently only available to clusters deployed on AWS and can only be enabled at cluster creation."),Object(o.b)("p",null,"By default, when your cluster is created, its worker nodes are allocated public IP addresses, which are used for external communication. For improved security and control, the ",Object(o.b)("strong",{parentName:"p"},"Static IP")," feature allows you to ensure that outbound traffic from your cluster uses specific IP addresses."),Object(o.b)("p",null,"Here is what will be deployed on AWS:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Nat Gateways"),Object(o.b)("li",{parentName:"ul"},"Elastic IPs"),Object(o.b)("li",{parentName:"ul"},"Private subnets")),Object(o.b)("p",null,"Once set up, here is the procedure to find your static IP addresses:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"On your AWS account, select the VPC service."),Object(o.b)("li",{parentName:"ul"},"On the left menu, you\u2019ll find Elastic IP addresses. Once on it, in the Allocated IPv4 address column, you\u2019ll have your public IPs.")),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you work in a sensitive business area such as financial technology, enabling the ",Object(o.b)("strong",{parentName:"p"},"Static IP")," feature can help fulfil the security requirements of some of the external services you use, therefore making it easier for you to get whitelisted by them.")),Object(o.b)("h5",{id:"custom-vpc-subnet"},"Custom VPC Subnet"),Object(o.b)("p",null,"The ",Object(o.b)("strong",{parentName:"p"},"VPC")," feature is currently only available to clusters deployed on AWS and can only be enabled at cluster creation."),Object(o.b)("p",null,"Virtual Private Cloud (VPC) peering allows you to set up a connection between your Qovery VPC and another VPC on your AWS account. This way, you can access resources stored on your AWS VPC directly from your Qovery applications."),Object(o.b)("p",null,"A VPC can only be used if it has at least one range of IP addresses called a ",Object(o.b)("strong",{parentName:"p"},"subnet"),". When you create a cluster, Qovery automatically picks a default subnet for it. However, to perform VPC peering, you may want to define which specific VPC subnet you want to use, so that you can avoid any conflicting settings. To do so, you can enable the ",Object(o.b)("strong",{parentName:"p"},"Custom VPC Subnet")," feature on your cluster. For more information on how to set up VPC peering, ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/tutorial/aws-vpc-peering-with-qovery/"}),"see our dedicated tutorial"),"."),Object(o.b)("h4",{id:"network"},"Network"),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"Network")," tab in your cluster settings allows you to update your Qovery VPC route table so that you can perform VPC peering. For step-by-step guidelines on how to set up VPC peering, ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/tutorial/aws-vpc-peering-with-qovery/"}),"see our dedicated tutorial"),"."),Object(o.b)("h3",{id:"performing-actions-on-your-clusters"},"Performing Actions on your Clusters"),Object(o.b)("p",null,"Qovery allows you to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#updating-a-cluster"}),"update"),", ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#stopping-a-cluster"}),"stop"),", ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#restarting-a-cluster"}),"restart")," or ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#deleting-a-cluster"}),"delete")," your clusters at organization level."),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Action"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/clusters/#updating-a-cluster"}),"Updating a cluster")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"To redeploy your cluster after a change has been made to it.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/clusters/#stopping-a-cluster"}),"Stopping a cluster")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"To temporarily stop your cluster. Some services you have subscribed to via your cloud provider may still be active and incur costs when your cluster is stopped. For more information, see ",Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/clusters/#stopping-a-cluster"}),"Stopping a cluster"),".")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/clusters/#restarting-a-cluster"}),"Restarting a cluster")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"To restart your cluster after it has been temporarily stopped.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/clusters/#deleting-a-cluster"}),"Deleting a cluster")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"To delete your cluster. This is final and needs to be done properly to ensure all the services deployed by Qovery on your cloud provider's account are disabled, with no leftover cloud-related costs. For more information, see ",Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/clusters/#deleting-a-cluster"}),"Deleting a cluster"),".")))),Object(o.b)("p",null,"To access these actions:"),Object(o.b)(l.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Open your ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"On the left menu bar, click on the Cluster page:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/cluster_section_access.png",alt:"Cluster Access"}))),Object(o.b)("li",null,Object(o.b)("p",null,"To view your cluster actions, click ",Object(o.b)("inlineCode",{parentName:"p"},"Play")," button:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/cluster_actions.png",alt:"Cluster Actions Menu"})),Object(o.b)("p",null,"A dropdown menu unfolds, featuring all the actions available on your cluster.")))),Object(o.b)("p",null,"You can follow the execution of the action via the cluster status and/or by accessing the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#logs"}),"Cluster Logs")),Object(o.b)("h4",{id:"updating-a-cluster"},"Updating a Cluster"),Object(o.b)("p",null,"If you made a change on your cluster, you need to run an update on your cluster to propagate remotely the new configuration."),Object(o.b)("p",null,"To update your cluster, select the action ",Object(o.b)("inlineCode",{parentName:"p"},"Update")," from the drop-down menu."),Object(o.b)("p",null,"A confirmation pop-up window opens before triggering the action."),Object(o.b)("p",null,"Once confirmed, the status of your cluster turns ",Object(o.b)("inlineCode",{parentName:"p"},"Updating...")," (orange status)."),Object(o.b)("p",null,"Once the update is complete, the status dot next to your cluster turns green."),Object(o.b)("h4",{id:"stopping-a-cluster"},"Stopping a Cluster"),Object(o.b)("p",null,"Qovery allows you to temporarily stop your cluster instead of deleting it."),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"When you stop a cluster from the Qovery console, only the workers nodes managed by Qovery are stopped. If you have subscribed to services via your cloud provider (load balancing, storage system, or any other managed services), they will remain active and you will be charged for them.\nFor more information, please contact your cloud provider.\nTo permanently delete a cluster and all its associated costs, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#deleting-a-cluster"}),"Deleting a Cluster"),".")),Object(o.b)("p",null,"To temporarily stop a cluster, select the ",Object(o.b)("inlineCode",{parentName:"p"},"Stop")," action from the drop-down menu.\nA confirmation pop-up window opens before triggering the action."),Object(o.b)("p",null,"Once confirmed, the status of your cluster turns to ",Object(o.b)("inlineCode",{parentName:"p"},"Pausing...")," (orange status)."),Object(o.b)("p",null,"Once the stop is complete, the status dot next to your cluster turns to grey, and the status of your cluster turns to ",Object(o.b)("inlineCode",{parentName:"p"},"Paused")," (gray status)."),Object(o.b)("h4",{id:"restarting-a-cluster"},"Restarting a Cluster"),Object(o.b)("p",null,"You can restart a cluster after it has been temporarily stopped."),Object(o.b)("p",null,"To restart your cluster, select the action ",Object(o.b)("inlineCode",{parentName:"p"},"Resume")," from the drop-down menu."),Object(o.b)("p",null,"A confirmation pop-up window opens before triggering the action."),Object(o.b)("p",null,"Once confirmed, the status of your cluster turns to ",Object(o.b)("inlineCode",{parentName:"p"},"Updating...")," (orange status)."),Object(o.b)("p",null,"Once your cluster has restarted, the status dot next to your cluster turns to green."),Object(o.b)("h4",{id:"deleting-a-cluster"},"Deleting a Cluster"),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Deleting a cluster from the Qovery console is final and cannot be reverted."),Object(o.b)("p",null,"To only temporarily stop a cluster, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#stopping-a-cluster"}),"Stopping a Cluster"),".")),Object(o.b)("p",null,"To delete a cluster, open the ",Object(o.b)("inlineCode",{parentName:"p"},"...")," section and press ",Object(o.b)("inlineCode",{parentName:"p"},"Delete Cluster"),"."),Object(o.b)("p",null,"3 options can be chosen to delete a cluster:"),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"}," 1) Default "),"\nThis is the default behaviour, this option shall be chosen every time you want to delete properly a cluster from the Qovery console AND your cloud provider account."),Object(o.b)("p",null,"This operation will delete:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Cloud provider"),": any resource created by Qovery on your cloud provider account to run this cluster will be deleted, including any application running on it."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Qovery organization"),": the configuration of this cluster and any linked environment.")),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Please note that you will have to manually delete on your cloud account:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"the S3 bucket created at cluster installation"),Object(o.b)("li",{parentName:"ul"},"the image registry linked to this cluster"),Object(o.b)("li",{parentName:"ul"},"any resource created by a lifecycle job that will not be properly deleted during the ",Object(o.b)("inlineCode",{parentName:"li"},"environment deletion")," event.")),Object(o.b)("p",null,"Check ","[this section][#cleaning-up-a-cluster-from-your-aws-account]"," to find these elements and delete them.")),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"}," 2) Delete Cluster on cloud provider and Qovery configuration ")),Object(o.b)("p",null,"This option shall be chosen when the cluster delete operation with the ",Object(o.b)("inlineCode",{parentName:"p"},"Default")," option fails since you have manually modified/deleted the RDS instances created by Qovery on your cloud provider account."),Object(o.b)("p",null,"This operation will delete:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Cloud provider"),": any resource created by Qovery on your cloud provider account to run this cluster will be deleted, including any application running on it."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Qovery organization"),": the configuration of this cluster and any linked environment.")),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Please note that you will have to manually delete on your cloud account:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"the S3 bucket created at cluster installation"),Object(o.b)("li",{parentName:"ul"},"the image registry linked to this cluster"),Object(o.b)("li",{parentName:"ul"},"any managed database that was created via Qovery"),Object(o.b)("li",{parentName:"ul"},"any resource created by a lifecycle job that will not be properly deleted during the ",Object(o.b)("inlineCode",{parentName:"li"},"environment deletion")," event.")),Object(o.b)("p",null,"Check ","[this section][#cleaning-up-a-cluster-from-your-aws-account]"," to find these elements and delete them.")),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"}," 3) Delete Qovery config only ")),Object(o.b)("p",null,"This option shall be chosen when you have already deleted any Qovery resource on your cloud account and you want to delete the cluster object from your Qovery console."),Object(o.b)("p",null,"This operation will delete:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Cloud provider"),": nothing will be removed from your cloud account. You will have to manually delete any resource created by Qovery directly from your cloud provider console."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Qovery organization"),": the configuration of this cluster and any linked environment.")),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Check ","[this section][#cleaning-up-a-cluster-from-your-aws-account]"," to find these elements and delete them.")),Object(o.b)("p",null,"Once confirmed, the cluster status turns to ",Object(o.b)("inlineCode",{parentName:"p"},"Deleting...")," (red status) and once the deletion is complete, the cluster is removed from your organization settings."),Object(o.b)("h2",{id:"logs"},"Logs"),Object(o.b)("p",null,"Qovery allows you to access the logs of your cluster in order to follow its installation or investigate any issue happening on it."),Object(o.b)("p",null,"To access the logs you need to open the cluster, click the log button"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/cluster_logs_access.png",alt:"Cluster Logs"})),Object(o.b)("p",null,"A new window is opened, displaying the logs of the cluster."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/ok-infra-logs.jpg",alt:"Cluster Logs"})),Object(o.b)("p",null,"The tab system on the right allows you to access the cluster information and, if an error occurs, the detail of the error."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/error-infra-logs.jpg",alt:"Cluster Logs"})),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"The error message should provide you enough information to solve the issue. If that's not the case, feel free to ask for support on our ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"forum")," or ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://discord.com/channels/688766934917185556/688826155611979807"}),"discord channel"))),Object(o.b)("h2",{id:"generating-an-ssh-key-for-your-cluster"},"Generating an SSH Key for Your Cluster"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"You need a public SSH key for your K3s clusters only.")),Object(o.b)("p",null," To allow Qovery or yourself to connect remotely to your K3s instance and manage it, you need to generate an SSH key and add it to your cluster settings. To do so:"),Object(o.b)(l.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null," On your computer, open a terminal.")),Object(o.b)("li",null,Object(o.b)("p",null," Run ",Object(o.b)("inlineCode",{parentName:"p"},"ssh-keygen -t"),", followed by the key type and an optional comment."),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This comment is included in the .pub file that is created. You may want to use an email address for the comment.")),Object(o.b)("p",null,"For example, you can enter ",Object(o.b)("inlineCode",{parentName:"p"},'ssh-keygen -t rsa -b 2048 -C ""'),".")),Object(o.b)("li",null,Object(o.b)("p",null,"Press ",Object(o.b)("inlineCode",{parentName:"p"},"Enter"),"."),Object(o.b)("p",null,"You should get an output similar to:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{}),"{\n Generating public/private ed25519 key pair.\n Enter file in which to save the key (/home/user/.ssh/id_ed25519):\n}\n"))),Object(o.b)("li",null,Object(o.b)("p",null," Accept the suggested filename and directory, unless you want to save your SSH key in a specific directory where you store other keys.")),Object(o.b)("li",null,Object(o.b)("p",null," Enter a passphrase:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{}),"{\n Enter passphrase (empty for no passphrase):\n Enter same passphrase again:\n}\n")),Object(o.b)("p",null," A confirmation is displayed, including information about where your files are stored.")),Object(o.b)("li",null,"Access the public key and copy its value",Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{}),"{\n cat /home/user/.ssh/id_ed25519.pub | pbcopy\n}\n")),Object(o.b)("p",null," Note: Replace the .pub key path with the one where is located the key you have previously generated")))),Object(o.b)("p",null," You can add the generated public SSH key at cluster creation (see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"Creating a Cluster"),"), or later from your cluster settings."),Object(o.b)("p",null," To do so:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"on your ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://console.qovery.com"}),"Qovery Console"),", access your ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#managing-your-cluster-settings"}),"cluster settings"),"."),Object(o.b)("li",{parentName:"ul"},"In the ",Object(o.b)("inlineCode",{parentName:"li"},"Remote Access")," tab, enter your SSH key and click ",Object(o.b)("inlineCode",{parentName:"li"},"Save"),"."),Object(o.b)("li",{parentName:"ul"},"Launch the ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/"}),"Update Cluster")," action to propagate the new key.")),Object(o.b)("h2",{id:"use-custom-domain-and-wildcard-tls-for-the-whole-cluster-beta"},"Use custom domain and wildcard TLS for the whole cluster (beta)"),Object(o.b)("p",null,"By default, Qovery provides a domain (ex ",Object(o.b)("inlineCode",{parentName:"p"},"bool.sh"),") on every deployed cluster. It is used to provide a DNS and TLS certificate to every application requiring external access on a cluster."),Object(o.b)("p",null,"You can customize the domain for every application. However, when it comes to having more than 100 custom domains with the same domain you will hit ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://letsencrypt.org/docs/rate-limits/"}),"Let's Encrypt quotas"),"."),Object(o.b)("p",null,"To overcome this issue, you can use a wildcard TLS certificate for the whole cluster. It will allow you to have as many DNS records for a single domain as you want on the same cluster with a single TLS certificate."),Object(o.b)("p",null,"At the moment, Qovery only supports wildcard TLS certificates with ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.cloudflare.com/"}),"Cloudflare"),". To use it, you need to have a Cloudflare account and a domain name managed by Cloudflare. If you don't have one, you can create a free account and transfer your domain to Cloudflare."),Object(o.b)("p",null,"Once you have a Cloudflare account and a domain name managed by Cloudflare, you need to create a Cloudflare API token. Go into your Cloudflare account, click on your profile picture, then ",Object(o.b)("inlineCode",{parentName:"p"},"My Profile"),". In the ",Object(o.b)("inlineCode",{parentName:"p"},"API Tokens")," section, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create Token"),". In the ",Object(o.b)("inlineCode",{parentName:"p"},"Create Custom Token")," section, select the following permissions:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"API token a descriptive name: Qovery domain ",Object(o.b)("inlineCode",{parentName:"li"},"your domain name")),Object(o.b)("li",{parentName:"ul"},"Permissions:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Zone - DNS - Edit"),Object(o.b)("li",{parentName:"ul"},"Zone - Zone - Read"))),Object(o.b)("li",{parentName:"ul"},"Zone Resources:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Include - Specific zone - ",Object(o.b)("inlineCode",{parentName:"li"},"your domain name"))))),Object(o.b)("p",null,"To finish, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Continue to Summary")," and ",Object(o.b)("inlineCode",{parentName:"p"},"Create Token"),". Save the token somewhere safe, you will need it later."),Object(o.b)("p",null,"Prepare the Token, the Cloudflare account email and the domain to be set on your cluster. Now contact Qovery and request to use your domain."),Object(o.b)("h2",{id:"cleaning-up-a-cluster-from-your-aws-account"},"Cleaning up a Cluster from your AWS Account"),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"The following troubleshooting procedure is intended for AWS users who did not properly delete their cluster before revoking Qovery's access to their platform."),Object(o.b)("p",null,"To properly delete your clusters and avoid any unexpected issues or costs, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#deleting-a-cluster"}),"Deleting a Cluster"),".")),Object(o.b)("p",null,"To clean up a Qovery cluster from your cloud provider account, go to ",Object(o.b)("inlineCode",{parentName:"p"},"AWS Console"),">",Object(o.b)("inlineCode",{parentName:"p"},"Services"),">",Object(o.b)("inlineCode",{parentName:"p"},"Management & Governance"),">",Object(o.b)("inlineCode",{parentName:"p"},"Resource Groups & Tag Editor"),"> ",Object(o.b)("inlineCode",{parentName:"p"},"Create Resource Group"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/aws-console-cluster-cleanup.jpg",alt:"AWS Console Cluster Cleanup"})),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Step"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"1"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"In the ",Object(o.b)("inlineCode",{parentName:"td"},"Group type")," area, select ",Object(o.b)("inlineCode",{parentName:"td"},"Tag based"),".")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"2"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"In the ",Object(o.b)("inlineCode",{parentName:"td"},"Tags")," field of the ",Object(o.b)("inlineCode",{parentName:"td"},"Grouping criteria")," area, enter ",Object(o.b)("inlineCode",{parentName:"td"},"ClusterId"),".")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"3"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Click ",Object(o.b)("inlineCode",{parentName:"td"},"Add"),".")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"4"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Click ",Object(o.b)("inlineCode",{parentName:"td"},"Preview Resources"),". ",Object(o.b)("br",null)," All your Qovery clusters are now displayed in the ",Object(o.b)("inlineCode",{parentName:"td"},"Group resources")," table, and you can delete them by hand.")))))}p.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},b=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),b=u(n),d=a,m=b["".concat(l,".").concat(d)]||b[d]||p[d]||o;return n?r.a.createElement(m,c({ref:t},s,{components:n})):r.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=d;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c.mdxType="string"==typeof e?e:a,l[1]=c;for(var s=2;s1?arguments[1]:void 0,n),i=l>2?arguments[2]:void 0,s=void 0===i?n:r(i,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),l=n(39),c=n(430),i=n(20),s=n.n(i);t.a=function(e){var t,n=e.to,i=e.href,u=n||i,b=Object(c.a)(u),p=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,b]),u&&b?o.a.createElement(l.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,a;d&&e&&b&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},428:function(e,t,n){"use strict";var a=n(432),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var l=[];return r.slice().forEach((function(e){void 0!==e&&l.push(n(a,e,l.length))})),l.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),l=n(420),c=n.n(l);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,l=e.leftIcon,i=e.rightIcon,s=e.size,u=e.target,b=e.to,p=c()("jump-to","jump-to--"+s,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},l&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+l})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(i||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:b,target:u,className:p},d):r.a.createElement(o.a,{to:b,className:p},d)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(420),n(428)),l=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,i={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+l.a.stringify(i),u=Object(a.useState)(null),b=u[0],p=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see dc00a797.16ee6cdf.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[234],{386:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),o=(n(0),n(425)),l=n(434),c=(n(431),n(424)),i=(n(429),{last_modified_on:"2023-11-25",title:"Clusters",description:"Learn how to configure your Kubernetes clusters on Qovery"}),s={id:"using-qovery/configuration/clusters",title:"Clusters",description:"Learn how to configure your Kubernetes clusters on Qovery",source:"@site/docs/using-qovery/configuration/clusters.md",permalink:"/docs/using-qovery/configuration/clusters",sidebar:"docs",previous:{title:"API Token",permalink:"/docs/using-qovery/configuration/organization/api-token"},next:{title:"Cloud Service Provider",permalink:"/docs/using-qovery/configuration/cloud-service-provider"}},u=[{value:"What is a cluster?",id:"what-is-a-cluster",children:[]},{value:"Why do I need a cluster?",id:"why-do-i-need-a-cluster",children:[]},{value:"What are the different instance types available when creating a cluster?",id:"what-are-the-different-instance-types-available-when-creating-a-cluster",children:[]},{value:"How does Qovery handle cluster updates and upgrades?",id:"how-does-qovery-handle-cluster-updates-and-upgrades",children:[]},{value:"What do you do when a vulnerability is found?",id:"what-do-you-do-when-a-vulnerability-is-found",children:[]},{value:"Managing your Clusters with Qovery",id:"managing-your-clusters-with-qovery",children:[{value:"Creating a Cluster",id:"creating-a-cluster",children:[]},{value:"Managing your Cluster Settings",id:"managing-your-cluster-settings",children:[]},{value:"Performing Actions on your Clusters",id:"performing-actions-on-your-clusters",children:[]}]},{value:"Logs",id:"logs",children:[]},{value:"Generating an SSH Key for Your Cluster",id:"generating-an-ssh-key-for-your-cluster",children:[]},{value:"Use custom domain and wildcard TLS for the whole cluster (beta)",id:"use-custom-domain-and-wildcard-tls-for-the-whole-cluster-beta",children:[]},{value:"Cleaning up a Cluster from your AWS Account",id:"cleaning-up-a-cluster-from-your-aws-account",children:[]}],b={rightToc:u};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are looking to install Qovery on your Kubernetes cluster, please refer to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/provider/guide-kubernetes/"}),"this guide"),".")),Object(o.b)("p",null,"This section brings you answers to all the questions our users usually ask about clusters:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#what-is-a-cluster"}),"What is a cluster?")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#why-do-i-need-a-cluster"}),"Why do I need a cluster?")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#what-are-the-different-instance-types-available-when-creating-a-cluster"}),"What are the different instance types available when creating a cluster?")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#how-does-qovery-handle-cluster-updates-and-upgrades"}),"How does Qovery handle cluster updates and upgrades?")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"How do I set up a cluster?")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#managing-your-cluster-settings"}),"How do I update my cluster settings?"))),Object(o.b)("h3",{id:"what-is-a-cluster"},"What is a cluster?"),Object(o.b)("p",null,"At Qovery, when we refer to cluster, we mean ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://kubernetes.io/"}),"Kubernetes")," cluster. A Kubernetes cluster is a collection of node machines that allows you to run containerized applications. It is usually made up of:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Pods"),": think of a pod as one instance of your application. Pods are the smallest deployable objects in Kubernetes, and they are hosted by worker nodes."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Worker Nodes"),": worker nodes essentially run your applications and workloads. When you create a cluster from your Qovery Console, it generates the set up of worker nodes (also called \u201cinstances\u201d, \u201cEC2 instances\u201d for AWS users, or \u201cdroplets\u201d for DigitalOcean users).\nQovery allows you to define worker nodes settings, so that you end up deploying the right type of instances on your infrastructure based on your CPU, memory, storage and network performance needs."),Object(o.b)("li",{parentName:"ul"},"a ",Object(o.b)("strong",{parentName:"li"},"Control Plane")," (or ",Object(o.b)("strong",{parentName:"li"},"Master Node"),"): the control plane manages the worker nodes. Since we deploy managed Kubernetes services, the control plane is handled exclusively by your cloud provider, and left untouched by Qovery.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/cluster-overview.jpg",alt:"Application"})),Object(o.b)("p",null,"For more information on Kubernetes clusters, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://kubernetes.io/docs/concepts/overview/components/"}),"the Kubernetes documentation"),"."),Object(o.b)("h3",{id:"why-do-i-need-a-cluster"},"Why do I need a cluster?"),Object(o.b)("p",null,"Qovery is built on top of Kubernetes, which means we need Kubernetes clusters to be able to deploy and run your applications."),Object(o.b)("p",null,"Thanks to clusters, you can easily deploy several (and many) instances of the same application, so that if one fails, the others can instantly take over. Also, clusters can auto-scale, meaning that the number of worker nodes in a cluster can automatically go up or down as traffic fluctuates on your application(s), thus ensuring high availability and performance. Clusters are also extremely useful ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/blog/how-to-isolate-your-production-from-staging-with-kubernetes"}),"to isolate your production environment from your staging environment"),"."),Object(o.b)("p",null,"In short, through the use of clusters, Kubernetes provides you with a resilient, flexible and powerful infrastructure, fit for production environment needs and requirements. And with the help of Qovery, setting up and maintaining your Kubernetes clusters has never been easier."),Object(o.b)("p",null,"Qovery allows you to create and manage two types of clusters:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null})),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"th"},"Managed K8S ")),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"th"}," BETA - Single EC2 (K3s)")))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Description")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"A multi-node Kubernetes cluster managed by your cloud provider (EKS, Kapsule etc..)"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"K3s Cluster running on a single EC2 instance (single-node) ",Object(o.b)("strong",{parentName:"td"},"Available only on AWS and still in BETA"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Usage")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Hosting professional applications in production (resilient, scalable and powerful infrastructure). Scalable staging / preview / dev environments"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Hobby projects, trying out Qovery, ephemeral environments deployment")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"Cloud provider cost")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Starting from 200$/month, based on the chosen instance type"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"starting from 20$/month, based on the chosen instance type")))),Object(o.b)("br",null),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Single EC2 (K3s) is still in BETA phase and has the following limitations",Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You can\u2019t access the historical logs and thus you can access your application logs only if it's running (Since we don\u2019t have loki installed)"),Object(o.b)("li",{parentName:"ul"},"No public accessibility for DB container (we do not manage the public DNS entry for db). We will work on it in the upcoming weeks, in the meantime we will write a guide on how to connect to the DB via the ssh key / kubeconf"),Object(o.b)("li",{parentName:"ul"},"You can configure only 1 instance per application. Thus you can\u2019t change the number of instances nor activate the sticky session feature"),Object(o.b)("li",{parentName:"ul"},"Stop instance feature not ready YET"),Object(o.b)("li",{parentName:"ul"},"You can\u2019t change the cluster settings without a service downtime since we kill the instance and we spawn a new one"),Object(o.b)("li",{parentName:"ul"},"We do not manage YET the external storage"),Object(o.b)("li",{parentName:"ul"},"We do not support YET the VPC setting"),Object(o.b)("li",{parentName:"ul"},"If you want to connect via SSH, you can't get YET the instance hostname directly in the Qovery console, you need to get it from the AWS console"))),Object(o.b)("br",null),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"K3s clusters are ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-availability-zones"}),"deployed on one AWS availability zone"),". Therefore, if a network or power disruption happens on the availability zone where your K3s instance is running, your applications will no longer be available until it is solved."),Object(o.b)("p",null,"This is why we do not recommend installing K3s clusters to run professional applications in a production environment.")),Object(o.b)("h3",{id:"what-are-the-different-instance-types-available-when-creating-a-cluster"},"What are the different instance types available when creating a cluster?"),Object(o.b)("p",null,"The range of instance types available at cluster creation depends on your cloud provider:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"AWS offers over 400 instance types. You can ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://aws.amazon.com/ec2/instance-types/"}),"view their details on the official AWS website"),", as well as ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://aws.amazon.com/ec2/pricing/on-demand/"}),"their pricing"),"."),Object(o.b)("li",{parentName:"ul"},"Scaleway also offers a wide range of instance types, ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.scaleway.com/en/pricing/"}),"whose details and pricing you can view on the official Scaleway website"),".")),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Qovery supports only instance types having an x86_64 or ARM architecture.")),Object(o.b)("h4",{id:"what-is-the-default-cluster"},"What is the default cluster?"),Object(o.b)("p",null,"The default cluster is the first cluster you installed in your organization."),Object(o.b)("p",null,"When you create a new environment and leave the ",Object(o.b)("inlineCode",{parentName:"p"},"mode")," and ",Object(o.b)("inlineCode",{parentName:"p"},"cluster")," parameters set to the value ",Object(o.b)("inlineCode",{parentName:"p"},"Automatic"),", your environment is deployed to:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"the cluster defined in one of ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/deployment-rule/#environment-deployment-rules"}),"your project rules"),","),Object(o.b)("li",{parentName:"ul"},"or to the default cluster if no project rule applies.")),Object(o.b)("p",null,"For more information on deployment rules, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/project/"}),"Project"),"."),Object(o.b)("h3",{id:"how-does-qovery-handle-cluster-updates-and-upgrades"},"How does Qovery handle cluster updates and upgrades?"),Object(o.b)("p",null,"As far as cluster updates and upgrades to a newer version of Kubernetes are concerned, our Qovery engineering team handles everything in due time, so you don\u2019t even need to think about it!"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"You may notice that Qovery does not provide you with the latest Kubernetes version offered by your cloud provider. This is due to the high amount of testing we need to perform to ensure smooth upgrades with no interruptions for your applications. Our priority is always to guarantee you maximum uptime.")),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Please ",Object(o.b)("strong",{parentName:"p"},"DO NOT")," upgrade the cluster version by yourself from the cloud provider console."),Object(o.b)("p",null,"That's the whole point of Qovery, we manage this task for you so you don't have to bother.\nIf you did update by mistake, then you need to reach to Qovery team in order to get some help."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Proceeding with a cluster version upgrade outside of Qovery will prevent any future update on this cluster")," and might be irreversible preventing Qovery from properly deploying on this cluster. Most importantly will expose you to some unknown / untested areas which can put your application stability at risks.")),Object(o.b)("p",null,"Usually, we work on a given upgrade for one month of intensive testing on our end in order to make sure everything will be smooth for you. Once we are pretty confident our stack is stable, we move on with the following steps which last approximately 3 weeks:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Notify users about new version coming in approximatively 1 month before"),Object(o.b)("li",{parentName:"ol"},"Upgrade clusters for a handful of beta-tester customers (1 week)"),Object(o.b)("li",{parentName:"ol"},"Upgrade all non-production flagged clusters (1-2 week(s))"),Object(o.b)("li",{parentName:"ol"},"Upgrade all clusters")),Object(o.b)("p",null,"If, somehow the planning or timeframe for the upgrade is clashing with your business needs, you will be able to contact us so we can arrange the best timeframe for you."),Object(o.b)("h3",{id:"what-do-you-do-when-a-vulnerability-is-found"},"What do you do when a vulnerability is found?"),Object(o.b)("p",null,"Security is our main concern. When a vulnerability is found, here are the actions that we take:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"We quickly identify how significant is the impact of the vulnerability."),Object(o.b)("li",{parentName:"ol"},"We look at how we can solve or mitigate the vulnerability."),Object(o.b)("li",{parentName:"ol"},"We transparently communicate with our customers about the vulnerability to help them take the right actions.")),Object(o.b)("h2",{id:"managing-your-clusters-with-qovery"},"Managing your Clusters with Qovery"),Object(o.b)("p",null,"From the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),", you can manage the settings of the clusters you want to run on your infrastructure. The clusters are then created (or updated) by the cloud provider that hosts them."),Object(o.b)("h3",{id:"creating-a-cluster"},"Creating a Cluster"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"To install a cluster, Qovery needs a set of credentials to access your cloud provider account (example: AWS secret_access_key and access_key_id). If this is the first time you are installing a cluster with Qovery, have a look at this guide on how to get the credentials: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"here for AWS"),", ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/scaleway/#connect-your-scaleway-account"}),"here for Scaleway"),".")),Object(o.b)("p",null,"To create a cluster:"),Object(o.b)(l.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Open your ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"On the left menu bar, click on the Cluster page:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/cluster_section_access.png",alt:"Cluster Access"}))),Object(o.b)("li",null,Object(o.b)("p",null,"Click ",Object(o.b)("inlineCode",{parentName:"p"},"Add Cluster"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/add-cluster-button.png",alt:"Add Cluster Button"}))),Object(o.b)("li",null,Object(o.b)("p",null,"In the ",Object(o.b)("inlineCode",{parentName:"p"},"Create Cluster")," window enter:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Cluster name"),": enter the name of your choice for your cluster."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Description"),": enter a description to identify better your cluster."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Production cluster"),": select this option if your cluster will be used for production."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Cloud provider"),": select your cloud provider."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Region"),": select the geographical area in which you want your cluster to be hosted."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Credentials"),": select one of the existing cloud provider credentials or add a new one by clicking on ",Object(o.b)("inlineCode",{parentName:"li"},"New Credentials"),". In the New credentials window, add the credentials that you have generated on your cloud provider console (",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"Procedure for AWS account"),", ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cloud-service-provider/scaleway/#connect-your-scaleway-account"}),"Procedure for Scaleway account"),"). Added credentials can be used later to create and manage additional cluster.")),Object(o.b)("p",null,"To confirm, click ",Object(o.b)("inlineCode",{parentName:"p"},"Next"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"In the ",Object(o.b)("inlineCode",{parentName:"p"},"Set Resources")," window, select:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Cluster"),": select the cluster type to use. Please refer to this section for ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#why-do-i-need-a-cluster"}),"more information"),"."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Instance type"),": select the type of ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#what-is-a-cluster"}),"worker nodes")," you want to deploy to your cluster:"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Disk size"),": select the size of the disks to be attached to your cluster instances (to locally store container images etc..). Setting available only on AWS."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Node auto-scaling"),": define the minimum and the maximum number of worker nodes that your cluster can run. The lowest number is the number of worker nodes running on your infrastructure at any time, while the highest number is the maximum number of worker nodes that can automatically be deployed as traffic grows. Please note that a minimum of 3 worker nodes is required to deploy your EKS cluster.")),Object(o.b)("br",null),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Instance type selection from your Qovery Console has direct consequences on your cloud provider\u2019s bill. While Qovery allows you to switch to a different instance type whenever you want, it is your sole responsibility to keep an eye on your infrastructure costs, especially when you want to upsize.",Object(o.b)("p",null,"Please be aware that changing the instance type or disk size might cause a downtime for your service."),Object(o.b)("p",null,"For more information on the instance types provided by each cloud provider and their associated pricing, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#what-are-the-different-instance-types-available-when-creating-a-cluster"}),"What are the different instance types available when creating a cluster?")),Object(o.b)("p",null,"Also, before downsizing, you need to ensure that your applications will still have enough resources to run correctly.")),Object(o.b)("br",null),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"At the bottom of the window, you can see an estimate of the cost associated with the selected instance type.")),Object(o.b)("p",null,"To confirm, click ",Object(o.b)("inlineCode",{parentName:"p"},"Next"),".")),Object(o.b)("li",null,Object(o.b)("p",null,Object(o.b)("em",{parentName:"p"},"(Only for AWS K8S Clusters)")," In the ",Object(o.b)("inlineCode",{parentName:"p"},"Features")," window, select the features you want to enable on your cluster."),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"For more information, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#features"}),"Features"),"."))),Object(o.b)("li",null,Object(o.b)("p",null,Object(o.b)("em",{parentName:"p"},"(Only for Single EC2 K3S Clusters)")," In the ",Object(o.b)("inlineCode",{parentName:"p"},"Set SSH Key")," window:"),Object(o.b)("p",null,"The SSH key enables you (or Qovery on your behalf) to freely manage your cluster. For information on how to generate an SSH key, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#generating-an-ssh-key-for-your-cluster"}),"Generating an SSH Key for Your Cluster"),"."),Object(o.b)("p",null,"You can add an SSH key to your cluster settings later, however it is recommended to do it at cluster creation to avoid downtime.")),Object(o.b)("li",null,Object(o.b)("p",null,"In the ",Object(o.b)("inlineCode",{parentName:"p"},"Ready to install your cluster")," window, check that the services needed to install your cluster are correct."),Object(o.b)("p",null,"You can now press the ",Object(o.b)("inlineCode",{parentName:"p"},"Create and Install")," button."),Object(o.b)("p",null,"Your cluster is now displayed in your organization settings, featuring the ",Object(o.b)("inlineCode",{parentName:"p"},"Installing...")," status (orange status). Once your cluster is properly installed, its status turns to green and you will be able to deploy your applications on it.")))),Object(o.b)("h3",{id:"managing-your-cluster-settings"},"Managing your Cluster Settings"),Object(o.b)("p",null,"To manage the settings of an existing cluster:"),Object(o.b)(l.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Open your ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"On the left menu bar, click on the Cluster page:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/cluster_section_access.png",alt:"Cluster Access"}))),Object(o.b)("li",null,Object(o.b)("p",null,"To access your cluster settings, click on the wheel button:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/cluster_settings.png",alt:"Display Cluster Settings"}))))),Object(o.b)("p",null,"Below you can find a description of each section"),Object(o.b)("h4",{id:"general"},"General"),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"General")," tab allows you to define high-level information on your cluster:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Item"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Cluster Name"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"To edit the name of your cluster.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"To enter or edit the description of your cluster.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Production Cluster"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"To enter or edit the production flag of your cluster.")))),Object(o.b)("h4",{id:"credentials"},"Credentials"),Object(o.b)("p",null,"Here you can manage here the cloud provider credentials associated with your cluster."),Object(o.b)("p",null,"If you need to change the credentials:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"generate a new set of credentials on your cloud provider(",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/#connect-your-aws-account"}),"Procedure for AWS account"),", ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cloud-service-provider/scaleway/#connect-your-scaleway-account"}),"Procedure for Scaleway account"),")"),Object(o.b)("li",{parentName:"ul"},'create the new credential on the Qovery by opening the drop-down and selecting "New Credentials"')),Object(o.b)("p",null,"In the two dedicated fields, enter the credentials you created on your cloud provider account:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Account Provider"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Field Labels"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"AWS"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("inlineCode",{parentName:"td"},"Access Key")," and ",Object(o.b)("inlineCode",{parentName:"td"},"Secret Access Key"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Scaleway"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("inlineCode",{parentName:"td"},"Scaleway Access Key")," and ",Object(o.b)("inlineCode",{parentName:"td"},"Scaleway Project ID"))))),Object(o.b)("p",null,"Once created and associated, you need to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#updating-a-cluster"}),"updating your cluster")," to apply the change."),Object(o.b)("h4",{id:"resources"},"Resources"),Object(o.b)("p",null,"Qovery allows you to modify the resources allocated for your cluster:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"In the ",Object(o.b)("inlineCode",{parentName:"li"},"Instance type")," dropdown menu, select the type of ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#what-is-a-cluster"}),"worker node(s)")," you want to deploy to your cluster."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("em",{parentName:"li"},"(AWS users only)")," In the ",Object(o.b)("inlineCode",{parentName:"li"},"Node disk size (GB)")," field, enter the disk capacity you want to allocate to your worker node(s) (meaning how much data, in gigabytes, you want each worker node to be able to hold)."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("em",{parentName:"li"},"(EKS users only)")," On the ",Object(o.b)("inlineCode",{parentName:"li"},"Nodes auto-scaling"),", define the range of worker nodes you want to deploy to your cluster.")),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Instance type selection from your Qovery Console has direct consequences on your cloud provider\u2019s bill. While Qovery allows you to switch to a different instance type whenever you want, it is your sole responsibility to keep an eye on your infrastructure costs, especially when you want to upsize.",Object(o.b)("p",null,"For more information on the instance types provided by each cloud provider and their associated pricing, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#what-are-the-different-instance-types-available-when-creating-a-cluster"}),"What are the different instance types available when creating a cluster?"))),Object(o.b)("br",null),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"The lowest number is the number of worker nodes running on your infrastructure at any time, while the highest number is the maximum number of worker nodes that can automatically be deployed as traffic grows."),Object(o.b)("p",null,"Please note that a minimum of 3 worker nodes is required to deploy your ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"EKS cluster"),"."),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"K3s clusters")," can only have one node.")),Object(o.b)("h4",{id:"features"},"Features"),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"Features")," tab in your cluster settings allows you to check if the ",Object(o.b)("strong",{parentName:"p"},"Static IP")," and ",Object(o.b)("strong",{parentName:"p"},"Custom VPC subnet")," features are enabled on your cluster. The enabled features cannot be changed after the creation of the cluster."),Object(o.b)("h5",{id:"static-ip"},"Static IP"),Object(o.b)("p",null,"The ",Object(o.b)("strong",{parentName:"p"},"Static IP")," feature is currently only available to clusters deployed on AWS and can only be enabled at cluster creation."),Object(o.b)("p",null,"By default, when your cluster is created, its worker nodes are allocated public IP addresses, which are used for external communication. For improved security and control, the ",Object(o.b)("strong",{parentName:"p"},"Static IP")," feature allows you to ensure that outbound traffic from your cluster uses specific IP addresses."),Object(o.b)("p",null,"Here is what will be deployed on AWS:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Nat Gateways"),Object(o.b)("li",{parentName:"ul"},"Elastic IPs"),Object(o.b)("li",{parentName:"ul"},"Private subnets")),Object(o.b)("p",null,"Once set up, here is the procedure to find your static IP addresses:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"On your AWS account, select the VPC service."),Object(o.b)("li",{parentName:"ul"},"On the left menu, you\u2019ll find Elastic IP addresses. Once on it, in the Allocated IPv4 address column, you\u2019ll have your public IPs.")),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you work in a sensitive business area such as financial technology, enabling the ",Object(o.b)("strong",{parentName:"p"},"Static IP")," feature can help fulfil the security requirements of some of the external services you use, therefore making it easier for you to get whitelisted by them.")),Object(o.b)("h5",{id:"custom-vpc-subnet"},"Custom VPC Subnet"),Object(o.b)("p",null,"The ",Object(o.b)("strong",{parentName:"p"},"VPC")," feature is currently only available to clusters deployed on AWS and can only be enabled at cluster creation."),Object(o.b)("p",null,"Virtual Private Cloud (VPC) peering allows you to set up a connection between your Qovery VPC and another VPC on your AWS account. This way, you can access resources stored on your AWS VPC directly from your Qovery applications."),Object(o.b)("p",null,"A VPC can only be used if it has at least one range of IP addresses called a ",Object(o.b)("strong",{parentName:"p"},"subnet"),". When you create a cluster, Qovery automatically picks a default subnet for it. However, to perform VPC peering, you may want to define which specific VPC subnet you want to use, so that you can avoid any conflicting settings. To do so, you can enable the ",Object(o.b)("strong",{parentName:"p"},"Custom VPC Subnet")," feature on your cluster. For more information on how to set up VPC peering, ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/tutorial/aws-vpc-peering-with-qovery/"}),"see our dedicated tutorial"),"."),Object(o.b)("h4",{id:"network"},"Network"),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"Network")," tab in your cluster settings allows you to update your Qovery VPC route table so that you can perform VPC peering. For step-by-step guidelines on how to set up VPC peering, ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/tutorial/aws-vpc-peering-with-qovery/"}),"see our dedicated tutorial"),"."),Object(o.b)("h3",{id:"performing-actions-on-your-clusters"},"Performing Actions on your Clusters"),Object(o.b)("p",null,"Qovery allows you to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#updating-a-cluster"}),"update"),", ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#stopping-a-cluster"}),"stop"),", ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#restarting-a-cluster"}),"restart")," or ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#deleting-a-cluster"}),"delete")," your clusters at organization level."),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Action"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/clusters/#updating-a-cluster"}),"Updating a cluster")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"To redeploy your cluster after a change has been made to it.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/clusters/#stopping-a-cluster"}),"Stopping a cluster")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"To temporarily stop your cluster. Some services you have subscribed to via your cloud provider may still be active and incur costs when your cluster is stopped. For more information, see ",Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/clusters/#stopping-a-cluster"}),"Stopping a cluster"),".")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/clusters/#restarting-a-cluster"}),"Restarting a cluster")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"To restart your cluster after it has been temporarily stopped.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/clusters/#deleting-a-cluster"}),"Deleting a cluster")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"To delete your cluster. This is final and needs to be done properly to ensure all the services deployed by Qovery on your cloud provider's account are disabled, with no leftover cloud-related costs. For more information, see ",Object(o.b)("a",Object(a.a)({parentName:"td"},{href:"/docs/using-qovery/configuration/clusters/#deleting-a-cluster"}),"Deleting a cluster"),".")))),Object(o.b)("p",null,"To access these actions:"),Object(o.b)(l.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Open your ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"On the left menu bar, click on the Cluster page:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/cluster_section_access.png",alt:"Cluster Access"}))),Object(o.b)("li",null,Object(o.b)("p",null,"To view your cluster actions, click ",Object(o.b)("inlineCode",{parentName:"p"},"Play")," button:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/cluster_actions.png",alt:"Cluster Actions Menu"})),Object(o.b)("p",null,"A dropdown menu unfolds, featuring all the actions available on your cluster.")))),Object(o.b)("p",null,"You can follow the execution of the action via the cluster status and/or by accessing the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#logs"}),"Cluster Logs")),Object(o.b)("h4",{id:"updating-a-cluster"},"Updating a Cluster"),Object(o.b)("p",null,"If you made a change on your cluster, you need to run an update on your cluster to propagate remotely the new configuration."),Object(o.b)("p",null,"To update your cluster, select the action ",Object(o.b)("inlineCode",{parentName:"p"},"Update")," from the drop-down menu."),Object(o.b)("p",null,"A confirmation pop-up window opens before triggering the action."),Object(o.b)("p",null,"Once confirmed, the status of your cluster turns ",Object(o.b)("inlineCode",{parentName:"p"},"Updating...")," (orange status)."),Object(o.b)("p",null,"Once the update is complete, the status dot next to your cluster turns green."),Object(o.b)("h4",{id:"stopping-a-cluster"},"Stopping a Cluster"),Object(o.b)("p",null,"Qovery allows you to temporarily stop your cluster instead of deleting it."),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"When you stop a cluster from the Qovery console, only the workers nodes managed by Qovery are stopped. If you have subscribed to services via your cloud provider (load balancing, storage system, or any other managed services), they will remain active and you will be charged for them.\nFor more information, please contact your cloud provider.\nTo permanently delete a cluster and all its associated costs, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#deleting-a-cluster"}),"Deleting a Cluster"),".")),Object(o.b)("p",null,"To temporarily stop a cluster, select the ",Object(o.b)("inlineCode",{parentName:"p"},"Stop")," action from the drop-down menu.\nA confirmation pop-up window opens before triggering the action."),Object(o.b)("p",null,"Once confirmed, the status of your cluster turns to ",Object(o.b)("inlineCode",{parentName:"p"},"Pausing...")," (orange status)."),Object(o.b)("p",null,"Once the stop is complete, the status dot next to your cluster turns to grey, and the status of your cluster turns to ",Object(o.b)("inlineCode",{parentName:"p"},"Paused")," (gray status)."),Object(o.b)("h4",{id:"restarting-a-cluster"},"Restarting a Cluster"),Object(o.b)("p",null,"You can restart a cluster after it has been temporarily stopped."),Object(o.b)("p",null,"To restart your cluster, select the action ",Object(o.b)("inlineCode",{parentName:"p"},"Resume")," from the drop-down menu."),Object(o.b)("p",null,"A confirmation pop-up window opens before triggering the action."),Object(o.b)("p",null,"Once confirmed, the status of your cluster turns to ",Object(o.b)("inlineCode",{parentName:"p"},"Updating...")," (orange status)."),Object(o.b)("p",null,"Once your cluster has restarted, the status dot next to your cluster turns to green."),Object(o.b)("h4",{id:"deleting-a-cluster"},"Deleting a Cluster"),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Deleting a cluster from the Qovery console is final and cannot be reverted."),Object(o.b)("p",null,"To only temporarily stop a cluster, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#stopping-a-cluster"}),"Stopping a Cluster"),".")),Object(o.b)("p",null,"To delete a cluster, open the ",Object(o.b)("inlineCode",{parentName:"p"},"...")," section and press ",Object(o.b)("inlineCode",{parentName:"p"},"Delete Cluster"),"."),Object(o.b)("p",null,"3 options can be chosen to delete a cluster:"),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"}," 1) Default "),"\nThis is the default behaviour, this option shall be chosen every time you want to delete properly a cluster from the Qovery console AND your cloud provider account."),Object(o.b)("p",null,"This operation will delete:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Cloud provider"),": any resource created by Qovery on your cloud provider account to run this cluster will be deleted, including any application running on it."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Qovery organization"),": the configuration of this cluster and any linked environment.")),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Please note that you will have to manually delete on your cloud account:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"the S3 bucket created at cluster installation"),Object(o.b)("li",{parentName:"ul"},"the image registry linked to this cluster"),Object(o.b)("li",{parentName:"ul"},"any resource created by a lifecycle job that will not be properly deleted during the ",Object(o.b)("inlineCode",{parentName:"li"},"environment deletion")," event.")),Object(o.b)("p",null,"Check ","[this section][#cleaning-up-a-cluster-from-your-aws-account]"," to find these elements and delete them.")),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"}," 2) Delete Cluster on cloud provider and Qovery configuration ")),Object(o.b)("p",null,"This option shall be chosen when the cluster delete operation with the ",Object(o.b)("inlineCode",{parentName:"p"},"Default")," option fails since you have manually modified/deleted the RDS instances created by Qovery on your cloud provider account."),Object(o.b)("p",null,"This operation will delete:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Cloud provider"),": any resource created by Qovery on your cloud provider account to run this cluster will be deleted, including any application running on it."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Qovery organization"),": the configuration of this cluster and any linked environment.")),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Please note that you will have to manually delete on your cloud account:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"the S3 bucket created at cluster installation"),Object(o.b)("li",{parentName:"ul"},"the image registry linked to this cluster"),Object(o.b)("li",{parentName:"ul"},"any managed database that was created via Qovery"),Object(o.b)("li",{parentName:"ul"},"any resource created by a lifecycle job that will not be properly deleted during the ",Object(o.b)("inlineCode",{parentName:"li"},"environment deletion")," event.")),Object(o.b)("p",null,"Check ","[this section][#cleaning-up-a-cluster-from-your-aws-account]"," to find these elements and delete them.")),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"}," 3) Delete Qovery config only ")),Object(o.b)("p",null,"This option shall be chosen when you have already deleted any Qovery resource on your cloud account and you want to delete the cluster object from your Qovery console."),Object(o.b)("p",null,"This operation will delete:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Cloud provider"),": nothing will be removed from your cloud account. You will have to manually delete any resource created by Qovery directly from your cloud provider console."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Qovery organization"),": the configuration of this cluster and any linked environment.")),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Check ","[this section][#cleaning-up-a-cluster-from-your-aws-account]"," to find these elements and delete them.")),Object(o.b)("p",null,"Once confirmed, the cluster status turns to ",Object(o.b)("inlineCode",{parentName:"p"},"Deleting...")," (red status) and once the deletion is complete, the cluster is removed from your organization settings."),Object(o.b)("h2",{id:"logs"},"Logs"),Object(o.b)("p",null,"Qovery allows you to access the logs of your cluster in order to follow its installation or investigate any issue happening on it."),Object(o.b)("p",null,"To access the logs you need to open the cluster, click the log button"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/cluster_logs_access.png",alt:"Cluster Logs"})),Object(o.b)("p",null,"A new window is opened, displaying the logs of the cluster."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/ok-infra-logs.jpg",alt:"Cluster Logs"})),Object(o.b)("p",null,"The tab system on the right allows you to access the cluster information and, if an error occurs, the detail of the error."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/error-infra-logs.jpg",alt:"Cluster Logs"})),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"The error message should provide you enough information to solve the issue. If that's not the case, feel free to ask for support on our ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"forum")," or ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://discord.com/channels/688766934917185556/688826155611979807"}),"discord channel"))),Object(o.b)("h2",{id:"generating-an-ssh-key-for-your-cluster"},"Generating an SSH Key for Your Cluster"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"You need a public SSH key for your K3s clusters only.")),Object(o.b)("p",null," To allow Qovery or yourself to connect remotely to your K3s instance and manage it, you need to generate an SSH key and add it to your cluster settings. To do so:"),Object(o.b)(l.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null," On your computer, open a terminal.")),Object(o.b)("li",null,Object(o.b)("p",null," Run ",Object(o.b)("inlineCode",{parentName:"p"},"ssh-keygen -t"),", followed by the key type and an optional comment."),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This comment is included in the .pub file that is created. You may want to use an email address for the comment.")),Object(o.b)("p",null,"For example, you can enter ",Object(o.b)("inlineCode",{parentName:"p"},'ssh-keygen -t rsa -b 2048 -C ""'),".")),Object(o.b)("li",null,Object(o.b)("p",null,"Press ",Object(o.b)("inlineCode",{parentName:"p"},"Enter"),"."),Object(o.b)("p",null,"You should get an output similar to:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{}),"{\n Generating public/private ed25519 key pair.\n Enter file in which to save the key (/home/user/.ssh/id_ed25519):\n}\n"))),Object(o.b)("li",null,Object(o.b)("p",null," Accept the suggested filename and directory, unless you want to save your SSH key in a specific directory where you store other keys.")),Object(o.b)("li",null,Object(o.b)("p",null," Enter a passphrase:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{}),"{\n Enter passphrase (empty for no passphrase):\n Enter same passphrase again:\n}\n")),Object(o.b)("p",null," A confirmation is displayed, including information about where your files are stored.")),Object(o.b)("li",null,"Access the public key and copy its value",Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{}),"{\n cat /home/user/.ssh/id_ed25519.pub | pbcopy\n}\n")),Object(o.b)("p",null," Note: Replace the .pub key path with the one where is located the key you have previously generated")))),Object(o.b)("p",null," You can add the generated public SSH key at cluster creation (see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"Creating a Cluster"),"), or later from your cluster settings."),Object(o.b)("p",null," To do so:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"on your ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://console.qovery.com"}),"Qovery Console"),", access your ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/#managing-your-cluster-settings"}),"cluster settings"),"."),Object(o.b)("li",{parentName:"ul"},"In the ",Object(o.b)("inlineCode",{parentName:"li"},"Remote Access")," tab, enter your SSH key and click ",Object(o.b)("inlineCode",{parentName:"li"},"Save"),"."),Object(o.b)("li",{parentName:"ul"},"Launch the ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/clusters/"}),"Update Cluster")," action to propagate the new key.")),Object(o.b)("h2",{id:"use-custom-domain-and-wildcard-tls-for-the-whole-cluster-beta"},"Use custom domain and wildcard TLS for the whole cluster (beta)"),Object(o.b)("p",null,"By default, Qovery provides a domain (ex ",Object(o.b)("inlineCode",{parentName:"p"},"bool.sh"),") on every deployed cluster. It is used to provide a DNS and TLS certificate to every application requiring external access on a cluster."),Object(o.b)("p",null,"You can customize the domain for every application. However, when it comes to having more than 100 custom domains with the same domain you will hit ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://letsencrypt.org/docs/rate-limits/"}),"Let's Encrypt quotas"),"."),Object(o.b)("p",null,"To overcome this issue, you can use a wildcard TLS certificate for the whole cluster. It will allow you to have as many DNS records for a single domain as you want on the same cluster with a single TLS certificate."),Object(o.b)("p",null,"At the moment, Qovery only supports wildcard TLS certificates with ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.cloudflare.com/"}),"Cloudflare"),". To use it, you need to have a Cloudflare account and a domain name managed by Cloudflare. If you don't have one, you can create a free account and transfer your domain to Cloudflare."),Object(o.b)("p",null,"Once you have a Cloudflare account and a domain name managed by Cloudflare, you need to create a Cloudflare API token. Go into your Cloudflare account, click on your profile picture, then ",Object(o.b)("inlineCode",{parentName:"p"},"My Profile"),". In the ",Object(o.b)("inlineCode",{parentName:"p"},"API Tokens")," section, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create Token"),". In the ",Object(o.b)("inlineCode",{parentName:"p"},"Create Custom Token")," section, select the following permissions:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"API token a descriptive name: Qovery domain ",Object(o.b)("inlineCode",{parentName:"li"},"your domain name")),Object(o.b)("li",{parentName:"ul"},"Permissions:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Zone - DNS - Edit"),Object(o.b)("li",{parentName:"ul"},"Zone - Zone - Read"))),Object(o.b)("li",{parentName:"ul"},"Zone Resources:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Include - Specific zone - ",Object(o.b)("inlineCode",{parentName:"li"},"your domain name"))))),Object(o.b)("p",null,"To finish, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Continue to Summary")," and ",Object(o.b)("inlineCode",{parentName:"p"},"Create Token"),". Save the token somewhere safe, you will need it later."),Object(o.b)("p",null,"Prepare the Token, the Cloudflare account email and the domain to be set on your cluster. Now contact Qovery and request to use your domain."),Object(o.b)("h2",{id:"cleaning-up-a-cluster-from-your-aws-account"},"Cleaning up a Cluster from your AWS Account"),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"The following troubleshooting procedure is intended for AWS users who did not properly delete their cluster before revoking Qovery's access to their platform."),Object(o.b)("p",null,"To properly delete your clusters and avoid any unexpected issues or costs, see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#deleting-a-cluster"}),"Deleting a Cluster"),".")),Object(o.b)("p",null,"To clean up a Qovery cluster from your cloud provider account, go to ",Object(o.b)("inlineCode",{parentName:"p"},"AWS Console"),">",Object(o.b)("inlineCode",{parentName:"p"},"Services"),">",Object(o.b)("inlineCode",{parentName:"p"},"Management & Governance"),">",Object(o.b)("inlineCode",{parentName:"p"},"Resource Groups & Tag Editor"),"> ",Object(o.b)("inlineCode",{parentName:"p"},"Create Resource Group"),":"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/aws-console-cluster-cleanup.jpg",alt:"AWS Console Cluster Cleanup"})),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Step"),Object(o.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"1"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"In the ",Object(o.b)("inlineCode",{parentName:"td"},"Group type")," area, select ",Object(o.b)("inlineCode",{parentName:"td"},"Tag based"),".")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"2"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"In the ",Object(o.b)("inlineCode",{parentName:"td"},"Tags")," field of the ",Object(o.b)("inlineCode",{parentName:"td"},"Grouping criteria")," area, enter ",Object(o.b)("inlineCode",{parentName:"td"},"ClusterId"),".")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"3"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Click ",Object(o.b)("inlineCode",{parentName:"td"},"Add"),".")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"4"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Click ",Object(o.b)("inlineCode",{parentName:"td"},"Preview Resources"),". ",Object(o.b)("br",null)," All your Qovery clusters are now displayed in the ",Object(o.b)("inlineCode",{parentName:"td"},"Group resources")," table, and you can delete them by hand.")))))}p.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},b=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),b=u(n),d=a,m=b["".concat(l,".").concat(d)]||b[d]||p[d]||o;return n?r.a.createElement(m,c({ref:t},s,{components:n})):r.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=d;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c.mdxType="string"==typeof e?e:a,l[1]=c;for(var s=2;s1?arguments[1]:void 0,n),i=l>2?arguments[2]:void 0,s=void 0===i?n:r(i,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),l=n(39),c=n(432),i=n(20),s=n.n(i);t.a=function(e){var t,n=e.to,i=e.href,u=n||i,b=Object(c.a)(u),p=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,b]),u&&b?o.a.createElement(l.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,a;d&&e&&b&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),l=n(423),c=n.n(l);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,l=e.leftIcon,i=e.rightIcon,s=e.size,u=e.target,b=e.to,p=c()("jump-to","jump-to--"+s,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},l&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+l})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(i||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:b,target:u,className:p},d):r.a.createElement(o.a,{to:b,className:p},d)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},433:function(e,t,n){"use strict";var a=n(435),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var l=[];return r.slice().forEach((function(e){void 0!==e&&l.push(n(a,e,l.length))})),l.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(423),n(433)),l=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,i={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+l.a.stringify(i),u=Object(a.useState)(null),b=u[0],p=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/dea3d534.694e9d54.js.LICENSE.txt b/dc00a797.16ee6cdf.js.LICENSE.txt similarity index 100% rename from dea3d534.694e9d54.js.LICENSE.txt rename to dc00a797.16ee6cdf.js.LICENSE.txt diff --git a/7aa59ca3.491bd2a3.js b/de0a75d9.b9fd23b0.js similarity index 80% rename from 7aa59ca3.491bd2a3.js rename to de0a75d9.b9fd23b0.js index b0a8062a6e..a7fb0c81ab 100644 --- a/7aa59ca3.491bd2a3.js +++ b/de0a75d9.b9fd23b0.js @@ -1,2 +1,2 @@ -/*! For license information please see 7aa59ca3.491bd2a3.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[126],{277:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return d}));var o=n(1),a=n(9),r=(n(0),n(422)),c=n(431),i=n(421),l=n(426),u=(n(429),{last_modified_on:"2023-03-30",$schema:"/.meta/.schemas/guides.json",title:"How to connect to your EKS cluster with kubectl",description:"How to connect to your EKS cluster using kubectl",author_github:"https://github.com/l0ck3",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to connect to your EKS cluster with kubectl",description:"How to connect to your EKS cluster using kubectl",permalink:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl",readingTime:"5 min read",source:"@site/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to connect to your EKS cluster with kubectl",truncated:!1,prevItem:{title:"How to connect to a managed MongoDB instance on AWS",permalink:"/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws"},nextItem:{title:"How to create an RDS instance through the AWS console",permalink:"/guides/tutorial/how-to-create-an-rds-instance-through-aws-console"}},b=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],p={rightToc:b};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(r.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Qovery makes it easy to create an EKS cluster on your AWS account and manage the deployment of applications on it. But you still might want to execute operations on it via ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," like you would on any other Kubernetes cluster."),Object(r.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have an existing EKS cluster manages by Qovery"),Object(r.b)("li",{parentName:"ul"},"You have deployed an application on this cluster with Qovery"))),Object(r.b)(i.a,{type:"warning",mdxType:"Alert"},"Be aware that any operation you do manually on your cluster could conflict with Qovery. We would advise to not use this method for anything else than connecting to a container with `kubectl exec`"),Object(r.b)("h2",{id:"goal"},"Goal"),Object(r.b)("p",null,"This tutorial will show you how to access a Qovery managed cluster on AWS with ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," and shell into a running application container."),Object(r.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,Object(r.b)("h4",{id:"install-and-configure-your-toolchain"},"Install and configure your toolchain"),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"kubectl")),Object(r.b)("p",null,"To interact with your cluster, you will need ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," installed.\n",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://kubernetes.io/docs/tasks/tools/"}),"https://kubernetes.io/docs/tasks/tools/")),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"AWS CLI")),Object(r.b)("p",null,"The AWS CLI must be installed and configured on your machine.\n",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"}),"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"))),Object(r.b)("li",null,Object(r.b)("h4",{id:"add-your-iam-user-to-the-admin-group"},"Add your IAM user to the Admin group"),Object(r.b)("p",null,"Since ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," will use IAM to authenticate, you need to add your IAM user (the one the AWS CLI is authenticated with) to the ",Object(r.b)("inlineCode",{parentName:"p"},"Admins")," group you created when setting up Qovery."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/how-to-connect-to-your-eks-cluster-with-kubectl/1.png",alt:"AWS console - add admin user"}))),Object(r.b)("li",null,Object(r.b)("h4",{id:"download-the-kubeconfig-file"},"Download the Kubeconfig file"),Object(r.b)("p",null,"To connect to your EKS cluster you will need to set a context to ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl"),". This is done with a ",Object(r.b)("inlineCode",{parentName:"p"},"Kubeconfig")," file."),Object(r.b)("p",null,"When installing a new cluster, Qovery stores it in an S3 bucket on your account."),Object(r.b)("p",null,"Go to S3, find the Qovery bucket, and download the file. The bucket should be named something like ",Object(r.b)("inlineCode",{parentName:"p"},"qovery-kubeconfigs-.yaml"),"."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/how-to-connect-to-your-eks-cluster-with-kubectl/2.png",alt:"AWS console - get Kubeconfig"}))),Object(r.b)("li",null,Object(r.b)("h4",{id:"set-the-context-for-kubectl"},"Set the context for kubectl"),Object(r.b)("p",null,"To set the context for kubectl, run the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"export KUBECONFIG=\n")),Object(r.b)("p",null,"You can check that it works with a kubectl command. For example:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get nodes\n")),Object(r.b)("p",null,"You are good to go if you see an output like the following:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"NAME STATUS ROLES AGE VERSION\nzb81b1cd4-ub667 Ready 14d v1.19.15\nzb81b1cd4-ujkm8 Ready 24d v1.19.15\nzb81b1cd4-ujkmc Ready 24d v1.19.15\n"))),Object(r.b)("li",null,Object(r.b)("h4",{id:"get-your-application-namespace"},"Get your application namespace"),Object(r.b)("p",null,"When you deploy an application, Qovery will create a separate namespace for each environment on your Kubernetes cluster."),Object(r.b)("p",null,"You can get the list of the namespaces on your cluster using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get namespaces\n")),Object(r.b)("p",null,"You will get an output similar to this one:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"NAME STATUS AGE\ncert-manager Active 44d\ndefault Active 44d\nkube-node-lease Active 44d\nkube-public Active 44d\nkube-system Active 44d\nlogging Active 44d\nnginx-ingress Active 44d\nprometheus Active 44d\nqovery Active 44d\nz0121531e-zb2daee81 Active 35d\nz016bd165-zeb51c37e Active 31d\n")),Object(r.b)("p",null,"The Qovery application namespaces are the ones begining with ",Object(r.b)("inlineCode",{parentName:"p"},"z"),"."),Object(r.b)("p",null,"In case you have several environments running, to identify the right one:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Go to the Qovery console"),Object(r.b)("li",{parentName:"ul"},"Go to the right environment")),Object(r.b)("p",null,"In your URL bar you'll have something like:"),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"https://console.qovery.com/platform/organization//projects//environments//applications")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/how-to-connect-to-your-eks-cluster-with-kubectl/3.png",alt:"Qovery console - environment"})),Object(r.b)("p",null,"The environment namespace is defined the following way: ",Object(r.b)("inlineCode",{parentName:"p"},"z-z"),"."),Object(r.b)("p",null,"The short ID is the first section of the ID. For example, given the following ID: ",Object(r.b)("inlineCode",{parentName:"p"},"e0aabc0d-99cb-4867-ad39-332d6162c32c"),", the short ID will be ",Object(r.b)("inlineCode",{parentName:"p"},"e0aabc0d"),"."),Object(r.b)("p",null,"The following environment URL: ",Object(r.b)("inlineCode",{parentName:"p"},"https://console.qovery.com/platform/organization//projects/e0aabc0d-99cb-4867-ad39-332d6162c32c/environments/b91d2eb8-a850-49b5-8626-ade7afc4a28b/applications"),"\nwould translate to the following namespace: ",Object(r.b)("inlineCode",{parentName:"p"},"ze0aabc0d-zb91d2eb8"),".")),Object(r.b)("li",null,Object(r.b)("h4",{id:"identify-the-right-application-pods"},"Identify the right application pod(s)"),Object(r.b)("p",null,"To list the pods running in your environment namespace, run the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get pods --namespace \n")),Object(r.b)("p",null,"The output should be similar to this one:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"NAME READY STATUS RESTARTS AGE\napp-z2fc29b74-5db6745975-nrw8v 1/1 Running 0 29h\napp-zabbcf976-74f969f848-kzp87 1/1 Running 0 29h\n")),Object(r.b)("p",null,"The same principle goes for finding the right application pod. Go to the application page on the Qovery console."),Object(r.b)("p",null,"You'll get an URL looking like this:"),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"https://console.qovery.com/platform/organization//projects//environments//applications/abbcf976-27a1-4531-9cdd-e4d15d7b2c27/summary")),Object(r.b)("p",null,"Get the short ID of our application, in our case ",Object(r.b)("inlineCode",{parentName:"p"},"abbcf976")," which means the application pod name will start with ",Object(r.b)("inlineCode",{parentName:"p"},"app-zabbcf976"),"."),Object(r.b)("p",null,"In case you setup your app to run multiple replicas, it is possible that you see several pods begining with the same string. You can pick any of them."),Object(r.b)("p",null,"In our case the right pod corresponding to our application would be ",Object(r.b)("inlineCode",{parentName:"p"},"app-zabbcf976-74f969f848-kzp87"),".")),Object(r.b)("li",null,Object(r.b)("h4",{id:"shell-into-the-container"},"Shell into the container"),Object(r.b)("p",null,"To get a shell access to the container running inside the application pod, all you have to do is:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl exec -ti --namespace -- sh\n")),Object(r.b)("p",null,"This will open a shell inside of your application container. You can now execute any command you need.")))),Object(r.b)("h2",{id:"conclusion"},"Conclusion"),Object(r.b)("p",null,"Qovery helps you manage your Kubernetes cluster and deploy your applications on it while still giving you the power of a full access to your cluster."),Object(r.b)(i.a,{type:"note",mdxType:"Alert"},"Soon you will be able to achieve the same thing through the Qovery CLI."))}d.isMDXComponent=!0},420:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),b=s(n),d=o,m=b["".concat(c,".").concat(d)]||b[d]||p[d]||r;return n?a.a.createElement(m,i({ref:t},u,{components:n})):a.a.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,c=new Array(r);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var u=2;u1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>i;)t[i++]=e;return t}},425:function(e,t,n){var o=n(28).f,a=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in a||n(10)&&o(a,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var o=n(0),a=n.n(o),r=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var o=n(1),a=n(0),r=n.n(a),c=n(39),i=n(430),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,b=Object(i.a)(s),p=Object(a.useRef)(!1),d=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(s),function(){d&&t&&t.disconnect()}}),[s,d,b]),s&&b?r.a.createElement(c.b,Object(o.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,o;d&&e&&b&&(n=e,o=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:s})):r.a.createElement("a",Object(o.a)({},e,{href:s}))}},428:function(e,t,n){"use strict";var o=n(432),a=n(51);function r(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),r=t.length>0?t.join("="):void 0;r=void 0===r?null:decodeURIComponent(r),n(decodeURIComponent(a),r,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[r(t,e),"[",o,"]"].join(""):[r(t,e),"[",r(o,e),"]=",r(n,e)].join("")};case"bracket":return function(t,n){return null===n?r(t,e):[r(t,e),"[]=",r(n,e)].join("")};default:return function(t,n){return null===n?r(t,e):[r(t,e),"=",r(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var a=e[o];if(void 0===a)return"";if(null===a)return r(o,t);if(Array.isArray(a)){var c=[];return a.slice().forEach((function(e){void 0!==e&&c.push(n(o,e,c.length))})),c.join("&")}return r(o,t)+"="+r(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=n(427),c=n(420),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,c=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,b=e.to,p=i()("jump-to","jump-to--"+u,n),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},c&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+c})),a.a.createElement("div",{className:"jump-to--main"},o?a.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?a.a.createElement("a",{href:b,target:s,className:p},d):a.a.createElement(r.a,{to:b,className:p},d)}},430:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},431:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=(n(420),n(428)),c=n.n(r);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,r=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(o.useState)(null),b=s[0],p=s[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!r&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see de0a75d9.b9fd23b0.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[235],{387:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return d}));var o=n(1),a=n(9),r=(n(0),n(425)),c=n(434),i=n(424),l=n(429),u=(n(431),{last_modified_on:"2023-03-30",$schema:"/.meta/.schemas/guides.json",title:"How to connect to your EKS cluster with kubectl",description:"How to connect to your EKS cluster using kubectl",author_github:"https://github.com/l0ck3",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to connect to your EKS cluster with kubectl",description:"How to connect to your EKS cluster using kubectl",permalink:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl",readingTime:"5 min read",source:"@site/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to connect to your EKS cluster with kubectl",truncated:!1,prevItem:{title:"How to connect to a managed MongoDB instance on AWS",permalink:"/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws"},nextItem:{title:"How to create an RDS instance through the AWS console",permalink:"/guides/tutorial/how-to-create-an-rds-instance-through-aws-console"}},b=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],p={rightToc:b};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(r.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Qovery makes it easy to create an EKS cluster on your AWS account and manage the deployment of applications on it. But you still might want to execute operations on it via ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," like you would on any other Kubernetes cluster."),Object(r.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"You have an existing EKS cluster manages by Qovery"),Object(r.b)("li",{parentName:"ul"},"You have deployed an application on this cluster with Qovery"))),Object(r.b)(i.a,{type:"warning",mdxType:"Alert"},"Be aware that any operation you do manually on your cluster could conflict with Qovery. We would advise to not use this method for anything else than connecting to a container with `kubectl exec`"),Object(r.b)("h2",{id:"goal"},"Goal"),Object(r.b)("p",null,"This tutorial will show you how to access a Qovery managed cluster on AWS with ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," and shell into a running application container."),Object(r.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,Object(r.b)("h4",{id:"install-and-configure-your-toolchain"},"Install and configure your toolchain"),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"kubectl")),Object(r.b)("p",null,"To interact with your cluster, you will need ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," installed.\n",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://kubernetes.io/docs/tasks/tools/"}),"https://kubernetes.io/docs/tasks/tools/")),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"AWS CLI")),Object(r.b)("p",null,"The AWS CLI must be installed and configured on your machine.\n",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"}),"https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html"))),Object(r.b)("li",null,Object(r.b)("h4",{id:"add-your-iam-user-to-the-admin-group"},"Add your IAM user to the Admin group"),Object(r.b)("p",null,"Since ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl")," will use IAM to authenticate, you need to add your IAM user (the one the AWS CLI is authenticated with) to the ",Object(r.b)("inlineCode",{parentName:"p"},"Admins")," group you created when setting up Qovery."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/how-to-connect-to-your-eks-cluster-with-kubectl/1.png",alt:"AWS console - add admin user"}))),Object(r.b)("li",null,Object(r.b)("h4",{id:"download-the-kubeconfig-file"},"Download the Kubeconfig file"),Object(r.b)("p",null,"To connect to your EKS cluster you will need to set a context to ",Object(r.b)("inlineCode",{parentName:"p"},"kubectl"),". This is done with a ",Object(r.b)("inlineCode",{parentName:"p"},"Kubeconfig")," file."),Object(r.b)("p",null,"When installing a new cluster, Qovery stores it in an S3 bucket on your account."),Object(r.b)("p",null,"Go to S3, find the Qovery bucket, and download the file. The bucket should be named something like ",Object(r.b)("inlineCode",{parentName:"p"},"qovery-kubeconfigs-.yaml"),"."),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/how-to-connect-to-your-eks-cluster-with-kubectl/2.png",alt:"AWS console - get Kubeconfig"}))),Object(r.b)("li",null,Object(r.b)("h4",{id:"set-the-context-for-kubectl"},"Set the context for kubectl"),Object(r.b)("p",null,"To set the context for kubectl, run the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"export KUBECONFIG=\n")),Object(r.b)("p",null,"You can check that it works with a kubectl command. For example:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get nodes\n")),Object(r.b)("p",null,"You are good to go if you see an output like the following:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"NAME STATUS ROLES AGE VERSION\nzb81b1cd4-ub667 Ready 14d v1.19.15\nzb81b1cd4-ujkm8 Ready 24d v1.19.15\nzb81b1cd4-ujkmc Ready 24d v1.19.15\n"))),Object(r.b)("li",null,Object(r.b)("h4",{id:"get-your-application-namespace"},"Get your application namespace"),Object(r.b)("p",null,"When you deploy an application, Qovery will create a separate namespace for each environment on your Kubernetes cluster."),Object(r.b)("p",null,"You can get the list of the namespaces on your cluster using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get namespaces\n")),Object(r.b)("p",null,"You will get an output similar to this one:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"NAME STATUS AGE\ncert-manager Active 44d\ndefault Active 44d\nkube-node-lease Active 44d\nkube-public Active 44d\nkube-system Active 44d\nlogging Active 44d\nnginx-ingress Active 44d\nprometheus Active 44d\nqovery Active 44d\nz0121531e-zb2daee81 Active 35d\nz016bd165-zeb51c37e Active 31d\n")),Object(r.b)("p",null,"The Qovery application namespaces are the ones begining with ",Object(r.b)("inlineCode",{parentName:"p"},"z"),"."),Object(r.b)("p",null,"In case you have several environments running, to identify the right one:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Go to the Qovery console"),Object(r.b)("li",{parentName:"ul"},"Go to the right environment")),Object(r.b)("p",null,"In your URL bar you'll have something like:"),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"https://console.qovery.com/platform/organization//projects//environments//applications")),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/how-to-connect-to-your-eks-cluster-with-kubectl/3.png",alt:"Qovery console - environment"})),Object(r.b)("p",null,"The environment namespace is defined the following way: ",Object(r.b)("inlineCode",{parentName:"p"},"z-z"),"."),Object(r.b)("p",null,"The short ID is the first section of the ID. For example, given the following ID: ",Object(r.b)("inlineCode",{parentName:"p"},"e0aabc0d-99cb-4867-ad39-332d6162c32c"),", the short ID will be ",Object(r.b)("inlineCode",{parentName:"p"},"e0aabc0d"),"."),Object(r.b)("p",null,"The following environment URL: ",Object(r.b)("inlineCode",{parentName:"p"},"https://console.qovery.com/platform/organization//projects/e0aabc0d-99cb-4867-ad39-332d6162c32c/environments/b91d2eb8-a850-49b5-8626-ade7afc4a28b/applications"),"\nwould translate to the following namespace: ",Object(r.b)("inlineCode",{parentName:"p"},"ze0aabc0d-zb91d2eb8"),".")),Object(r.b)("li",null,Object(r.b)("h4",{id:"identify-the-right-application-pods"},"Identify the right application pod(s)"),Object(r.b)("p",null,"To list the pods running in your environment namespace, run the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl get pods --namespace \n")),Object(r.b)("p",null,"The output should be similar to this one:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"NAME READY STATUS RESTARTS AGE\napp-z2fc29b74-5db6745975-nrw8v 1/1 Running 0 29h\napp-zabbcf976-74f969f848-kzp87 1/1 Running 0 29h\n")),Object(r.b)("p",null,"The same principle goes for finding the right application pod. Go to the application page on the Qovery console."),Object(r.b)("p",null,"You'll get an URL looking like this:"),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"https://console.qovery.com/platform/organization//projects//environments//applications/abbcf976-27a1-4531-9cdd-e4d15d7b2c27/summary")),Object(r.b)("p",null,"Get the short ID of our application, in our case ",Object(r.b)("inlineCode",{parentName:"p"},"abbcf976")," which means the application pod name will start with ",Object(r.b)("inlineCode",{parentName:"p"},"app-zabbcf976"),"."),Object(r.b)("p",null,"In case you setup your app to run multiple replicas, it is possible that you see several pods begining with the same string. You can pick any of them."),Object(r.b)("p",null,"In our case the right pod corresponding to our application would be ",Object(r.b)("inlineCode",{parentName:"p"},"app-zabbcf976-74f969f848-kzp87"),".")),Object(r.b)("li",null,Object(r.b)("h4",{id:"shell-into-the-container"},"Shell into the container"),Object(r.b)("p",null,"To get a shell access to the container running inside the application pod, all you have to do is:"),Object(r.b)("pre",null,Object(r.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"kubectl exec -ti --namespace -- sh\n")),Object(r.b)("p",null,"This will open a shell inside of your application container. You can now execute any command you need.")))),Object(r.b)("h2",{id:"conclusion"},"Conclusion"),Object(r.b)("p",null,"Qovery helps you manage your Kubernetes cluster and deploy your applications on it while still giving you the power of a full access to your cluster."),Object(r.b)(i.a,{type:"note",mdxType:"Alert"},"Soon you will be able to achieve the same thing through the Qovery CLI."))}d.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),s=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=s(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),b=s(n),d=o,m=b["".concat(c,".").concat(d)]||b[d]||p[d]||r;return n?a.a.createElement(m,i({ref:t},u,{components:n})):a.a.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,c=new Array(r);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var u=2;u1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>i;)t[i++]=e;return t}},428:function(e,t,n){var o=n(28).f,a=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in a||n(10)&&o(a,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var o=n(0),a=n.n(o),r=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var o=n(1),a=n(0),r=n.n(a),c=n(39),i=n(432),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,b=Object(i.a)(s),p=Object(a.useRef)(!1),d=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(s),function(){d&&t&&t.disconnect()}}),[s,d,b]),s&&b?r.a.createElement(c.b,Object(o.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,o;d&&e&&b&&(n=e,o=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),o())}))}))).observe(n))},to:s})):r.a.createElement("a",Object(o.a)({},e,{href:s}))}},431:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=n(430),c=n(423),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,o=e.badge,c=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,b=e.to,p=i()("jump-to","jump-to--"+u,n),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},c&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+c})),a.a.createElement("div",{className:"jump-to--main"},o?a.a.createElement("span",{className:"badge badge--primary badge--right"},o):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?a.a.createElement("a",{href:b,target:s,className:p},d):a.a.createElement(r.a,{to:b,className:p},d)}},432:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},433:function(e,t,n){"use strict";var o=n(435),a=n(51);function r(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),r=t.length>0?t.join("="):void 0;r=void 0===r?null:decodeURIComponent(r),n(decodeURIComponent(a),r,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[r(t,e),"[",o,"]"].join(""):[r(t,e),"[",r(o,e),"]=",r(n,e)].join("")};case"bracket":return function(t,n){return null===n?r(t,e):[r(t,e),"[]=",r(n,e)].join("")};default:return function(t,n){return null===n?r(t,e):[r(t,e),"=",r(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var a=e[o];if(void 0===a)return"";if(null===a)return r(o,t);if(Array.isArray(a)){var c=[];return a.slice().forEach((function(e){void 0!==e&&c.push(n(o,e,c.length))})),c.join("&")}return r(o,t)+"="+r(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=(n(423),n(433)),c=n.n(r);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,r=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(o.useState)(null),b=s[0],p=s[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!r&&!b&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/deef6d59.67094f5c.js.LICENSE.txt b/de0a75d9.b9fd23b0.js.LICENSE.txt similarity index 100% rename from deef6d59.67094f5c.js.LICENSE.txt rename to de0a75d9.b9fd23b0.js.LICENSE.txt diff --git a/66bbed7b.198e1a0b.js b/dea3d534.252309a6.js similarity index 94% rename from 66bbed7b.198e1a0b.js rename to dea3d534.252309a6.js index 6fed4aa677..fce748e737 100644 --- a/66bbed7b.198e1a0b.js +++ b/dea3d534.252309a6.js @@ -1,2 +1,2 @@ -/*! For license information please see 66bbed7b.198e1a0b.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[116],{267:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return p})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var a=n(1),r=n(9),o=(n(0),n(422)),i=n(431),c=n(426),l=n(421),s={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Microservices",description:"How to deploy microservices with Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: guide","technology: qovery"]},p={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Microservices",description:"How to deploy microservices with Qovery",permalink:"/guides/advanced/microservices",readingTime:"6 min read",source:"@site/guides/advanced/microservices.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Microservices",truncated:!1,prevItem:{title:"Managing Environment Variables in React (create-react-app)",permalink:"/guides/tutorial/managing-env-variables-in-create-react-app"},nextItem:{title:"Migrate your application from Heroku to AWS",permalink:"/guides/tutorial/migrate-your-application-from-heroku-to-aws"}},u=[{value:"Deploy Application A",id:"deploy-application-a",children:[{value:"Exposing public API",id:"exposing-public-api",children:[]}]},{value:"Deploy Application B",id:"deploy-application-b",children:[]},{value:"Deploy Database",id:"deploy-database",children:[]},{value:"Use the database",id:"use-the-database",children:[]},{value:"Consume internal APIs",id:"consume-internal-apis",children:[]},{value:"Consume the public API in the frontend application",id:"consume-the-public-api-in-the-frontend-application",children:[]},{value:"Summary",id:"summary",children:[]},{value:"Q&A",id:"qa",children:[]}],b={rightToc:u};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)(l.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"This guide is a bit outdated. We are working on a new version of it. Stay tuned!")),Object(o.b)(c.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have already deployed an application with Qovery"),Object(o.b)("li",{parentName:"ul"},"You are familiar with the concept of Microservices"))),Object(o.b)("p",null,"In this guide, we'll deploy a set of microservices, a database and a frontend UI application that consumes our public API.\nOur backend microservices will communicate on a secure internal network, not accessible from the outside.\nOur front-end application will consume the API only from the publicly exposed application."),Object(o.b)("p",null,"The schema of what we want to achieve:"),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros.jpg",alt:"Microservices"})),Object(o.b)("p",null,"As you can see in the picture:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"we have two backend applications (",Object(o.b)("strong",{parentName:"li"},"App A")," and ",Object(o.b)("strong",{parentName:"li"},"App B"),")"),Object(o.b)("li",{parentName:"ul"},"one of them (",Object(o.b)("strong",{parentName:"li"},"App B"),") connected to a database"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"App A")," exposes a public API that is consumed by API clients (our frontend application run in users browsers)."),Object(o.b)("li",{parentName:"ul"},"additionally, we host our frontend application (",Object(o.b)("strong",{parentName:"li"},"UI"),") on Qovery so that users can access it directly in their browsers.")),Object(o.b)("p",null,"What differentiates Qovery from most other similar platforms is its first-class support of microservices. At Qovery, your project can be easily\ncomposed of multiple applications. It's up to you to decide how to build your system, but Qovery enables you to easily and safely communicate between your backend applications, databases, and frontend websites."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h2",{id:"deploy-application-a"},"Deploy Application A"),Object(o.b)(l.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This guide assumes you already know how to deploy applications. If you have any problems, refer to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"this video guide"),".")),Object(o.b)("p",null,"In the first step, deploy an application named ",Object(o.b)("strong",{parentName:"p"},"APP_A")," in your environment."),Object(o.b)("p",null,"Assumptions:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The app exposes REST API over HTTP on port 8080"),Object(o.b)("li",{parentName:"ul"},"The app name is ",Object(o.b)("strong",{parentName:"li"},"APP_A"))),Object(o.b)("p",null,"After the application is created, let's expose the API publicly - it will be used later on by our frontend application."),Object(o.b)("h3",{id:"exposing-public-api"},"Exposing public API"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate to ",Object(o.b)("strong",{parentName:"li"},"APP_A")," application settings"),Object(o.b)("li",{parentName:"ul"},"Select ",Object(o.b)("strong",{parentName:"li"},"Port")),Object(o.b)("li",{parentName:"ul"},"Add port 8080")),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros-1.png",alt:"Microservices"})),Object(o.b)("p",null,"This is it. By default, Qovery exposes your ports publicly over HTTPS on port 443, so the app should be publicly accessible and reachable later on by our frontend application.")),Object(o.b)("li",null,Object(o.b)("h2",{id:"deploy-application-b"},"Deploy Application B"),Object(o.b)("p",null,"In the second step, deploy an application named ",Object(o.b)("strong",{parentName:"p"},"APP_B")," in your environment."),Object(o.b)("p",null,"Assumptions:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The app exposes REST API over HTTP on port 8080"),Object(o.b)("li",{parentName:"ul"},"The app name is ",Object(o.b)("strong",{parentName:"li"},"APP_B")),Object(o.b)("li",{parentName:"ul"},"The app is ready to use a PostgreSQL client to connect to a PostgreSQL database")),Object(o.b)("p",null,"Steps to do:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate to ",Object(o.b)("strong",{parentName:"li"},"APP_B")," application settings"),Object(o.b)("li",{parentName:"ul"},"Select ",Object(o.b)("strong",{parentName:"li"},"Port")),Object(o.b)("li",{parentName:"ul"},"Add port 8080"),Object(o.b)("li",{parentName:"ul"},"Click ",Object(o.b)("strong",{parentName:"li"},"Advanced")," settings in the 8080 port"),Object(o.b)("li",{parentName:"ul"},"Remove the check from the ",Object(o.b)("strong",{parentName:"li"},"Publicly Accessible")," field")),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros-2.png",alt:"Microservices"})),Object(o.b)(l.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"It will make your ",Object(o.b)("strong",{parentName:"p"},"APP_B")," application not reachable publicly. It will be only reachable on the internal network by other microservices in your environment."))),Object(o.b)("li",null,Object(o.b)("h2",{id:"deploy-database"},"Deploy Database"),Object(o.b)("p",null,"In this step, we'll deploy a PostgreSQL database that we'll consume in ",Object(o.b)("strong",{parentName:"p"},"APP_B")," in the next step."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate to the environment in which you previously deployed your apps"),Object(o.b)("li",{parentName:"ul"},"Create a new PostgreSQL database named ",Object(o.b)("strong",{parentName:"li"},"MY_DB"))),Object(o.b)(l.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This guide assumes you already know how to deploy databases. If you have any problems, refer to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"this video guide"),"."))),Object(o.b)("li",null,Object(o.b)("h2",{id:"use-the-database"},"Use the database"),Object(o.b)("p",null,"In this step, we'll make use of our database in ",Object(o.b)("strong",{parentName:"p"},"APP_B")),Object(o.b)("p",null,"All you need to do to consume your database in ",Object(o.b)("strong",{parentName:"p"},"APP_B")," is to configure your PostgreSQL client to use ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," secrets injected by Qovery.\nYou can read more about this concept ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-a-database"}),"here"),"."),Object(o.b)("p",null,"If your ",Object(o.b)("strong",{parentName:"p"},"APP_B")," is a Node.js application, this examplary code snippet will work well:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"const { Client } = require('pg')\n\nconst client = new Client({\n host: process.env.QOVERY_DATABASE_MY_DB_HOST,\n port: process.env.QOVERY_DATABASE_MY_DB_PORT,\n user: process.env.QOVERY_DATABASE_MY_DB_USER,\n password: process.env.QOVERY_DATABASE_MY_DB_PASSWORD,\n})\n\nclient.connect(err => {\n if (err) {\n console.error('connection error', err.stack)\n } else {\n console.log('connected')\n }\n})\n")),Object(o.b)("p",null,"This is it! After deploying the database, application and executing the code snippet, you should see the message ",Object(o.b)("inlineCode",{parentName:"p"},"connected"),"."),Object(o.b)("p",null,"We made use of ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," variables injected by Qovery to make it easy to consume all the services within the environment.")),Object(o.b)("li",null,Object(o.b)("h2",{id:"consume-internal-apis"},"Consume internal APIs"),Object(o.b)("p",null,"In this step, we'll use the private API of our ",Object(o.b)("strong",{parentName:"p"},"APP_B")," in our ",Object(o.b)("strong",{parentName:"p"},"APP_A")," over a private network.\nWe have already configured everything to make it work. The only missing step is the configuration in ",Object(o.b)("strong",{parentName:"p"},"APP_A")," - it needs to know how to access our ",Object(o.b)("strong",{parentName:"p"},"APP_B"),"."),Object(o.b)("p",null,"In the example below, we'll use Node.js and ",Object(o.b)("inlineCode",{parentName:"p"},"axios")," to create an HTTP client able to consume the API of ",Object(o.b)("strong",{parentName:"p"},"APP_B"),":"),Object(o.b)("p",null,"Now, you can configure your HTTP client in the frontend application to target your backend API:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"const axios = require('axios');\nconst appBAddress = \"http://\" + process.env.QOVERY_APPLICATION_APP_B_HOST + \":\" + process.env.QOVERY_APPLICATION_APP_B_PORT\n\naxios.get(appBAddress + '/api/users')\n .then(response => {\n console.log(response.data);\n })\n .catch(error => {\n console.log(error);\n });\n")),Object(o.b)("p",null,"This is it! ",Object(o.b)("strong",{parentName:"p"},"Every request using the API client we have just configured will consume the API of "),"APP_B",Object(o.b)("strong",{parentName:"p"}," over the secure, internal network.")),Object(o.b)("p",null,"Once again, we used the ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," secrets. Read more about them ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-another-application"}),"here"))),Object(o.b)("li",null,Object(o.b)("h2",{id:"consume-the-public-api-in-the-frontend-application"},"Consume the public API in the frontend application"),Object(o.b)("p",null,"In this step, we'll deploy a frontend application and consume our public API exposed by ",Object(o.b)("strong",{parentName:"p"},"APP_A"),"."),Object(o.b)("p",null,"In the first step, create your frontend application."),Object(o.b)("p",null,"After the application is created, we can easily configure it to consume our public API. All we need to do is to make use of the ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," secrets. See how to achieve it in a Nuxt.js example below:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"export default {\n env: {\n apiUrl: process.env.QOVERY_APPLICATION_APP_A_URL\n }\n}\n")),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"import axios from 'axios'\n\nexport default axios.create({\n baseURL: process.env.apiUrl\n})\n")),Object(o.b)("p",null,"After providing the configuration from above, deploy your frontend application."),Object(o.b)("p",null,"Now our frontend application will be able to consume the API exposed by the publicly exposed ",Object(o.b)("strong",{parentName:"p"},"APP_A"),".")))),Object(o.b)("h2",{id:"summary"},"Summary"),Object(o.b)("p",null,"In this guide, we deployed two microservices that communicate over the internal network. We also deployed a frontend application that makes use of a public API exposed by one of our applications. At the same time, we deployed a database and connected it to the second of our backend microservices."),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}d.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),p=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=p(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=p(n),d=a,m=u["".concat(i,".").concat(d)]||u[d]||b[d]||o;return n?r.a.createElement(m,c({ref:t},s,{components:n})):r.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var a=n(432),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(n(a,e,i.length))})),i.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),p=Object(a.useState)(null),u=p[0],b=p[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see dea3d534.252309a6.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[236],{388:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return p})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var a=n(1),r=n(9),o=(n(0),n(425)),i=n(434),c=n(429),l=n(424),s={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Microservices",description:"How to deploy microservices with Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: guide","technology: qovery"]},p={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Microservices",description:"How to deploy microservices with Qovery",permalink:"/guides/advanced/microservices",readingTime:"6 min read",source:"@site/guides/advanced/microservices.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Microservices",truncated:!1,prevItem:{title:"Managing Environment Variables in React (create-react-app)",permalink:"/guides/tutorial/managing-env-variables-in-create-react-app"},nextItem:{title:"Migrate your application from Heroku to AWS",permalink:"/guides/tutorial/migrate-your-application-from-heroku-to-aws"}},u=[{value:"Deploy Application A",id:"deploy-application-a",children:[{value:"Exposing public API",id:"exposing-public-api",children:[]}]},{value:"Deploy Application B",id:"deploy-application-b",children:[]},{value:"Deploy Database",id:"deploy-database",children:[]},{value:"Use the database",id:"use-the-database",children:[]},{value:"Consume internal APIs",id:"consume-internal-apis",children:[]},{value:"Consume the public API in the frontend application",id:"consume-the-public-api-in-the-frontend-application",children:[]},{value:"Summary",id:"summary",children:[]},{value:"Q&A",id:"qa",children:[]}],b={rightToc:u};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)(l.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"This guide is a bit outdated. We are working on a new version of it. Stay tuned!")),Object(o.b)(c.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have already deployed an application with Qovery"),Object(o.b)("li",{parentName:"ul"},"You are familiar with the concept of Microservices"))),Object(o.b)("p",null,"In this guide, we'll deploy a set of microservices, a database and a frontend UI application that consumes our public API.\nOur backend microservices will communicate on a secure internal network, not accessible from the outside.\nOur front-end application will consume the API only from the publicly exposed application."),Object(o.b)("p",null,"The schema of what we want to achieve:"),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros.jpg",alt:"Microservices"})),Object(o.b)("p",null,"As you can see in the picture:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"we have two backend applications (",Object(o.b)("strong",{parentName:"li"},"App A")," and ",Object(o.b)("strong",{parentName:"li"},"App B"),")"),Object(o.b)("li",{parentName:"ul"},"one of them (",Object(o.b)("strong",{parentName:"li"},"App B"),") connected to a database"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"App A")," exposes a public API that is consumed by API clients (our frontend application run in users browsers)."),Object(o.b)("li",{parentName:"ul"},"additionally, we host our frontend application (",Object(o.b)("strong",{parentName:"li"},"UI"),") on Qovery so that users can access it directly in their browsers.")),Object(o.b)("p",null,"What differentiates Qovery from most other similar platforms is its first-class support of microservices. At Qovery, your project can be easily\ncomposed of multiple applications. It's up to you to decide how to build your system, but Qovery enables you to easily and safely communicate between your backend applications, databases, and frontend websites."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h2",{id:"deploy-application-a"},"Deploy Application A"),Object(o.b)(l.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This guide assumes you already know how to deploy applications. If you have any problems, refer to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"this video guide"),".")),Object(o.b)("p",null,"In the first step, deploy an application named ",Object(o.b)("strong",{parentName:"p"},"APP_A")," in your environment."),Object(o.b)("p",null,"Assumptions:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The app exposes REST API over HTTP on port 8080"),Object(o.b)("li",{parentName:"ul"},"The app name is ",Object(o.b)("strong",{parentName:"li"},"APP_A"))),Object(o.b)("p",null,"After the application is created, let's expose the API publicly - it will be used later on by our frontend application."),Object(o.b)("h3",{id:"exposing-public-api"},"Exposing public API"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate to ",Object(o.b)("strong",{parentName:"li"},"APP_A")," application settings"),Object(o.b)("li",{parentName:"ul"},"Select ",Object(o.b)("strong",{parentName:"li"},"Port")),Object(o.b)("li",{parentName:"ul"},"Add port 8080")),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros-1.png",alt:"Microservices"})),Object(o.b)("p",null,"This is it. By default, Qovery exposes your ports publicly over HTTPS on port 443, so the app should be publicly accessible and reachable later on by our frontend application.")),Object(o.b)("li",null,Object(o.b)("h2",{id:"deploy-application-b"},"Deploy Application B"),Object(o.b)("p",null,"In the second step, deploy an application named ",Object(o.b)("strong",{parentName:"p"},"APP_B")," in your environment."),Object(o.b)("p",null,"Assumptions:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"The app exposes REST API over HTTP on port 8080"),Object(o.b)("li",{parentName:"ul"},"The app name is ",Object(o.b)("strong",{parentName:"li"},"APP_B")),Object(o.b)("li",{parentName:"ul"},"The app is ready to use a PostgreSQL client to connect to a PostgreSQL database")),Object(o.b)("p",null,"Steps to do:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate to ",Object(o.b)("strong",{parentName:"li"},"APP_B")," application settings"),Object(o.b)("li",{parentName:"ul"},"Select ",Object(o.b)("strong",{parentName:"li"},"Port")),Object(o.b)("li",{parentName:"ul"},"Add port 8080"),Object(o.b)("li",{parentName:"ul"},"Click ",Object(o.b)("strong",{parentName:"li"},"Advanced")," settings in the 8080 port"),Object(o.b)("li",{parentName:"ul"},"Remove the check from the ",Object(o.b)("strong",{parentName:"li"},"Publicly Accessible")," field")),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros-2.png",alt:"Microservices"})),Object(o.b)(l.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"It will make your ",Object(o.b)("strong",{parentName:"p"},"APP_B")," application not reachable publicly. It will be only reachable on the internal network by other microservices in your environment."))),Object(o.b)("li",null,Object(o.b)("h2",{id:"deploy-database"},"Deploy Database"),Object(o.b)("p",null,"In this step, we'll deploy a PostgreSQL database that we'll consume in ",Object(o.b)("strong",{parentName:"p"},"APP_B")," in the next step."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate to the environment in which you previously deployed your apps"),Object(o.b)("li",{parentName:"ul"},"Create a new PostgreSQL database named ",Object(o.b)("strong",{parentName:"li"},"MY_DB"))),Object(o.b)(l.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This guide assumes you already know how to deploy databases. If you have any problems, refer to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"this video guide"),"."))),Object(o.b)("li",null,Object(o.b)("h2",{id:"use-the-database"},"Use the database"),Object(o.b)("p",null,"In this step, we'll make use of our database in ",Object(o.b)("strong",{parentName:"p"},"APP_B")),Object(o.b)("p",null,"All you need to do to consume your database in ",Object(o.b)("strong",{parentName:"p"},"APP_B")," is to configure your PostgreSQL client to use ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," secrets injected by Qovery.\nYou can read more about this concept ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-a-database"}),"here"),"."),Object(o.b)("p",null,"If your ",Object(o.b)("strong",{parentName:"p"},"APP_B")," is a Node.js application, this examplary code snippet will work well:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"const { Client } = require('pg')\n\nconst client = new Client({\n host: process.env.QOVERY_DATABASE_MY_DB_HOST,\n port: process.env.QOVERY_DATABASE_MY_DB_PORT,\n user: process.env.QOVERY_DATABASE_MY_DB_USER,\n password: process.env.QOVERY_DATABASE_MY_DB_PASSWORD,\n})\n\nclient.connect(err => {\n if (err) {\n console.error('connection error', err.stack)\n } else {\n console.log('connected')\n }\n})\n")),Object(o.b)("p",null,"This is it! After deploying the database, application and executing the code snippet, you should see the message ",Object(o.b)("inlineCode",{parentName:"p"},"connected"),"."),Object(o.b)("p",null,"We made use of ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," variables injected by Qovery to make it easy to consume all the services within the environment.")),Object(o.b)("li",null,Object(o.b)("h2",{id:"consume-internal-apis"},"Consume internal APIs"),Object(o.b)("p",null,"In this step, we'll use the private API of our ",Object(o.b)("strong",{parentName:"p"},"APP_B")," in our ",Object(o.b)("strong",{parentName:"p"},"APP_A")," over a private network.\nWe have already configured everything to make it work. The only missing step is the configuration in ",Object(o.b)("strong",{parentName:"p"},"APP_A")," - it needs to know how to access our ",Object(o.b)("strong",{parentName:"p"},"APP_B"),"."),Object(o.b)("p",null,"In the example below, we'll use Node.js and ",Object(o.b)("inlineCode",{parentName:"p"},"axios")," to create an HTTP client able to consume the API of ",Object(o.b)("strong",{parentName:"p"},"APP_B"),":"),Object(o.b)("p",null,"Now, you can configure your HTTP client in the frontend application to target your backend API:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"const axios = require('axios');\nconst appBAddress = \"http://\" + process.env.QOVERY_APPLICATION_APP_B_HOST + \":\" + process.env.QOVERY_APPLICATION_APP_B_PORT\n\naxios.get(appBAddress + '/api/users')\n .then(response => {\n console.log(response.data);\n })\n .catch(error => {\n console.log(error);\n });\n")),Object(o.b)("p",null,"This is it! ",Object(o.b)("strong",{parentName:"p"},"Every request using the API client we have just configured will consume the API of "),"APP_B",Object(o.b)("strong",{parentName:"p"}," over the secure, internal network.")),Object(o.b)("p",null,"Once again, we used the ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," secrets. Read more about them ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/#connecting-to-another-application"}),"here"))),Object(o.b)("li",null,Object(o.b)("h2",{id:"consume-the-public-api-in-the-frontend-application"},"Consume the public API in the frontend application"),Object(o.b)("p",null,"In this step, we'll deploy a frontend application and consume our public API exposed by ",Object(o.b)("strong",{parentName:"p"},"APP_A"),"."),Object(o.b)("p",null,"In the first step, create your frontend application."),Object(o.b)("p",null,"After the application is created, we can easily configure it to consume our public API. All we need to do is to make use of the ",Object(o.b)("inlineCode",{parentName:"p"},"BUILT_IN")," secrets. See how to achieve it in a Nuxt.js example below:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"export default {\n env: {\n apiUrl: process.env.QOVERY_APPLICATION_APP_A_URL\n }\n}\n")),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-javascript"}),"import axios from 'axios'\n\nexport default axios.create({\n baseURL: process.env.apiUrl\n})\n")),Object(o.b)("p",null,"After providing the configuration from above, deploy your frontend application."),Object(o.b)("p",null,"Now our frontend application will be able to consume the API exposed by the publicly exposed ",Object(o.b)("strong",{parentName:"p"},"APP_A"),".")))),Object(o.b)("h2",{id:"summary"},"Summary"),Object(o.b)("p",null,"In this guide, we deployed two microservices that communicate over the internal network. We also deployed a frontend application that makes use of a public API exposed by one of our applications. At the same time, we deployed a database and connected it to the second of our backend microservices."),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}d.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),p=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=p(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=p(n),d=a,m=u["".concat(i,".").concat(d)]||u[d]||b[d]||o;return n?r.a.createElement(m,c({ref:t},s,{components:n})):r.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var a=n(435),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(n(a,e,i.length))})),i.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),p=Object(a.useState)(null),u=p[0],b=p[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/df1c18d8.4cb266fc.js.LICENSE.txt b/dea3d534.252309a6.js.LICENSE.txt similarity index 100% rename from df1c18d8.4cb266fc.js.LICENSE.txt rename to dea3d534.252309a6.js.LICENSE.txt diff --git a/deef6d59.5fbcca74.js b/deef6d59.5fbcca74.js new file mode 100644 index 0000000000..99e3b57602 --- /dev/null +++ b/deef6d59.5fbcca74.js @@ -0,0 +1,2 @@ +/*! For license information please see deef6d59.5fbcca74.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[237],{389:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return c})),t.d(r,"metadata",(function(){return l})),t.d(r,"rightToc",(function(){return u})),t.d(r,"default",(function(){return p}));var o=t(1),a=t(9),n=(t(0),t(425)),i=t(424),c={last_modified_on:"2023-08-04",title:"Terraform",description:"Learn how to use Terraform with Qovery"},l={id:"using-qovery/integration/terraform",title:"Terraform",description:"Learn how to use Terraform with Qovery",source:"@site/docs/using-qovery/integration/terraform.md",permalink:"/docs/using-qovery/integration/terraform",sidebar:"docs",previous:{title:"Helm Repository",permalink:"/docs/using-qovery/integration/helm-repository"},next:{title:"Continuous Integration",permalink:"/docs/using-qovery/integration/continuous-integration"}},u=[{value:"Deploy Qovery with Terraform",id:"deploy-qovery-with-terraform",children:[{value:"Examples",id:"examples",children:[]},{value:"Terraform Exporter",id:"terraform-exporter",children:[]},{value:"Resources",id:"resources",children:[]}]},{value:"Deploy your Terraform code with Qovery",id:"deploy-your-terraform-code-with-qovery",children:[{value:"Examples",id:"examples-1",children:[]},{value:"Resources",id:"resources-1",children:[]}]},{value:"Do you need help?",id:"do-you-need-help",children:[]}],s={rightToc:u};function p(e){var r=e.components,t=Object(a.a)(e,["components"]);return Object(n.b)("wrapper",Object(o.a)({},s,t,{components:r,mdxType:"MDXLayout"}),Object(n.b)("p",null,Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"https://www.terraform.io"}),"Terraform")," is an open-source infrastructure as code software (IaC) tool that provides a consistent CLI workflow to manage hundreds of cloud services. Terraform codifies cloud APIs into declarative configuration files."),Object(n.b)("p",null,"Terraform can be used in 2 context:"),Object(n.b)("ol",null,Object(n.b)("li",{parentName:"ol"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"#deploy-qovery-with-terraform"}),"Qovery can be controlled via Terraform"),". This allows you to automate the creation of your organization, project, clusters, applications and environments (and more)."),Object(n.b)("li",{parentName:"ol"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"#deploy-your-terraform-code-with-qovery"}),"Qovery can be used to deploy your Terraform code"),". This allows you to automate the deployment of your infrastructure.")),Object(n.b)("h2",{id:"deploy-qovery-with-terraform"},"Deploy Qovery with Terraform"),Object(n.b)("p",null,"Qovery integrates with Terraform to create a complete workflow with a strong developer and operations experience for the different teams from development to critical production applications. By integrating Terraform with Qovery, your team can quickly implement governance at scale while drastically improving the developer experience when deploying and managing applications."),Object(n.b)(i.a,{type:"info",mdxType:"Alert"},Object(n.b)("p",null,"Check out our Terraform Provider on ",Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"https://registry.terraform.io/providers/Qovery/qovery/latest/docs"}),"Terraform Registry")," and ",Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/terraform-provider-qovery"}),"GitHub"),".")),Object(n.b)("h3",{id:"examples"},"Examples"),Object(n.b)("p",null,"Check out our Terraform examples ",Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/terraform-examples"}),"here"),"."),Object(n.b)("h3",{id:"terraform-exporter"},"Terraform Exporter"),Object(n.b)("p",null,"Qovery allows you to export your environment as a Terraform Manifest. Check ",Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#terraform-exporter"}),"the Terraform Exporter documentation")," to know more."),Object(n.b)("h3",{id:"resources"},"Resources"),Object(n.b)("ul",null,Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"https://registry.terraform.io/providers/Qovery/qovery/latest/docs"}),"Qovery Terraform Registry")),Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"https://github.com/Qovery/terraform-provider-qovery"}),"Qovery Terraform Provider source code")),Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"https://github.com/Qovery/terraform-examples"}),"Terraform Examples"))),Object(n.b)("h2",{id:"deploy-your-terraform-code-with-qovery"},"Deploy your Terraform code with Qovery"),Object(n.b)("p",null,"Qovery can deploy your Terraform code. It's very useful when you want to deploy your own cloud resources. For example, you can deploy your own databases, lambdas, brokers etc...\nTo do so, you need to use the ",Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"Lifecycle Jobs")," feature."),Object(n.b)(i.a,{type:"info",mdxType:"Alert"},Object(n.b)("p",null,"Lifecycle Jobs can be used to deploy any kind of code. It's not limited to Terraform. It works with Serverless, Pulumi, Helm etc...")),Object(n.b)("h3",{id:"examples-1"},"Examples"),Object(n.b)("p",null,"Check out our Terraform examples ",Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples"}),"here"),"."),Object(n.b)("h3",{id:"resources-1"},"Resources"),Object(n.b)("ul",null,Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"Qovery Lifecycle Job Documentation")),Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"https://github.com/Qovery/lifecycle-job-examples"}),"Qovery Lifecycle Job Examples")),Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"How to deploy MySQL RDS with Terraform and Lifecycle Jobs"))),Object(n.b)("h2",{id:"do-you-need-help"},"Do you need help?"),Object(n.b)("p",null,"Feel free to open a thread on our ",Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community Forum"),". We will be happy to help you."))}p.isMDXComponent=!0},423:function(e,r,t){var o;!function(){"use strict";var t={}.hasOwnProperty;function a(){for(var e=[],r=0;r=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var u=a.a.createContext({}),s=function(e){var r=a.a.useContext(u),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},p=function(e){var r=s(e.components);return a.a.createElement(u.Provider,{value:r},e.children)},f={inlineCode:"code",wrapper:function(e){var r=e.children;return a.a.createElement(a.a.Fragment,{},r)}},b=Object(o.forwardRef)((function(e,r){var t=e.components,o=e.mdxType,n=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(t),b=o,m=p["".concat(i,".").concat(b)]||p[b]||f[b]||n;return t?a.a.createElement(m,c({ref:r},u,{components:t})):a.a.createElement(m,c({ref:r},u))}));function m(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var n=t.length,i=new Array(n);i[0]=b;var c={};for(var l in r)hasOwnProperty.call(r,l)&&(c[l]=r[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var u=2;u1?arguments[1]:void 0,t),l=i>2?arguments[2]:void 0,u=void 0===l?t:a(l,t);u>c;)r[c++]=e;return r}}}]); \ No newline at end of file diff --git a/e06f2af5.90c333c9.js.LICENSE.txt b/deef6d59.5fbcca74.js.LICENSE.txt similarity index 100% rename from e06f2af5.90c333c9.js.LICENSE.txt rename to deef6d59.5fbcca74.js.LICENSE.txt diff --git a/deef6d59.67094f5c.js b/deef6d59.67094f5c.js deleted file mode 100644 index b36c34459e..0000000000 --- a/deef6d59.67094f5c.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see deef6d59.67094f5c.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[234],{386:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return c})),t.d(r,"metadata",(function(){return l})),t.d(r,"rightToc",(function(){return u})),t.d(r,"default",(function(){return p}));var o=t(1),a=t(9),n=(t(0),t(422)),i=t(421),c={last_modified_on:"2023-08-04",title:"Terraform",description:"Learn how to use Terraform with Qovery"},l={id:"using-qovery/integration/terraform",title:"Terraform",description:"Learn how to use Terraform with Qovery",source:"@site/docs/using-qovery/integration/terraform.md",permalink:"/docs/using-qovery/integration/terraform",sidebar:"docs",previous:{title:"Container Registry",permalink:"/docs/using-qovery/integration/container-registry"},next:{title:"Continuous Integration",permalink:"/docs/using-qovery/integration/continuous-integration"}},u=[{value:"Deploy Qovery with Terraform",id:"deploy-qovery-with-terraform",children:[{value:"Examples",id:"examples",children:[]},{value:"Terraform Exporter",id:"terraform-exporter",children:[]},{value:"Resources",id:"resources",children:[]}]},{value:"Deploy your Terraform code with Qovery",id:"deploy-your-terraform-code-with-qovery",children:[{value:"Examples",id:"examples-1",children:[]},{value:"Resources",id:"resources-1",children:[]}]},{value:"Do you need help?",id:"do-you-need-help",children:[]}],s={rightToc:u};function p(e){var r=e.components,t=Object(a.a)(e,["components"]);return Object(n.b)("wrapper",Object(o.a)({},s,t,{components:r,mdxType:"MDXLayout"}),Object(n.b)("p",null,Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"https://www.terraform.io"}),"Terraform")," is an open-source infrastructure as code software (IaC) tool that provides a consistent CLI workflow to manage hundreds of cloud services. Terraform codifies cloud APIs into declarative configuration files."),Object(n.b)("p",null,"Terraform can be used in 2 context:"),Object(n.b)("ol",null,Object(n.b)("li",{parentName:"ol"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"#deploy-qovery-with-terraform"}),"Qovery can be controlled via Terraform"),". This allows you to automate the creation of your organization, project, clusters, applications and environments (and more)."),Object(n.b)("li",{parentName:"ol"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"#deploy-your-terraform-code-with-qovery"}),"Qovery can be used to deploy your Terraform code"),". This allows you to automate the deployment of your infrastructure.")),Object(n.b)("h2",{id:"deploy-qovery-with-terraform"},"Deploy Qovery with Terraform"),Object(n.b)("p",null,"Qovery integrates with Terraform to create a complete workflow with a strong developer and operations experience for the different teams from development to critical production applications. By integrating Terraform with Qovery, your team can quickly implement governance at scale while drastically improving the developer experience when deploying and managing applications."),Object(n.b)(i.a,{type:"info",mdxType:"Alert"},Object(n.b)("p",null,"Check out our Terraform Provider on ",Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"https://registry.terraform.io/providers/Qovery/qovery/latest/docs"}),"Terraform Registry")," and ",Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/terraform-provider-qovery"}),"GitHub"),".")),Object(n.b)("h3",{id:"examples"},"Examples"),Object(n.b)("p",null,"Check out our Terraform examples ",Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/terraform-examples"}),"here"),"."),Object(n.b)("h3",{id:"terraform-exporter"},"Terraform Exporter"),Object(n.b)("p",null,"Qovery allows you to export your environment as a Terraform Manifest. Check ",Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#terraform-exporter"}),"the Terraform Exporter documentation")," to know more."),Object(n.b)("h3",{id:"resources"},"Resources"),Object(n.b)("ul",null,Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"https://registry.terraform.io/providers/Qovery/qovery/latest/docs"}),"Qovery Terraform Registry")),Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"https://github.com/Qovery/terraform-provider-qovery"}),"Qovery Terraform Provider source code")),Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"https://github.com/Qovery/terraform-examples"}),"Terraform Examples"))),Object(n.b)("h2",{id:"deploy-your-terraform-code-with-qovery"},"Deploy your Terraform code with Qovery"),Object(n.b)("p",null,"Qovery can deploy your Terraform code. It's very useful when you want to deploy your own cloud resources. For example, you can deploy your own databases, lambdas, brokers etc...\nTo do so, you need to use the ",Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"Lifecycle Jobs")," feature."),Object(n.b)(i.a,{type:"info",mdxType:"Alert"},Object(n.b)("p",null,"Lifecycle Jobs can be used to deploy any kind of code. It's not limited to Terraform. It works with Serverless, Pulumi, Helm etc...")),Object(n.b)("h3",{id:"examples-1"},"Examples"),Object(n.b)("p",null,"Check out our Terraform examples ",Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/Qovery/lifecycle-job-examples"}),"here"),"."),Object(n.b)("h3",{id:"resources-1"},"Resources"),Object(n.b)("ul",null,Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"Qovery Lifecycle Job Documentation")),Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"https://github.com/Qovery/lifecycle-job-examples"}),"Qovery Lifecycle Job Examples")),Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/"}),"How to deploy MySQL RDS with Terraform and Lifecycle Jobs"))),Object(n.b)("h2",{id:"do-you-need-help"},"Do you need help?"),Object(n.b)("p",null,"Feel free to open a thread on our ",Object(n.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community Forum"),". We will be happy to help you."))}p.isMDXComponent=!0},420:function(e,r,t){var o;!function(){"use strict";var t={}.hasOwnProperty;function a(){for(var e=[],r=0;r=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var u=a.a.createContext({}),s=function(e){var r=a.a.useContext(u),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},p=function(e){var r=s(e.components);return a.a.createElement(u.Provider,{value:r},e.children)},f={inlineCode:"code",wrapper:function(e){var r=e.children;return a.a.createElement(a.a.Fragment,{},r)}},b=Object(o.forwardRef)((function(e,r){var t=e.components,o=e.mdxType,n=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(t),b=o,m=p["".concat(i,".").concat(b)]||p[b]||f[b]||n;return t?a.a.createElement(m,c({ref:r},u,{components:t})):a.a.createElement(m,c({ref:r},u))}));function m(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var n=t.length,i=new Array(n);i[0]=b;var c={};for(var l in r)hasOwnProperty.call(r,l)&&(c[l]=r[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var u=2;u1?arguments[1]:void 0,t),l=i>2?arguments[2]:void 0,u=void 0===l?t:a(l,t);u>c;)r[c++]=e;return r}}}]); \ No newline at end of file diff --git a/df1c18d8.4cb266fc.js b/df1c18d8.645abae9.js similarity index 91% rename from df1c18d8.4cb266fc.js rename to df1c18d8.645abae9.js index 4fd580075e..5c9002be57 100644 --- a/df1c18d8.4cb266fc.js +++ b/df1c18d8.645abae9.js @@ -1,2 +1,2 @@ -/*! For license information please see df1c18d8.4cb266fc.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[235],{387:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return c})),a.d(t,"metadata",(function(){return l})),a.d(t,"rightToc",(function(){return s})),a.d(t,"default",(function(){return p}));var n=a(1),r=a(9),o=(a(0),a(422)),i=(a(429),a(421)),c=(a(426),{last_modified_on:"2022-11-18",$schema:"/.meta/.schemas/guides.json",title:"Grafana setup with Qovery",description:"Easily setup Grafana with Qovery",author_github:"https://github.com/deimosfr",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Grafana setup with Qovery",description:"Easily setup Grafana with Qovery",permalink:"/guides/tutorial/grafana-install",readingTime:"3 min read",source:"@site/guides/tutorial/grafana-install.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Grafana setup with Qovery",truncated:!1,prevItem:{title:"Getting Started with Preview Environments on AWS",permalink:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners"},nextItem:{title:"Helm Charts",permalink:"/guides/advanced/helm-chart"}},s=[{value:"Grafana setup",id:"grafana-setup",children:[{value:"Create a Grafana application",id:"create-a-grafana-application",children:[]},{value:"Configure database storage",id:"configure-database-storage",children:[]}]},{value:"Usage",id:"usage",children:[]},{value:"Cloudwatch Datasource",id:"cloudwatch-datasource",children:[]},{value:"Links",id:"links",children:[]}],u={rightToc:s};function p(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},u,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://grafana.com/grafana/"}),"Grafana")," is a famous Open Source solution to observe graphs and logs, supporting many data sources."),Object(o.b)("p",null,"This tutorial explains how to install Grafana on Qovery, and you will see how easy it is."),Object(o.b)("h2",{id:"grafana-setup"},"Grafana setup"),Object(o.b)("p",null,"First of all, create a project and an environment. Then let's create Grafana application."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"At the moment, Qovery does not support configuration file injection into Docker. So it can't be connected to an external database.\nThe currently used database is stored on the volume, so data will be lost on an application deletion. Qovery is going to implement configuration files for Docker in the coming weeks")),Object(o.b)("h3",{id:"create-a-grafana-application"},"Create a Grafana application"),Object(o.b)("p",null,"Connect to the console and add a new application:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_create_app.png",alt:"create gafana app"})),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Set an application name"),Object(o.b)("li",{parentName:"ol"},"Select the application source type: Container registry"),Object(o.b)("li",{parentName:"ol"},"Select DockerHub Public (or the one you have. If you do not have one, create a registry pointing to DockerHub)"),Object(o.b)("li",{parentName:"ol"},"Set the image name: grafana/grafana"),Object(o.b)("li",{parentName:"ol"},"Take a look at the latest ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://hub.docker.com/r/grafana/grafana/tags"}),"Grafana tags")," and set the tag you want to use (do not use latest one to avoid later issues)")),Object(o.b)("p",null,"Then set the resources to 1 instance and let other default values (Grafana doesn't consume a lot of resources):"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_set_resources.png",alt:"set resources"})),Object(o.b)("p",null,"Add a port mapping to the application, and set it to ",Object(o.b)("inlineCode",{parentName:"p"},"3000"),":"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_set_port.png",alt:"set port"})),Object(o.b)("p",null,"Finally, click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Create")," button:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_create.png",alt:"create app"})),Object(o.b)("h3",{id:"configure-database-storage"},"Configure database storage"),Object(o.b)("p",null,"We're now going to create a volume that will contain Grafana default database:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_volume.png",alt:"create app"})),Object(o.b)("p",null,"Go into Settings > Storage > Add Storage. Set the ",Object(o.b)("inlineCode",{parentName:"p"},"Path")," to ",Object(o.b)("inlineCode",{parentName:"p"},"/var/lib/grafana")," and the ",Object(o.b)("inlineCode",{parentName:"p"},"Size")," to ",Object(o.b)("inlineCode",{parentName:"p"},"4Gi"),". Click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create"),"."),Object(o.b)("h2",{id:"usage"},"Usage"),Object(o.b)("p",null,"Now you can deploy Grafana :). On the top right, you have the ",Object(o.b)("inlineCode",{parentName:"p"},"Open links")," button which will help you to get quick access. Then connect with those credentials:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Login: admin"),Object(o.b)("li",{parentName:"ul"},"Password: admin")),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Update the default password with a strong one as it is publicly exposed.")),Object(o.b)("h2",{id:"cloudwatch-datasource"},"Cloudwatch Datasource"),Object(o.b)("p",null,"You can add several data sources to Grafana. One we recommend at Qovery for full-text search is Cloudwatch. First of all, you have to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/cloudwatch-integration/"}),"follow this guide")," to ensure all your logs are sent to Cloudwatch. Then, you can add a new data source in Grafana:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/grafana_cloudwatch.png",alt:"grafana cloudwatch"})),Object(o.b)("p",null,"We advise you to use ",Object(o.b)("inlineCode",{parentName:"p"},"assume role")," or use a dedicated service account in read-only to access your logs. In this case, those permissions will be required:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Sid": "AllowReadingLogsFromCloudWatch",\n "Effect": "Allow",\n "Action": [\n "logs:DescribeLogGroups",\n "logs:GetLogGroupFields",\n "logs:StartQuery",\n "logs:StopQuery",\n "logs:GetQueryResults",\n "logs:GetLogEvents"\n ],\n "Resource": "*"\n },\n {\n "Sid": "AllowReadingTagsInstancesRegionsFromEC2",\n "Effect": "Allow",\n "Action": ["ec2:DescribeTags", "ec2:DescribeInstances", "ec2:DescribeRegions"],\n "Resource": "*"\n },\n {\n "Sid": "AllowReadingResourcesForTags",\n "Effect": "Allow",\n "Action": "tag:GetResources",\n "Resource": "*"\n }\n ]\n}\n')),Object(o.b)("p",null,"More info: ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://grafana.com/docs/grafana/latest/datasources/aws-cloudwatch/"}),"https://grafana.com/docs/grafana/latest/datasources/aws-cloudwatch/")),Object(o.b)("p",null,"Once done, you're able to create dashboards using Cloudwatch datasource and perform queries to your logs."),Object(o.b)("h2",{id:"links"},"Links"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://grafana.com/docs/grafana/v9.0/setup-grafana/configure-docker/#configure-aws-credentials-for-cloudwatch-support"}),"Add Cloudwatch support to Grafana")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://grafana.com/docs/grafana/latest/datasources/aws-cloudwatch/"}),"Grafana configuration for AWS"))))}p.isMDXComponent=!0},420:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):c({},t,{},e)),a},p=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(a),d=n,f=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return a?r.a.createElement(f,c({ref:t},s,{components:a})):r.a.createElement(f,c({ref:t},s))}));function f(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s1?arguments[1]:void 0,a),l=i>2?arguments[2]:void 0,s=void 0===l?a:r(l,a);s>c;)t[c++]=e;return t}},425:function(e,t,a){var n=a(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var n=a(0),r=a.n(n),o=a(421);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},427:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),i=a(39),c=a(430),l=a(20),s=a.n(l);t.a=function(e){var t,a=e.to,l=e.href,u=a||l,p=Object(c.a)(u),b=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?o.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var a,n;d&&e&&p&&(a=e,n=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:u})):o.a.createElement("a",Object(n.a)({},e,{href:u}))}},429:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(427),i=a(420),c=a.n(i);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+s,a),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:p,target:u,className:b},d):r.a.createElement(o.a,{to:p,className:b},d)}},430:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))}}]); \ No newline at end of file +/*! For license information please see df1c18d8.645abae9.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[238],{390:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return c})),a.d(t,"metadata",(function(){return l})),a.d(t,"rightToc",(function(){return s})),a.d(t,"default",(function(){return p}));var n=a(1),r=a(9),o=(a(0),a(425)),i=(a(431),a(424)),c=(a(429),{last_modified_on:"2022-11-18",$schema:"/.meta/.schemas/guides.json",title:"Grafana setup with Qovery",description:"Easily setup Grafana with Qovery",author_github:"https://github.com/deimosfr",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Grafana setup with Qovery",description:"Easily setup Grafana with Qovery",permalink:"/guides/tutorial/grafana-install",readingTime:"3 min read",source:"@site/guides/tutorial/grafana-install.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Grafana setup with Qovery",truncated:!1,prevItem:{title:"Getting Started with Preview Environments on AWS",permalink:"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners"},nextItem:{title:"Helm Charts",permalink:"/guides/advanced/helm-chart"}},s=[{value:"Grafana setup",id:"grafana-setup",children:[{value:"Create a Grafana application",id:"create-a-grafana-application",children:[]},{value:"Configure database storage",id:"configure-database-storage",children:[]}]},{value:"Usage",id:"usage",children:[]},{value:"Cloudwatch Datasource",id:"cloudwatch-datasource",children:[]},{value:"Links",id:"links",children:[]}],u={rightToc:s};function p(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},u,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://grafana.com/grafana/"}),"Grafana")," is a famous Open Source solution to observe graphs and logs, supporting many data sources."),Object(o.b)("p",null,"This tutorial explains how to install Grafana on Qovery, and you will see how easy it is."),Object(o.b)("h2",{id:"grafana-setup"},"Grafana setup"),Object(o.b)("p",null,"First of all, create a project and an environment. Then let's create Grafana application."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"At the moment, Qovery does not support configuration file injection into Docker. So it can't be connected to an external database.\nThe currently used database is stored on the volume, so data will be lost on an application deletion. Qovery is going to implement configuration files for Docker in the coming weeks")),Object(o.b)("h3",{id:"create-a-grafana-application"},"Create a Grafana application"),Object(o.b)("p",null,"Connect to the console and add a new application:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_create_app.png",alt:"create gafana app"})),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Set an application name"),Object(o.b)("li",{parentName:"ol"},"Select the application source type: Container registry"),Object(o.b)("li",{parentName:"ol"},"Select DockerHub Public (or the one you have. If you do not have one, create a registry pointing to DockerHub)"),Object(o.b)("li",{parentName:"ol"},"Set the image name: grafana/grafana"),Object(o.b)("li",{parentName:"ol"},"Take a look at the latest ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://hub.docker.com/r/grafana/grafana/tags"}),"Grafana tags")," and set the tag you want to use (do not use latest one to avoid later issues)")),Object(o.b)("p",null,"Then set the resources to 1 instance and let other default values (Grafana doesn't consume a lot of resources):"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_set_resources.png",alt:"set resources"})),Object(o.b)("p",null,"Add a port mapping to the application, and set it to ",Object(o.b)("inlineCode",{parentName:"p"},"3000"),":"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_set_port.png",alt:"set port"})),Object(o.b)("p",null,"Finally, click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Create")," button:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_create.png",alt:"create app"})),Object(o.b)("h3",{id:"configure-database-storage"},"Configure database storage"),Object(o.b)("p",null,"We're now going to create a volume that will contain Grafana default database:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/qovery_volume.png",alt:"create app"})),Object(o.b)("p",null,"Go into Settings > Storage > Add Storage. Set the ",Object(o.b)("inlineCode",{parentName:"p"},"Path")," to ",Object(o.b)("inlineCode",{parentName:"p"},"/var/lib/grafana")," and the ",Object(o.b)("inlineCode",{parentName:"p"},"Size")," to ",Object(o.b)("inlineCode",{parentName:"p"},"4Gi"),". Click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create"),"."),Object(o.b)("h2",{id:"usage"},"Usage"),Object(o.b)("p",null,"Now you can deploy Grafana :). On the top right, you have the ",Object(o.b)("inlineCode",{parentName:"p"},"Open links")," button which will help you to get quick access. Then connect with those credentials:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Login: admin"),Object(o.b)("li",{parentName:"ul"},"Password: admin")),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Update the default password with a strong one as it is publicly exposed.")),Object(o.b)("h2",{id:"cloudwatch-datasource"},"Cloudwatch Datasource"),Object(o.b)("p",null,"You can add several data sources to Grafana. One we recommend at Qovery for full-text search is Cloudwatch. First of all, you have to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/tutorial/cloudwatch-integration/"}),"follow this guide")," to ensure all your logs are sent to Cloudwatch. Then, you can add a new data source in Grafana:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/grafana/grafana_cloudwatch.png",alt:"grafana cloudwatch"})),Object(o.b)("p",null,"We advise you to use ",Object(o.b)("inlineCode",{parentName:"p"},"assume role")," or use a dedicated service account in read-only to access your logs. In this case, those permissions will be required:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Sid": "AllowReadingLogsFromCloudWatch",\n "Effect": "Allow",\n "Action": [\n "logs:DescribeLogGroups",\n "logs:GetLogGroupFields",\n "logs:StartQuery",\n "logs:StopQuery",\n "logs:GetQueryResults",\n "logs:GetLogEvents"\n ],\n "Resource": "*"\n },\n {\n "Sid": "AllowReadingTagsInstancesRegionsFromEC2",\n "Effect": "Allow",\n "Action": ["ec2:DescribeTags", "ec2:DescribeInstances", "ec2:DescribeRegions"],\n "Resource": "*"\n },\n {\n "Sid": "AllowReadingResourcesForTags",\n "Effect": "Allow",\n "Action": "tag:GetResources",\n "Resource": "*"\n }\n ]\n}\n')),Object(o.b)("p",null,"More info: ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://grafana.com/docs/grafana/latest/datasources/aws-cloudwatch/"}),"https://grafana.com/docs/grafana/latest/datasources/aws-cloudwatch/")),Object(o.b)("p",null,"Once done, you're able to create dashboards using Cloudwatch datasource and perform queries to your logs."),Object(o.b)("h2",{id:"links"},"Links"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://grafana.com/docs/grafana/v9.0/setup-grafana/configure-docker/#configure-aws-credentials-for-cloudwatch-support"}),"Add Cloudwatch support to Grafana")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://grafana.com/docs/grafana/latest/datasources/aws-cloudwatch/"}),"Grafana configuration for AWS"))))}p.isMDXComponent=!0},423:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):c({},t,{},e)),a},p=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(a),d=n,f=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return a?r.a.createElement(f,c({ref:t},s,{components:a})):r.a.createElement(f,c({ref:t},s))}));function f(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s1?arguments[1]:void 0,a),l=i>2?arguments[2]:void 0,s=void 0===l?a:r(l,a);s>c;)t[c++]=e;return t}},428:function(e,t,a){var n=a(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var n=a(0),r=a.n(n),o=a(424);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},430:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),i=a(39),c=a(432),l=a(20),s=a.n(l);t.a=function(e){var t,a=e.to,l=e.href,u=a||l,p=Object(c.a)(u),b=Object(r.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?o.a.createElement(i.b,Object(n.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var a,n;d&&e&&p&&(a=e,n=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:u})):o.a.createElement("a",Object(n.a)({},e,{href:u}))}},431:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(430),i=a(423),c=a.n(i);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+s,a),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:p,target:u,className:b},d):r.a.createElement(o.a,{to:p,className:b},d)}},432:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))}}]); \ No newline at end of file diff --git a/e1becc8e.9b069b5e.js.LICENSE.txt b/df1c18d8.645abae9.js.LICENSE.txt similarity index 100% rename from e1becc8e.9b069b5e.js.LICENSE.txt rename to df1c18d8.645abae9.js.LICENSE.txt diff --git a/docs/getting-started/basic-concepts/index.html b/docs/getting-started/basic-concepts/index.html index 617b581cef..1970108c2c 100644 --- a/docs/getting-started/basic-concepts/index.html +++ b/docs/getting-started/basic-concepts/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
-

Basic Concepts

Organization

An Organization is the workspace where devops and developers can collaborate across many projects at once and it usually corresponds to your company. A user can have access to one or more organizations and have different roles & permissions assigned within it thanks to our RBAC system.

More information about Organization here.

Cluster

At Qovery, when we refer to Cluster, we mean Kubernetes cluster. A Kubernetes cluster is a collection of node machines that allows you to run containerized applications.

More information about Cluster here.

Project

A Project allows you to group together a set of services interacting between each other to serve a common purpose. For example, you can have one project to run your main application (composed by a front-end, back-end and a db) and another project to manage your internal tools.

Services can be then organized into environments so that you can have different versions of the same service running within your project (production, staging, fix for issue X etc..)

One organization can have more than one project and you can customize the access to your project thanks to our RBAC system.

More information about Project here.

Environment

An Environment allows you to group together a set of services having a specific version, usually based on a branch of your repository. For example, you can have one Production environment (all the services pointing to the main branch), one Staging environment (all services pointing to the staging branch) etc..

Your production environment runs 24/7 while your other environments may not need to run all day long. By setting a Deployment Rule on your environment you can automatically start/stop your non-production environments and thus reduce your cloud provider bill.

Environments let's you chose on which cluster your services should be deployed.

More information about Environment here.

Preview Environment

A Preview Environment is an ephemeral environment allowing you to get early feedback on your application changes before the changes are merged into production. A dedicated preview environment can be automatically created at each new PR on your repository to validate the change. The environment is automatically deleted once the PR is merged or closed.

More information about Preview Environment here.

Service

A Service is the basic unit that you can add to an environment. Each service has an associated git repository (or registry) and a commit (or image_name:tag) that will be used to deploy the service on the cluster.

Four type of services exists:

  • Application: it allows you to run your long-running workloads. We usually call them "Containers" when the source code is stored on an image registry. More information about Applications here
  • Database: it allows you to deploy a database. Qovery allows you to deploy a container and a cloud provider managed version. More information about Databases here
  • CronJob: it allows you to deploy a cronjob on your cluster and execute it based on the selected schedule. More information about Cronjob here
  • Lifecycle: it allows you to execute your code based on the events happening on your environment (Start, Stop, Delete etc..). With the right code, it can be used to seed your database when the environment is created or manage the lifecycle of any external resource (via a terraform file, pulumi code etc..). More information about Lifecycle here

Deployment

A Deployment is the operation allowing you to gather your code and make it runs on your cluster. Qovery can pull your repository, generate a docker image and spawn the necessary resources on your clusters to make your application run. You can find more information within this section.

You can monitor the execution of the deployment via the Deployment Logs while you can monitor the execution of your application thanks to the streamed Live Logs directly from the Qovery interface.

High Level Schema

Basic Structure

+

Basic Concepts

Organization

An Organization is the workspace where devops and developers can collaborate across many projects at once and it usually corresponds to your company. A user can have access to one or more organizations and have different roles & permissions assigned within it thanks to our RBAC system.

More information about Organization here.

Cluster

At Qovery, when we refer to Cluster, we mean Kubernetes cluster. A Kubernetes cluster is a collection of node machines that allows you to run containerized applications.

More information about Cluster here.

Project

A Project allows you to group together a set of services interacting between each other to serve a common purpose. For example, you can have one project to run your main application (composed by a front-end, back-end and a db) and another project to manage your internal tools.

Services can be then organized into environments so that you can have different versions of the same service running within your project (production, staging, fix for issue X etc..)

One organization can have more than one project and you can customize the access to your project thanks to our RBAC system.

More information about Project here.

Environment

An Environment allows you to group together a set of services having a specific version, usually based on a branch of your repository. For example, you can have one Production environment (all the services pointing to the main branch), one Staging environment (all services pointing to the staging branch) etc..

Your production environment runs 24/7 while your other environments may not need to run all day long. By setting a Deployment Rule on your environment you can automatically start/stop your non-production environments and thus reduce your cloud provider bill.

Environments let's you chose on which cluster your services should be deployed.

More information about Environment here.

Preview Environment

A Preview Environment is an ephemeral environment allowing you to get early feedback on your application changes before the changes are merged into production. A dedicated preview environment can be automatically created at each new PR on your repository to validate the change. The environment is automatically deleted once the PR is merged or closed.

More information about Preview Environment here.

Service

A Service is the basic unit that you can add to an environment. Each service has an associated git repository (or registry) and a commit (or image_name:tag) that will be used to deploy the service on the cluster.

Four type of services exists:

  • Application: it allows you to run your long-running workloads. We usually call them "Containers" when the source code is stored on an image registry. More information about Applications here
  • Database: it allows you to deploy a database. Qovery allows you to deploy a container and a cloud provider managed version. More information about Databases here
  • CronJob: it allows you to deploy a cronjob on your cluster and execute it based on the selected schedule. More information about Cronjob here
  • Lifecycle: it allows you to execute your code based on the events happening on your environment (Start, Stop, Delete etc..). With the right code, it can be used to seed your database when the environment is created or manage the lifecycle of any external resource (via a terraform file, pulumi code etc..). More information about Lifecycle here

Deployment

A Deployment is the operation allowing you to gather your code and make it runs on your cluster. Qovery can pull your repository, generate a docker image and spawn the necessary resources on your clusters to make your application run. You can find more information within this section.

You can monitor the execution of the deployment via the Deployment Logs while you can monitor the execution of your application thanks to the streamed Live Logs directly from the Qovery interface.

High Level Schema

Basic Structure

- + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/deploy-my-app/index.html b/docs/getting-started/deploy-my-app/index.html index 7362a0f85e..ee6c330ab9 100644 --- a/docs/getting-started/deploy-my-app/index.html +++ b/docs/getting-started/deploy-my-app/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
-

Deploy my application

Check our video tutorial to learn how to quickly deploy your application with Qovery!

Deploy your application

Advanced

Once you know how to deploy a simple application, take a look at how to go beyond with Qovery.

Advanced
Contents
Resources
    +

    Deploy my application

    Check our video tutorial to learn how to quickly deploy your application with Qovery!

    Deploy your application

    Advanced

    Once you know how to deploy a simple application, take a look at how to go beyond with Qovery.

    Advanced
    Contents
    Resources
      - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/how-qovery-works/index.html b/docs/getting-started/how-qovery-works/index.html index eca96a262c..ec2fbe4f4d 100644 --- a/docs/getting-started/how-qovery-works/index.html +++ b/docs/getting-started/how-qovery-works/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
      -

      How Qovery Works

      Curious to get the big picture of how Qovery works? Refer to this article

      Resources
        +

        How Qovery Works

        Curious to get the big picture of how Qovery works? Refer to this article

        Resources
          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/index.html b/docs/getting-started/index.html index 2b2b9a94b7..db7183084a 100644 --- a/docs/getting-started/index.html +++ b/docs/getting-started/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
          -
          Resources
            +
            Resources
              - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/index.html b/docs/getting-started/install-qovery/index.html index cbb0a6aba4..5d03610033 100644 --- a/docs/getting-started/install-qovery/index.html +++ b/docs/getting-started/install-qovery/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
              -

              Install Qovery

              Qovery offers two distinct approaches to Kubernetes management: Kubernetes managed by Qovery and self-managed Kubernetes (Bring Your Own Kubernetes - BYOK)

              Here is a table to help you to choose between both:

              Feature/AspectKubernetes Managed by QoveryBYOK (Bring Your Own Kubernetes)
              ManagementFully managed by QoverySelf-managed by the organization
              ControlLimited control over Kubernetes infrastructureFull control over Kubernetes setup
              Supported Cloud Service ProvidersAWS, GCP, ScalewayAll
              CustomizationStandard Qovery configurationHigh customization and configuration freedom
              Expertise RequiredNoneRequires Kubernetes expertise
              ResponsibilityQovery is responsible for maintenanceOrganization is responsible for maintenance
              Developer ExperienceStreamlined and simplifiedStreamlined and simplified (no difference)
              Setup ComplexityJust a AWS, GCP or Scaleway accountRequires infrastructure and Kubernetes knowledge
              Flexibility in UsageStandardized to Qovery's environmentFlexible to meet specific organizational needs
              Ideal Use CaseOrganizations preferring a hands-off approachOrganizations with specific Kubernetes needs
              Managed ServicesCf. list belowN/A

              Note that the Qovery Managed Kubernetes also support out of the box the following capabilities:

              • Vertical Pod Autoscaler
              • Cluster Autoscaler
              • CoreDNS
              • Cert-manager
              • Cert-manager Qovery Webhook
              • Nginx Ingress
              • Metrics Server
              • External DNS
              • Promtail
              • Loki
              • AWS
                • AWS EBS Driver
                • AWS Kubeproxy
                • AWS CNI
                • IAM EKS User Mapper
                • Karpenter
                • AWS Node Term Handler

              Easy: Kubernetes Managed by Qovery

              Deploy Qovery on AWS
              Deploy Qovery on GCP
              Deploy Qovery on Azure
              Deploy Qovery on Scaleway

              Advanced: Bring Your Own Kubernetes (BYOK)

              Deploy Qovery on Kubernetes
              +

              Install Qovery

              Qovery offers two distinct approaches to Kubernetes management: Kubernetes managed by Qovery and self-managed Kubernetes (Bring Your Own Kubernetes - BYOK)

              Here is a table to help you to choose between both:

              Feature/AspectKubernetes Managed by QoveryBYOK (Bring Your Own Kubernetes)
              ManagementFully managed by QoverySelf-managed by the organization
              ControlLimited control over Kubernetes infrastructureFull control over Kubernetes setup
              Supported Cloud Service ProvidersAWS, GCP, ScalewayAll
              CustomizationStandard Qovery configurationHigh customization and configuration freedom
              Expertise RequiredNoneRequires Kubernetes expertise
              ResponsibilityQovery is responsible for maintenanceOrganization is responsible for maintenance
              Developer ExperienceStreamlined and simplifiedStreamlined and simplified (no difference)
              Setup ComplexityJust a AWS, GCP or Scaleway accountRequires infrastructure and Kubernetes knowledge
              Flexibility in UsageStandardized to Qovery's environmentFlexible to meet specific organizational needs
              Ideal Use CaseOrganizations preferring a hands-off approachOrganizations with specific Kubernetes needs
              Managed ServicesCf. list belowN/A

              Note that the Qovery Managed Kubernetes also support out of the box the following capabilities:

              • Vertical Pod Autoscaler
              • Cluster Autoscaler
              • CoreDNS
              • Cert-manager
              • Cert-manager Qovery Webhook
              • Nginx Ingress
              • Metrics Server
              • External DNS
              • Promtail
              • Loki
              • AWS
                • AWS EBS Driver
                • AWS Kubeproxy
                • AWS CNI
                • IAM EKS User Mapper
                • Karpenter
                • AWS Node Term Handler

              Easy: Kubernetes Managed by Qovery

              Deploy Qovery on AWS
              Deploy Qovery on GCP
              Deploy Qovery on Azure
              Deploy Qovery on Scaleway

              Advanced: Bring Your Own Kubernetes (BYOK)

              Deploy Qovery on Kubernetes
              - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/what-is-qovery/index.html b/docs/getting-started/what-is-qovery/index.html index 041ce3a95f..5e8925b3ad 100644 --- a/docs/getting-started/what-is-qovery/index.html +++ b/docs/getting-started/what-is-qovery/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
              -

              What is Qovery?

              Qovery is the Internal Developer Platform (IDP) that cuts noise for developers with paved paths to production. Testing, ephemeral environments, and drive action to improve software.

              Developers and a Platform Engineer using Qovery as an IDP

              Qovery For Platform Engineers

              By using Qovery, Platform Engineering teams can provide an outstanding platform to their developers in less than a hour. Then Platform Engineering teams can tailor the experience of Qovery and even build on top of it to fit their own golden path. They keep the control and can audit what developers do.

              How Qovery Works

              Qovery runs on top of Kubernetes and provide a convenient layer with a set of features to build a platform that your developers love.

              Qovery - How it Works

              Notable features for Platform Engineers

              Qovery For Developers / Engineering Teams

              By using Qovery, developers are autonomous in deploying their applications, debugging, and scaling. They don't need any infrastructure knowledge. They can connect their git repository, pushing and deploying their apps.

              Qovery focus on providing an outstanding Developer Experience and never assume that developers know how underlying infrastructure work.

              Notable features for Developers

              • Self-Service Platform
              • Git Push And Deploy
              • Live Application Logs
              • Easy Variables Management
              • Easy Domain Management
              • No Infra Knowledge Needed
              • Ephemeral Environments

              Integrates Qovery in your technical stack

              1. Qovery is battery included! Get a State-of-the-Art Internal Developer Platform in 30 minutes.
              2. Qovery integrates perfectly well into an existing ecosystem.

              Qovery - Internal Developer Platform landscape

              +

              What is Qovery?

              Qovery is the Internal Developer Platform (IDP) that cuts noise for developers with paved paths to production. Testing, ephemeral environments, and drive action to improve software.

              Developers and a Platform Engineer using Qovery as an IDP

              Qovery For Platform Engineers

              By using Qovery, Platform Engineering teams can provide an outstanding platform to their developers in less than a hour. Then Platform Engineering teams can tailor the experience of Qovery and even build on top of it to fit their own golden path. They keep the control and can audit what developers do.

              How Qovery Works

              Qovery runs on top of Kubernetes and provide a convenient layer with a set of features to build a platform that your developers love.

              Qovery - How it Works

              Notable features for Platform Engineers

              Qovery For Developers / Engineering Teams

              By using Qovery, developers are autonomous in deploying their applications, debugging, and scaling. They don't need any infrastructure knowledge. They can connect their git repository, pushing and deploying their apps.

              Qovery focus on providing an outstanding Developer Experience and never assume that developers know how underlying infrastructure work.

              Notable features for Developers

              • Self-Service Platform
              • Git Push And Deploy
              • Live Application Logs
              • Easy Variables Management
              • Easy Domain Management
              • No Infra Knowledge Needed
              • Ephemeral Environments

              Integrates Qovery in your technical stack

              1. Qovery is battery included! Get a State-of-the-Art Internal Developer Platform in 30 minutes.
              2. Qovery integrates perfectly well into an existing ecosystem.

              Qovery - Internal Developer Platform landscape

              - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/whats-next/index.html b/docs/getting-started/whats-next/index.html index c8169b3772..7746ecdd6c 100644 --- a/docs/getting-started/whats-next/index.html +++ b/docs/getting-started/whats-next/index.html @@ -21,60 +21,60 @@ - + - + - + - + - + - + - + - + - + - + - + - +
              -

              What's next?

              Before you go any further, make sure you have followed and finished the basic Getting Started Guide:

              Getting Started Guide

              After you have hands-on experience with Qovery, you can learn more about all the concepts and features in Using Qovery +

              What's next?

              Before you go any further, make sure you have followed and finished the basic Getting Started Guide:

              Getting Started Guide

              After you have hands-on experience with Qovery, you can learn more about all the concepts and features in Using Qovery subsections:

              Using Qovery
              Resources
                - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/index.html b/docs/index.html index af3e3c3569..2c4a7e2fa9 100644 --- a/docs/index.html +++ b/docs/index.html @@ -17,16 +17,16 @@ - + - + - + - + - + @@ -35,13 +35,13 @@
                - + - + - + - + diff --git a/docs/security-and-compliance/backup-and-restore/index.html b/docs/security-and-compliance/backup-and-restore/index.html index 5ebf4d2620..d1eaf8dd13 100644 --- a/docs/security-and-compliance/backup-and-restore/index.html +++ b/docs/security-and-compliance/backup-and-restore/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                -

                Backup and Restore

                Backups and restore are frequently a nightmare to setup. Especially for databases. Qovery helps you to get this part always automatically managed by the Cloud provider.

                Backups

                Applications

                When containers' applications are successfully built, all containers are kept for possible future rollback.

                Services

                Take a look at the desired service to know how they are backed up.

                Restore

                Applications

                As the Qovery configuration file is in your git repository and versioned, you can rollback any version when you want.

                Services

                Take a look at the desired service to know how you can restore it.

                +

                Backup and Restore

                Backups and restore are frequently a nightmare to setup. Especially for databases. Qovery helps you to get this part always automatically managed by the Cloud provider.

                Backups

                Applications

                When containers' applications are successfully built, all containers are kept for possible future rollback.

                Services

                Take a look at the desired service to know how they are backed up.

                Restore

                Applications

                As the Qovery configuration file is in your git repository and versioned, you can rollback any version when you want.

                Services

                Take a look at the desired service to know how you can restore it.

                - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/security-and-compliance/encryption/index.html b/docs/security-and-compliance/encryption/index.html index 710618f1ad..f6a906afc4 100644 --- a/docs/security-and-compliance/encryption/index.html +++ b/docs/security-and-compliance/encryption/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                -

                Encryption

                Data in transit

                Data in transit between the World and Qovery is always encrypted, as all of the services which Qovery supports. Services include the Qovery CLI, management console, Documentation, Landing Page, and Back Office.

                Data in transit between the World and customer applications is encrypted. By default, HTTPS connections use an automatically generated Let's Encrypt certificate, or users may provide their own TLS certificate (Enterprise only).

                Data in transit on Qovery controlled networks (e.g., between the application and a database) use end-to-end encryption and private networking rules.

                Data storage

                All application data is encrypted by using encrypted storage (typically using an AES-256 block cipher). If you have specific audit requirements surrounding data at rest encryption, please contact us.

                Secrets

                All secrets data is encrypted by using salted AES-256.

                +

                Encryption

                Data in transit

                Data in transit between the World and Qovery is always encrypted, as all of the services which Qovery supports. Services include the Qovery CLI, management console, Documentation, Landing Page, and Back Office.

                Data in transit between the World and customer applications is encrypted. By default, HTTPS connections use an automatically generated Let's Encrypt certificate, or users may provide their own TLS certificate (Enterprise only).

                Data in transit on Qovery controlled networks (e.g., between the application and a database) use end-to-end encryption and private networking rules.

                Data storage

                All application data is encrypted by using encrypted storage (typically using an AES-256 block cipher). If you have specific audit requirements surrounding data at rest encryption, please contact us.

                Secrets

                All secrets data is encrypted by using salted AES-256.

                - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/security-and-compliance/gdpr/index.html b/docs/security-and-compliance/gdpr/index.html index a8e69255c5..fe6adb45b1 100644 --- a/docs/security-and-compliance/gdpr/index.html +++ b/docs/security-and-compliance/gdpr/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                -

                GDPR

                Qovery has taken numerous steps to ensure GDPR compliance. As part of our measures, we have implemented the following:

                Data Protection by Design

                We've implemented policies in the company to ensure all of our employees follow the necessary training and protocols around security. Besides, privacy protection is part of every project during instantiation.

                Data Protection Officer

                Appointment of a Security Officer, who also holds the Data Protection Officer (DPO) role. If you have any concern, contact us.

                Consent

                We've confirmed that all of our customer communication, both business-related and marketing-related, is opt-in, and no information is shared with us without a customer's consent.

                Enhanced Rights

                The GDPR provides rights to individuals, such as the right to portability, right of rectification, and the right to be forgotten. We've made sure we comply with these rights. Nearly all information can be edited through a user's account, and we can delete accounts upon request.

                Data Collection

                We've documented information about what data we collect.

                Data Retention

                We documented information about our data retention.

                +

                GDPR

                Qovery has taken numerous steps to ensure GDPR compliance. As part of our measures, we have implemented the following:

                Data Protection by Design

                We've implemented policies in the company to ensure all of our employees follow the necessary training and protocols around security. Besides, privacy protection is part of every project during instantiation.

                Data Protection Officer

                Appointment of a Security Officer, who also holds the Data Protection Officer (DPO) role. If you have any concern, contact us.

                Consent

                We've confirmed that all of our customer communication, both business-related and marketing-related, is opt-in, and no information is shared with us without a customer's consent.

                Enhanced Rights

                The GDPR provides rights to individuals, such as the right to portability, right of rectification, and the right to be forgotten. We've made sure we comply with these rights. Nearly all information can be edited through a user's account, and we can delete accounts upon request.

                Data Collection

                We've documented information about what data we collect.

                Data Retention

                We documented information about our data retention.

                - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/security-and-compliance/index.html b/docs/security-and-compliance/index.html index 6340b465bc..f5980b54f7 100644 --- a/docs/security-and-compliance/index.html +++ b/docs/security-and-compliance/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                -
                Resources
                  +
                  Resources
                    - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/security-and-compliance/soc2/index.html b/docs/security-and-compliance/soc2/index.html index cd19feef80..51af43d4c5 100644 --- a/docs/security-and-compliance/soc2/index.html +++ b/docs/security-and-compliance/soc2/index.html @@ -21,60 +21,60 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                    -

                    SOC2

                    Qovery infrastructure and process comply with SOC2 (Systems and Organizations Controls 2) best practices. Qovery also brings by default many security features to your applications, clusters, and databases to comply with the most stringent security standards of SOC2. +

                    SOC2

                    Qovery infrastructure and process comply with SOC2 (Systems and Organizations Controls 2) best practices. Qovery also brings by default many security features to your applications, clusters, and databases to comply with the most stringent security standards of SOC2. You can find additional information on the Qovery trust page.

                    All customers using Qovery, requiring to be SOC2 compliant, save a lot of time as the deployed infrastructure is SOC2 ready!

                    In this documentation, you will find settings to update to comply with SOC2 and even more.

                    Cluster advanced settings

                    In the cluster advanced settings, you will find several options to update based on your wishes and to comply with SOC2. Here are the most important ones:

                    Log retention days

                    • AWS Cloudwatch retention days (aws.cloudwatch.eks_logs_retention_days): 365 days is what SOC2 requests at least
                    • Enable VPC flow logs (aws.vpc.enable_s3_flow_logs and aws.vpc.flow_logs_retention_days): Enable it and set the retention days to 365 days
                    • Allowed databases CIDR: you have to disable or restrict public access, but not let them open to the world
                    - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/useful-resources/faq/index.html b/docs/useful-resources/faq/index.html index b8d7df7b17..dd9e0552e0 100644 --- a/docs/useful-resources/faq/index.html +++ b/docs/useful-resources/faq/index.html @@ -21,61 +21,61 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                    -

                    FAQ

                    What is the difference between a Project, an Application, and an Environment?

                    A project is the site that you're working on. Each project can contain multiple applications and be deployed in multiple environments. An environment is a standalone copy of your site, including apps, databases, storage, data, and all other services. By default, main branch is the production environment, while all other branches can be set up as identical copies of the prod environment for testing purposes.

                    How does Qovery manage databases?

                    Qovery provides managed and container modes for your databases. Basically, managed mode relies on the managed database provided by the cloud provider. E.g. if you choose Postgres with the managed mode while your environment is running on AWS, then Qovery provides an AWS RDS instance. Please check out our database section for further details.

                    Does Qovery replace Kubernetes?

                    Behind the scene, Qovery uses Kubernetes. Qovery extends Kubernetes to make it accessible to any developer teams. +

                    FAQ

                    What is the difference between a Project, an Application, and an Environment?

                    A project is the site that you're working on. Each project can contain multiple applications and be deployed in multiple environments. An environment is a standalone copy of your site, including apps, databases, storage, data, and all other services. By default, main branch is the production environment, while all other branches can be set up as identical copies of the prod environment for testing purposes.

                    How does Qovery manage databases?

                    Qovery provides managed and container modes for your databases. Basically, managed mode relies on the managed database provided by the cloud provider. E.g. if you choose Postgres with the managed mode while your environment is running on AWS, then Qovery provides an AWS RDS instance. Please check out our database section for further details.

                    Does Qovery replace Kubernetes?

                    Behind the scene, Qovery uses Kubernetes. Qovery extends Kubernetes to make it accessible to any developer teams. Important: Qovery does not modify Kubernetes. It only deploys his services in a qovery Kubernetes namespace.

                    Does Qovery support mono repository?

                    Yes, absolutely! Check out our monorepo guide.

                    Does Qovery support microservices?

                    Yes, absolutely! Check out our microservices guide.

                    What Git providers do you support?

                    GitHub, GitLab, BitBucket.

                    Do you support GitHub Enterprise or Gitlab Self-hosted?

                    Not at the moment, but you can upvote for this feature in our roadmap.

                    Does Qovery support private Git repository?

                    Yes, absolutely!

                    Which IP address does my cluster use to communicate externally over the Internet?

                    There isn't just one public cluster IP adress dedicated to external communication. However, worker nodes inside your cluster each have a public IP automatically attached to them. You can view those default public IPs in the details of your worker nodes (EC2 instances for AWS users) which belong to the node group in your cluster.

                    For improved security and control, the Static IP feature allows you to ensure that outbound traffic from your cluster uses specific IP addresses. For more information on the Static IP feature and how to enable it at cluster creation, see Static IP.

                    If I have N custom domains under the same root domain, do I need to create N CNAME records, or just creating one for the root domain is enough ?

                    You have to create N CNAME, one per custom domain

                    How do you support new Kubernetes version?

                    The Qovery team manages your Kubernetes cluster's upgrade, and you don't have to think about it. Upgrades from one minor Kubernetes version to another require a good amount of tests to make sure everything goes smoothly with zero interruptions for your app. This is why Qovery always provides 1 or 2 minor versions below the last one offered by the cloud provider. Our goal is to guarantee you the maximum uptime.

                    More details on this dedicated section: how-does-qovery-handle-cluster-updates-and-upgrades

                    Can I upgrade my cluster myself

                    NO and you SHOULDN'T ! More details on this dedicated section: how-does-qovery-handle-cluster-updates-and-upgrades

                    Can I have access to my Kubernetes cluster?

                    Absolutely, you can follow this guide.

                    Can I have access to my application with a shell?

                    Absolutely, check out our CLI and the qovery shell command.

                    How application auto-scaling works?

                    Take a look at our application documentation.

                    Why you should use Qovery?

                    The power of Kubernetes

                    Under the hood, Qovery uses containers and Kubernetes to run applications. With us, your applications scale accordingly to your traffic and needs. We rely on major cloud providers to provide reliable infrastructure to make your applications highly available.

                    Reliable infrastructure

                    What's more, we took on our shoulders the complexity of providing and managing other infrastructure requirements you need (like databases or message brokers), so you can focus merely on developing business features.

                    Simple and Powerful

                    With Qovery, the cloud is simple again. Get all the benefits of using cloud and Kubernetes without dealing with its complexity. You don't need to hire infrastructure experts - configuring continuous integration, deployment, databases, message brokers, storage, DNS, SSL/TLS, VPCs, and many others - we do it all for you. On Qovery, you can spin up a set of microservices, databases, and other cloud services in minutes with a single Git push!

                    Built for all developers

                    Qovery is designed by developers for developers. Our goal is to make your life easier and allow you to move faster. Developer experience is at our heart. Building cloud-native applications was never that fast and simple!

                    Fully customizable for advanced business use cases

                    Create teams, split responsibilities, manage privileges, enforce company-wide rules, deploy to multiple clouds, plug in your own CI solutions. Qovery Business allows you to bring your organization to the next level with ease.

                    How Qovery works under the hood?

                    Here is a detailed explanation on how Qovery works under the hood.

                    What is an Active User?

                    An Active User is someone who made a code change on git or deployed an application in the last 30 days. We do not count contributions to public (open-source) repositories.

                    How can I contact you?

                    Feel free to join our Discord server or contact us by email at hello (at) qovery.com.

                    - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/useful-resources/help-and-support/index.html b/docs/useful-resources/help-and-support/index.html index 5c0fef21c6..8e8577c068 100644 --- a/docs/useful-resources/help-and-support/index.html +++ b/docs/useful-resources/help-and-support/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                    -

                    Help and Support

                    Qovery support

                    If you need any help, you can:

                    1. Most common issues and solutions are listed in the troubleshooting section.
                    2. Qovery Community Forum is the first place to tool at. You will find a lot of qualitative questions and answers.
                    3. Finally, if you did not receive answers on the forum or if you have a big outage, you can contact us from the product on Intercom.

                    There, you can discuss directly with our fantastic team as well as our wonderful community!

                    Cloud provider support

                    Qovery is responsible for deployed elements on your cloud provider made and maintained by Qovery. We are not responsible for the cloud provider itself.

                    +

                    Help and Support

                    Qovery support

                    If you need any help, you can:

                    1. Most common issues and solutions are listed in the troubleshooting section.
                    2. Qovery Community Forum is the first place to tool at. You will find a lot of qualitative questions and answers.
                    3. Finally, if you did not receive answers on the forum or if you have a big outage, you can contact us from the product on Intercom.

                    There, you can discuss directly with our fantastic team as well as our wonderful community!

                    Cloud provider support

                    Qovery is responsible for deployed elements on your cloud provider made and maintained by Qovery. We are not responsible for the cloud provider itself.

                    - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/audit-logs/index.html b/docs/using-qovery/audit-logs/index.html index 2adeb4b2ff..fe9e2020f4 100644 --- a/docs/using-qovery/audit-logs/index.html +++ b/docs/using-qovery/audit-logs/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                    -

                    Audit Logs

                    Qovery allows you to monitor any action happened within your organization thanks to the audit logs section. This section provides you with a complete view on any change happened within your organization configuration, providing you the answer to "who did what, where, and when?".

                    This is extremely useful when debugging complex issues and trying to understand what happened in a specific timeframe or monitor the actions done by your users within your organization.

                    You can access this section by opening the Audit logs section from the nav bar on the left

                    Audit Logs Access

                    Once entered this section, you will find here the list of events happened within your organization over the past 30 days (this is the maximum retention time).

                    Event information

                    Each event in the list is composed by the following information:

                    • Timestamp: it tells you when the event happened
                    • Event Type: it describe the type of event (Create, Update, Delete, Trigger Deployment etc..)
                    • Target Type: it defines the type of object that has been modified (Environment, Cluster, Role, Image registry etc..)
                    • Target: it defines the object that has been modified. You can get additional information on the target by hovering on it.
                    • Change: it describes what has been modified (high level information: its config, a deployment rule etc..)
                    • User: it describes who modified the object. If the change has been done via API, you will find the API token name that has changed it.
                    • Tool: it describes how the object has been changed (via the console, the qovery terraform provider, via a git push etc..)

                    Since the audit logs are based on the calls done on our API, Qovery provides you with the JSON sent in the API response for each API call (and thus, for each event). This JSON represents the status of the target object after the event has happened. You can access the JSON by clicking on the event and might be useful to get a more granular information of what has changed between two events of the same type by comparing their JSON.

                    Example: if an update happened on the configuration of an application , the stored UPDATE event will provide you access to the JSON returned by the API when the /application endpoint was called. This JSON will thus contain the configuration of the application after the update.

                    Filters

                    To simplify the research within the audit logs, you can filter the events by:

                    • Time range
                    • Target: you will have to specify a target type (cluster, environment, service etc..) and then specify the name of the target. For example, if you want to look for the changes happened on the cluster Production, you will have to select Cluster as Target type and then you will have to select Production from within the cluster list.

                    Quick Filters

                    While navigating within the console, a few quick filters allow you to jump on the audit logs and get the events happened on that specific object. For example, you can quickly get the events happened on a specific environment, by clicking on the See Events button available within the 3 dots sub-menu

                    See Events Quick Filter

                    Export

                    Not yet available, feature coming soon!

                    +

                    Audit Logs

                    Qovery allows you to monitor any action happened within your organization thanks to the audit logs section. This section provides you with a complete view on any change happened within your organization configuration, providing you the answer to "who did what, where, and when?".

                    This is extremely useful when debugging complex issues and trying to understand what happened in a specific timeframe or monitor the actions done by your users within your organization.

                    You can access this section by opening the Audit logs section from the nav bar on the left

                    Audit Logs Access

                    Once entered this section, you will find here the list of events happened within your organization over the past 30 days (this is the maximum retention time).

                    Event information

                    Each event in the list is composed by the following information:

                    • Timestamp: it tells you when the event happened
                    • Event Type: it describe the type of event (Create, Update, Delete, Trigger Deployment etc..)
                    • Target Type: it defines the type of object that has been modified (Environment, Cluster, Role, Image registry etc..)
                    • Target: it defines the object that has been modified. You can get additional information on the target by hovering on it.
                    • Change: it describes what has been modified (high level information: its config, a deployment rule etc..)
                    • User: it describes who modified the object. If the change has been done via API, you will find the API token name that has changed it.
                    • Tool: it describes how the object has been changed (via the console, the qovery terraform provider, via a git push etc..)

                    Since the audit logs are based on the calls done on our API, Qovery provides you with the JSON sent in the API response for each API call (and thus, for each event). This JSON represents the status of the target object after the event has happened. You can access the JSON by clicking on the event and might be useful to get a more granular information of what has changed between two events of the same type by comparing their JSON.

                    Example: if an update happened on the configuration of an application , the stored UPDATE event will provide you access to the JSON returned by the API when the /application endpoint was called. This JSON will thus contain the configuration of the application after the update.

                    Filters

                    To simplify the research within the audit logs, you can filter the events by:

                    • Time range
                    • Target: you will have to specify a target type (cluster, environment, service etc..) and then specify the name of the target. For example, if you want to look for the changes happened on the cluster Production, you will have to select Cluster as Target type and then you will have to select Production from within the cluster list.

                    Quick Filters

                    While navigating within the console, a few quick filters allow you to jump on the audit logs and get the events happened on that specific object. For example, you can quickly get the events happened on a specific environment, by clicking on the See Events button available within the 3 dots sub-menu

                    See Events Quick Filter

                    Export

                    Not yet available, feature coming soon!

                    - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/advanced-settings/index.html b/docs/using-qovery/configuration/advanced-settings/index.html index b135eb0d0c..c33ee9a49a 100644 --- a/docs/using-qovery/configuration/advanced-settings/index.html +++ b/docs/using-qovery/configuration/advanced-settings/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                    -

                    Service Advanced Settings

                    To further fine-tune your Qovery infrastructure, you can set advanced settings through the Advanced Settings section of your service.

                    To access the Advanced Settings section:

                    1. Select the service where you want to modify the advanced settings

                      Settings

                    2. Open the advanced settings section from the left menu

                      Advanced Settings

                    The screen shows you the list of available advanced settings and for each of them:

                    • The default value
                    • The value configured right now

                    You can show only the modified values by activating the "Show only overridden settings" feature toggle.

                    All services have access to advanced settings, you can find where they are available in the documentation below with those badges:

                    Application Deployment

                    build.timeout_max_sec

                    TypeDescriptionDefault Value
                    integerAllows you to specify an interval, in seconds, after which the application build times out.1800

                    build.cpu_max_in_milli

                    TypeDescriptionDefault Value
                    integerCPU allocated to your build process4000

                    build.ram_max_in_gib

                    TypeDescriptionDefault Value
                    integerGB RAM allocated to your build process8

                    deployment.custom_domain_check_enabled

                    TypeDescriptionUse CaseDefault Value
                    booleanQovery allows you to set custom domains for your applications through the addition of a CNAME record to your domain's DNS settings. By default, when an application is deployed, Qovery checks that the CNAME record is set up correctly. This advanced setting allows you to disable this check.If you are using a Content Delivery Network (CDN), checking the CNAME setup for any custom domains you may have set up is likely to stall the deployment of your application.

                    Therefore, if you are using a CDN behind your application, we recommend disabling this feature to save time during your application deployments.
                    true

                    deployment.termination_grace_period_seconds

                    TypeDescriptionUse CaseDefault Value
                    integerDecide how many times in seconds the application is supposed to stop at maximum. After this time, the application will be forced to stop (killed)An application requiring several tasks to be stopped properly should have a higher grace period. If the application finishes early, then it will not wait until the end of the grace period60

                    deployment.affinity.node.required

                    TypeDescriptionUse CaseDefault Value
                    Map<String, String>Set pod placement on specific Kubernetes nodes labels.Can be useful to send pods on GPU nodes or any other specific workload based on node lablels (Eg. {"eks.amazonaws.com/nodegroup": "gpu"})``

                    deployment.antiaffinity.pod

                    TypeDescriptionDefault Value
                    stringDefine how you want pods affinity to behave.
                    Preferred: allows, but does not require, pods of a given service are not co-located (or co-hosted) on a single node
                    Required: ensures that the pods of a given service are not co-located (or co-hosted) on a single node (safer in term of availability but can be expensive depending on the number of replicas)
                    Preferred

                    Deployment strategy

                    deployment.update_strategy.type

                    TypeDescriptionUse CaseDefault Value
                    stringSet deployment strategy type (RollingUpdate or Recreate)Rolling update strategy will gracefully rollout new versions, while Recreate will stop all current versions and create new ones once all old ones have been shutdown (more info)RollingUpdate

                    deployment.update_strategy.rolling_update.max_unavailable_percent

                    TypeDescriptionDefault Value
                    integerDefine the percentage of a maximum number of pods that can be unavailable during the update process (more info).25

                    deployment.update_strategy.rolling_update.max_surge_percent

                    TypeDescriptionDefault Value
                    integerDefine the percentage of the maximum number of pods that can be created over the desired number of pods (more info)25

                    Network Settings

                    network.ingress.cors_allow_headers

                    TypeDescriptionUse CaseDefault Value
                    string(For CORS users) Allows you to specify which set of headers can be present in the client request.For security purposes, you can indicate which HTTP headers can be used during a CORS preflight request which includes the Access-Control-Request-Headers request header. For more information, see CORS HTTP Response Headers."DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization"

                    network.ingress.cors_allow_methods

                    TypeDescriptionUse CaseDefault Value
                    string(For CORS users) Allows you to specify which set of methods can be used for the client request.For security purposes, you can indicate which HTTP methods are permitted while accessing a resource in response to cross-origin requests. For more information, see CORS HTTP Response Headers."GET, PUT, POST, DELETE, PATCH, OPTIONS"

                    network.ingress.cors_allow_origin

                    TypeDescriptionUse CaseDefault Value
                    string(For CORS users) Allows you to specify which origin(s) (domain, scheme, port) can access a resource.For security purposes, you can allow only one or a short list of origins to access your resources. For more information, see CORS HTTP Response Headers."*"

                    network.ingress.enable_cors

                    TypeDescriptionUse CaseDefault Value
                    booleanAllows you to enable Cross-Origin Resource Sharing (CORS).The CORS mechanism supports secure cross-origin requests and data transfers between browsers and servers. For more information on CORS and when to enable it, see Cross-Origin Resources Sharing.false

                    network.ingress.enable_sticky_session

                    TypeDescriptionUse CaseDefault Value
                    booleanAllows you to enable Sticky session.Enable the load balancer to bind a user's session to a specific target. This ensures that all requests from the user during the session are sent to the same targetfalse

                    network.ingress.keepalive_time_seconds

                    TypeDescriptionUse CaseDefault Value
                    integerLimits the maximum time (in seconds) during which requests can be processed through one keepalive connection. After this time is reached, the connection is closed following the subsequent request processing.Useful to tune your gRPC application3600

                    network.ingress.keepalive_timeout_seconds

                    TypeDescriptionUse CaseDefault Value
                    integerSets a timeout (in seconds) during which an idle keepalive connection to an upstream server will stay open.Useful to tune your gRPC application60

                    network.ingress.proxy_body_size_mb

                    TypeDescriptionUse CaseDefault Value
                    integerAllows you to set, in megabytes, a maximum size for resources that can be downloaded from your server.By default, users can download resources (files, images, videos...) of up to 100 MB. You can use this advanced setting to lower or increase this limitation.100

                    network.ingress.proxy_buffer_size_kb

                    TypeDescriptionUse CaseDefault Value
                    integerAllows you to set, in kilobytes, a header buffer size used while reading the response header from upstream.E.g. You are using Auth0 with NextJS, you will need to set a bigger header size4

                    network.ingress.proxy_connect_timeout_seconds

                    TypeDescriptionUse CaseDefault Value
                    integerDefines a timeout (in seconds) for establishing a connection with a proxied server. It should be noted that this timeout cannot usually exceed 75 seconds.E.g. You can use it to define the maximum time to wait for your application to establish the connexion.60

                    network.ingress.proxy_read_timeout_seconds

                    TypeDescriptionUse CaseDefault Value
                    integerDefines a timeout for reading a response from the proxied server. The timeout is set only between two successive read operations, not for the transmission of the whole response. If the proxied server does not transmit anything within this time, the connection is closed.E.g. You can use it to fine-tune your WebSocket application.60

                    network.ingress.proxy_send_timeout_seconds

                    TypeDescriptionUse CaseDefault Value
                    integerSets a timeout (in seconds) for transmitting a request to the proxied server. The timeout is set only between two successive write operations, not for the transmission of the whole request. If the proxied server does not receive anything within this time, the connection is closed.E.g. You can use it to fine-tune your WebSocket application.60

                    network.ingress.proxy_buffering

                    TypeDescriptionDefault Value
                    stringAllows you to enable or disable nginx proxy-buffering. Valid values are on or offon

                    network.ingress.proxy_request_buffering

                    TypeDescriptionDefault Value
                    stringAllows you to enable or disable nginx proxy-request_buffering. Valid values are on or offon

                    network.ingress.send_timeout_seconds

                    TypeDescriptionUse CaseDefault Value
                    integerSets a timeout (in seconds) for transmitting a response to the client. The timeout is set only between two successive write operations, not for the transmission of the whole response. If the client does not receive anything within this time, the connection is closed.Useful to define the maximum timeout to wait for client connection.60

                    network.ingress.whitelist_source_range

                    TypeDescriptionUse CaseDefault Value
                    stringAllows you to specify which IP ranges are allowed to access your application. The value is a comma-separated list of CIDRs, e.g. 10.0.0.0/24,172.10.0.1By default, any IP can access your application if it's exposed publicly and the users know the URL. You can limit its access by specifying the IPs you want to reach the app (e.g. the IP of your office)0.0.0.0/0 (any IP)

                    network.ingress.denylist_source_range

                    TypeDescriptionDefault Value
                    stringAllows you to specify which IP ranges are not allowed to access your application. The value is a comma-separated list of CIDRs, e.g. 10.0.0.0/24,172.10.0.1``

                    network.ingress.basic_auth_env_var

                    TypeDescriptionDefault Value
                    stringSet the name of an environment variable to use as a basic authentication (login:crypted_password) from htpasswd command.``

                    Here is an example where you can create a secret environment variable on Qovery and set a name like BASIC_AUTH_CREDENTIALS. The content should be the result of the htpasswd command:

                    $ htpasswd -n <username>
                    New password:
                    Re-type new password:
                    username:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20

                    The content of the BASIC_AUTH_CREDENTIALS environment variable should be: username:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20. To finish, set the network.ingress.basic_auth_env_var advanced settings to BASIC_AUTH_CREDENTIALS.

                    You can pass set credentials by separating them with a comma. For example: username1:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20,username2:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20. However, the total length of the environment variable should not exceed 1MB.

                    network.ingress.extra_headers

                    TypeDescriptionDefault Value
                    stringAllows you to specify response headers with values separated by comma (e.g. {"X-Frame-Options":"DENY","X-Content-Type-Options":"nosniff"}{}

                    Auto-scaling

                    hpa.cpu.average_utilization_percent

                    TypeDescriptionDefault Value
                    integerAuto-scaling is triggered when a specific CPU utilization metric is reached (for instance, 40%). This advanced setting allows you to set this metric.60

                    Job Settings

                    job.delete_ttl_seconds_after_finished

                    TypeDescriptionDefault Value
                    integerBy default terminated jobs in a completed or failure state are not deleted. if this parameter is set, Kubernetes will automatically cleanup completed jobs after the ttlnull

                    cronjob.concurrency_policy

                    TypeDescriptionDefault Value
                    stringIt defines if it is allowed to start another instance of the same job if the previous execution didn't finish yet: Allow/Forbid/Replace)Forbidden

                    cronjob.failed_job_history_limit

                    TypeDescriptionDefault Value
                    stringAllows you to define the maximum number of failed job executions that should be returned in the job execution history1

                    cronjob.success_job_history_limit

                    TypeDescriptionDefault Value
                    stringAllows you to define the maximum number of succeeded job executions that should be returned in the job execution history1

                    Security

                    security.service_account_name

                    TypeDescriptionUse CaseDefault Value
                    stringAllows you to set an existing Kubernetes service account nameE.g. On AWS, you can assume a role on an application to give it specific AWS permissions without having to specify AWS credentials``
                    +

                    Service Advanced Settings

                    To further fine-tune your Qovery infrastructure, you can set advanced settings through the Advanced Settings section of your service.

                    To access the Advanced Settings section:

                    1. Select the service where you want to modify the advanced settings

                      Settings

                    2. Open the advanced settings section from the left menu

                      Advanced Settings

                    The screen shows you the list of available advanced settings and for each of them:

                    • The default value
                    • The value configured right now

                    You can show only the modified values by activating the "Show only overridden settings" feature toggle.

                    All services have access to advanced settings, you can find where they are available in the documentation below with those badges:

                    Application Deployment

                    build.timeout_max_sec

                    TypeDescriptionDefault Value
                    integerAllows you to specify an interval, in seconds, after which the application build times out.1800

                    build.cpu_max_in_milli

                    TypeDescriptionDefault Value
                    integerCPU allocated to your build process4000

                    build.ram_max_in_gib

                    TypeDescriptionDefault Value
                    integerGB RAM allocated to your build process8

                    deployment.custom_domain_check_enabled

                    TypeDescriptionUse CaseDefault Value
                    booleanQovery allows you to set custom domains for your applications through the addition of a CNAME record to your domain's DNS settings. By default, when an application is deployed, Qovery checks that the CNAME record is set up correctly. This advanced setting allows you to disable this check.If you are using a Content Delivery Network (CDN), checking the CNAME setup for any custom domains you may have set up is likely to stall the deployment of your application.

                    Therefore, if you are using a CDN behind your application, we recommend disabling this feature to save time during your application deployments.
                    true

                    deployment.termination_grace_period_seconds

                    TypeDescriptionUse CaseDefault Value
                    integerDecide how many times in seconds the application is supposed to stop at maximum. After this time, the application will be forced to stop (killed)An application requiring several tasks to be stopped properly should have a higher grace period. If the application finishes early, then it will not wait until the end of the grace period60

                    deployment.affinity.node.required

                    TypeDescriptionUse CaseDefault Value
                    Map<String, String>Set pod placement on specific Kubernetes nodes labels.Can be useful to send pods on GPU nodes or any other specific workload based on node lablels (Eg. {"eks.amazonaws.com/nodegroup": "gpu"})``

                    deployment.antiaffinity.pod

                    TypeDescriptionDefault Value
                    stringDefine how you want pods affinity to behave.
                    Preferred: allows, but does not require, pods of a given service are not co-located (or co-hosted) on a single node
                    Required: ensures that the pods of a given service are not co-located (or co-hosted) on a single node (safer in term of availability but can be expensive depending on the number of replicas)
                    Preferred

                    Deployment strategy

                    deployment.update_strategy.type

                    TypeDescriptionUse CaseDefault Value
                    stringSet deployment strategy type (RollingUpdate or Recreate)Rolling update strategy will gracefully rollout new versions, while Recreate will stop all current versions and create new ones once all old ones have been shutdown (more info)RollingUpdate

                    deployment.update_strategy.rolling_update.max_unavailable_percent

                    TypeDescriptionDefault Value
                    integerDefine the percentage of a maximum number of pods that can be unavailable during the update process (more info).25

                    deployment.update_strategy.rolling_update.max_surge_percent

                    TypeDescriptionDefault Value
                    integerDefine the percentage of the maximum number of pods that can be created over the desired number of pods (more info)25

                    Network Settings

                    network.ingress.cors_allow_headers

                    TypeDescriptionUse CaseDefault Value
                    string(For CORS users) Allows you to specify which set of headers can be present in the client request.For security purposes, you can indicate which HTTP headers can be used during a CORS preflight request which includes the Access-Control-Request-Headers request header. For more information, see CORS HTTP Response Headers."DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization"

                    network.ingress.cors_allow_methods

                    TypeDescriptionUse CaseDefault Value
                    string(For CORS users) Allows you to specify which set of methods can be used for the client request.For security purposes, you can indicate which HTTP methods are permitted while accessing a resource in response to cross-origin requests. For more information, see CORS HTTP Response Headers."GET, PUT, POST, DELETE, PATCH, OPTIONS"

                    network.ingress.cors_allow_origin

                    TypeDescriptionUse CaseDefault Value
                    string(For CORS users) Allows you to specify which origin(s) (domain, scheme, port) can access a resource.For security purposes, you can allow only one or a short list of origins to access your resources. For more information, see CORS HTTP Response Headers."*"

                    network.ingress.enable_cors

                    TypeDescriptionUse CaseDefault Value
                    booleanAllows you to enable Cross-Origin Resource Sharing (CORS).The CORS mechanism supports secure cross-origin requests and data transfers between browsers and servers. For more information on CORS and when to enable it, see Cross-Origin Resources Sharing.false

                    network.ingress.enable_sticky_session

                    TypeDescriptionUse CaseDefault Value
                    booleanAllows you to enable Sticky session.Enable the load balancer to bind a user's session to a specific target. This ensures that all requests from the user during the session are sent to the same targetfalse

                    network.ingress.keepalive_time_seconds

                    TypeDescriptionUse CaseDefault Value
                    integerLimits the maximum time (in seconds) during which requests can be processed through one keepalive connection. After this time is reached, the connection is closed following the subsequent request processing.Useful to tune your gRPC application3600

                    network.ingress.keepalive_timeout_seconds

                    TypeDescriptionUse CaseDefault Value
                    integerSets a timeout (in seconds) during which an idle keepalive connection to an upstream server will stay open.Useful to tune your gRPC application60

                    network.ingress.proxy_body_size_mb

                    TypeDescriptionUse CaseDefault Value
                    integerAllows you to set, in megabytes, a maximum size for resources that can be downloaded from your server.By default, users can download resources (files, images, videos...) of up to 100 MB. You can use this advanced setting to lower or increase this limitation.100

                    network.ingress.proxy_buffer_size_kb

                    TypeDescriptionUse CaseDefault Value
                    integerAllows you to set, in kilobytes, a header buffer size used while reading the response header from upstream.E.g. You are using Auth0 with NextJS, you will need to set a bigger header size4

                    network.ingress.proxy_connect_timeout_seconds

                    TypeDescriptionUse CaseDefault Value
                    integerDefines a timeout (in seconds) for establishing a connection with a proxied server. It should be noted that this timeout cannot usually exceed 75 seconds.E.g. You can use it to define the maximum time to wait for your application to establish the connexion.60

                    network.ingress.proxy_read_timeout_seconds

                    TypeDescriptionUse CaseDefault Value
                    integerDefines a timeout for reading a response from the proxied server. The timeout is set only between two successive read operations, not for the transmission of the whole response. If the proxied server does not transmit anything within this time, the connection is closed.E.g. You can use it to fine-tune your WebSocket application.60

                    network.ingress.proxy_send_timeout_seconds

                    TypeDescriptionUse CaseDefault Value
                    integerSets a timeout (in seconds) for transmitting a request to the proxied server. The timeout is set only between two successive write operations, not for the transmission of the whole request. If the proxied server does not receive anything within this time, the connection is closed.E.g. You can use it to fine-tune your WebSocket application.60

                    network.ingress.proxy_buffering

                    TypeDescriptionDefault Value
                    stringAllows you to enable or disable nginx proxy-buffering. Valid values are on or offon

                    network.ingress.proxy_request_buffering

                    TypeDescriptionDefault Value
                    stringAllows you to enable or disable nginx proxy-request_buffering. Valid values are on or offon

                    network.ingress.send_timeout_seconds

                    TypeDescriptionUse CaseDefault Value
                    integerSets a timeout (in seconds) for transmitting a response to the client. The timeout is set only between two successive write operations, not for the transmission of the whole response. If the client does not receive anything within this time, the connection is closed.Useful to define the maximum timeout to wait for client connection.60

                    network.ingress.whitelist_source_range

                    TypeDescriptionUse CaseDefault Value
                    stringAllows you to specify which IP ranges are allowed to access your application. The value is a comma-separated list of CIDRs, e.g. 10.0.0.0/24,172.10.0.1By default, any IP can access your application if it's exposed publicly and the users know the URL. You can limit its access by specifying the IPs you want to reach the app (e.g. the IP of your office)0.0.0.0/0 (any IP)

                    network.ingress.denylist_source_range

                    TypeDescriptionDefault Value
                    stringAllows you to specify which IP ranges are not allowed to access your application. The value is a comma-separated list of CIDRs, e.g. 10.0.0.0/24,172.10.0.1``

                    network.ingress.basic_auth_env_var

                    TypeDescriptionDefault Value
                    stringSet the name of an environment variable to use as a basic authentication (login:crypted_password) from htpasswd command.``

                    Here is an example where you can create a secret environment variable on Qovery and set a name like BASIC_AUTH_CREDENTIALS. The content should be the result of the htpasswd command:

                    $ htpasswd -n <username>
                    New password:
                    Re-type new password:
                    username:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20

                    The content of the BASIC_AUTH_CREDENTIALS environment variable should be: username:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20. To finish, set the network.ingress.basic_auth_env_var advanced settings to BASIC_AUTH_CREDENTIALS.

                    You can pass set credentials by separating them with a comma. For example: username1:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20,username2:$apr1$jpwW4vG9$fwbzWBgRqARzNX93plDq20. However, the total length of the environment variable should not exceed 1MB.

                    network.ingress.extra_headers

                    TypeDescriptionDefault Value
                    stringAllows you to specify response headers with values separated by comma (e.g. {"X-Frame-Options":"DENY","X-Content-Type-Options":"nosniff"}{}

                    Auto-scaling

                    hpa.cpu.average_utilization_percent

                    TypeDescriptionDefault Value
                    integerAuto-scaling is triggered when a specific CPU utilization metric is reached (for instance, 40%). This advanced setting allows you to set this metric.60

                    Job Settings

                    job.delete_ttl_seconds_after_finished

                    TypeDescriptionDefault Value
                    integerBy default terminated jobs in a completed or failure state are not deleted. if this parameter is set, Kubernetes will automatically cleanup completed jobs after the ttlnull

                    cronjob.concurrency_policy

                    TypeDescriptionDefault Value
                    stringIt defines if it is allowed to start another instance of the same job if the previous execution didn't finish yet: Allow/Forbid/Replace)Forbidden

                    cronjob.failed_job_history_limit

                    TypeDescriptionDefault Value
                    stringAllows you to define the maximum number of failed job executions that should be returned in the job execution history1

                    cronjob.success_job_history_limit

                    TypeDescriptionDefault Value
                    stringAllows you to define the maximum number of succeeded job executions that should be returned in the job execution history1

                    Security

                    security.service_account_name

                    TypeDescriptionUse CaseDefault Value
                    stringAllows you to set an existing Kubernetes service account nameE.g. On AWS, you can assume a role on an application to give it specific AWS permissions without having to specify AWS credentials``
                    - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/application-health-checks/index.html b/docs/using-qovery/configuration/application-health-checks/index.html index 52c7560656..1f27aa907d 100644 --- a/docs/using-qovery/configuration/application-health-checks/index.html +++ b/docs/using-qovery/configuration/application-health-checks/index.html @@ -21,30 +21,30 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -57,27 +57,27 @@ Exec probes allow to define a command to be executed within your container. If the command execution fails, the probe is considered as failed.

                    Initial Delay (in seconds)

                    Allows you to specify an interval, in seconds, between the application container start and the first liveness check.

                    Allowing additional time for the application to start can be useful when boot time usually takes too long (due to long boot operations), or when the application opens the port before being ready to receive traffic on it (due to a still ongoing boot operation).

                    Period (in seconds)

                    Allows you to specify an interval, in seconds, between each probe.

                    Timeout (in seconds)

                    Allows you to specify the interval, in seconds, after which the probe times out.

                    Success Threshold

                    Allows you to specify how many consecutive successes are needed, as a minimum, for the probe to be considered successful after having failed previously.

                    Failure Threshold

                    Allows you to specify how many consecutive failures are needed, as a minimum, for the probe to be considered failed after having succeeded previously.

                    Configuiration for Long-starting application

                    If your application has a long boot operation to run, your deployment might be marked as failed since the probe can't verify the state of your application within the specified time frame. In this case, you will find in your deployment logs a warning message Liveness probe failed: dial tcp xx.xx.xx.xx:xx: connect: connection refused , telling you that the probe is failing.

                    If your application needs more time to boot, increase the Initial Delay in seconds of the probes to match the application boot time.

                    - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/application/index.html b/docs/using-qovery/configuration/application/index.html index 4c1f7eb0cc..2be7bdb133 100644 --- a/docs/using-qovery/configuration/application/index.html +++ b/docs/using-qovery/configuration/application/index.html @@ -21,66 +21,66 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                    -

                    Application

                    An application is part of a Project within an Environment and is a container unit. Multiple applications can be part of the same Environment, be connected to a set of dependencies (databases and other services), and can communicate with other applications within the same Environment.

                    Qovery allows you to create and deploy applications from two different sources: Git Repository or Container Registry

                    Deploying from a Git Repository

                    In this configuration, Qovery will pull the code from the chosen repository, build the application and deploy it on your kubernetes cluster.

                    The list of Git repositories available during the setup is strictly tied to the permissions of your git account (by default Qovery can access all your repositories). If you want to restrict the Qovery access only to a few repositories, user the GitHub Qovery Application (only for Github).

                    Deploying from a Container Registry

                    In this configuration, Qovery will pull the chosen container registry an image you have pre-built and deploy it on your kubernetes cluster.

                    To improve security and avoid deploying images from non-authorized registries, we have decided to restrict the list of Container Registry you can use during the setup process. Only an administrator with the right permissions can manage it from the Container Registry Management page

                    Create an Application

                    1. Go into the chosen environment and press the "New Service" button and then the "Create application" button

                      Creation

                    2. Select the following fields:

                      • Application Name: give a name to your application
                      • Application Source: Chose between Git Repository or Container Registry, depending on the source location of your application

                      If you want to deploy an application from a Git Repository you will have to select:

                      • Git Repository: Select the git provider hosting your code (it can be hosted on GitHub, GitLab or Bitbucket).
                      • Branch: Select branch that Qovery should use to deploy your application
                      • Root Application Path: base folder in which the application resides in your repository
                      • Build Mode: choose between Docker or Buildpack. For more information, go to this section

                      If you want to deploy an application from a Container Registry you will have to select:

                      • Registry: select the container registry storing the image of your application. Note: only pre-configured registry are available in this list, check the Container Registry Management page for more information.
                      • Image name: the name of the image to be deployed with this application (example: postgres)
                      • Image tag: the tag of the image to be deployed with this application (example: 1.0).
                      • Image Entrypoint: the entrypoint to be used to launch your applicaiton (not mandatory)
                      • CMD Arguments: the arguments to be passed to launch your applicaiton (not mandatory). We expect the format to be an array. Example ["rails", "-h", "0.0.0.0", "-p", "8080", "string"]

                      Auto Deploy

                      See the Deploying with auto-deploy feature section.

                    3. Within this section, you will need to define the resources to be assigned to your application at run time.

                      • vCPU: the vCPU assigned to each instance of your application. The default is 500m (0.5 vCPU).
                      • RAM: the amount of RAM assigned to each instance of your application. The default is 512MB.
                      • Number of instances (Application Auto-scaling): select the minimum and the maximum number of instances of your application that can run within your cluster. The number of instances running at an insant t is automatically managed by Kubernetes (Application auto-scaling) and it is based on real-time CPU consumption. When your app goes above 60% of CPU consumption for 5 minutes, your app will be auto-scaled and more instances will be added. It is transparent. +

                        Application

                        An application is part of a Project within an Environment and is a container unit. Multiple applications can be part of the same Environment, be connected to a set of dependencies (databases and other services), and can communicate with other applications within the same Environment.

                        Qovery allows you to create and deploy applications from two different sources: Git Repository or Container Registry

                        Deploying from a Git Repository

                        In this configuration, Qovery will pull the code from the chosen repository, build the application and deploy it on your kubernetes cluster.

                        The list of Git repositories available during the setup is strictly tied to the permissions of your git account (by default Qovery can access all your repositories). If you want to restrict the Qovery access only to a few repositories, user the GitHub Qovery Application (only for Github).

                        Deploying from a Container Registry

                        In this configuration, Qovery will pull the chosen container registry an image you have pre-built and deploy it on your kubernetes cluster.

                        To improve security and avoid deploying images from non-authorized registries, we have decided to restrict the list of Container Registry you can use during the setup process. Only an administrator with the right permissions can manage it from the Container Registry Management page

                        Create an Application

                        1. Go into the chosen environment and press the "New Service" button and then the "Create application" button

                          Creation

                        2. Select the following fields:

                          • Application Name: give a name to your application
                          • Application Source: Chose between Git Repository or Container Registry, depending on the source location of your application

                          If you want to deploy an application from a Git Repository you will have to select:

                          • Git Repository: Select the git provider hosting your code (it can be hosted on GitHub, GitLab or Bitbucket).
                          • Branch: Select branch that Qovery should use to deploy your application
                          • Root Application Path: base folder in which the application resides in your repository
                          • Build Mode: choose between Docker or Buildpack. For more information, go to this section

                          If you want to deploy an application from a Container Registry you will have to select:

                          • Registry: select the container registry storing the image of your application. Note: only pre-configured registry are available in this list, check the Container Registry Management page for more information.
                          • Image name: the name of the image to be deployed with this application (example: postgres)
                          • Image tag: the tag of the image to be deployed with this application (example: 1.0).
                          • Image Entrypoint: the entrypoint to be used to launch your applicaiton (not mandatory)
                          • CMD Arguments: the arguments to be passed to launch your applicaiton (not mandatory). We expect the format to be an array. Example ["rails", "-h", "0.0.0.0", "-p", "8080", "string"]

                          Auto Deploy

                          See the Deploying with auto-deploy feature section.

                        3. Within this section, you will need to define the resources to be assigned to your application at run time.

                          • vCPU: the vCPU assigned to each instance of your application. The default is 500m (0.5 vCPU).
                          • RAM: the amount of RAM assigned to each instance of your application. The default is 512MB.
                          • Number of instances (Application Auto-scaling): select the minimum and the maximum number of instances of your application that can run within your cluster. The number of instances running at an insant t is automatically managed by Kubernetes (Application auto-scaling) and it is based on real-time CPU consumption. When your app goes above 60% of CPU consumption for 5 minutes, your app will be auto-scaled and more instances will be added. It is transparent. Qovery runs your application on Kubernetes and relies on metrics-server service to auto-scale your app.

                          Resources

                        4. You can now define one or more ports for your Application. Most of the application needs to be accessed by other services inside or outside your environment over different L7/L4 protocols. -Today Qovery supports the following protocols:

                          • HTTPS (Select this protocol if you need to run Websockets)
                          • gRPC
                          • TCP
                          • UDP

                          By default ports are accessible only from inside your environment. You can also expose them publicly, making them accessible over the public network via a dedicated public domain that will be assigned to your application by Qovery during the deployment (See the Qovery Provided Domains section). Note that HTTPS/gRPC ports are always exposed over the port 443.

                          Application Ports

                          Important Informations

                          • Most of the Kubernetes Health Checks are based on the port declared in this section. Make sure you declare the right port and that you configure the health checks properly.
                          • Connections on public ports are automatically closed after 60 seconds. If you want to implement long living connection (like for websockets) please make sure to use the rigth ingress timeouts in the advanced settings section
                          • Exposing publicly TCP/UDP ports requires to create a dedicated load balancer and it takes a few minutes before having it ready (~15 minutes). Note also that this has a direct impact on your cloud provider bill.
                          • You can configure your application to use the PORT environment variable by adding the PORT on your application env variables page.
                          • A Note on Listening IPs: It's best for your application to listen on 0.0.0.0:$PORT. While most things work with 127.0.0.1 and localhost, some do not (NodeJS for example)
                        5. (Optional) If a port has been defined for your application, you can define the health check probes to run in order to verify the state of your application

                          To know more about how to configure your Liveness and Readiness probes, have a look at the health-checks section

                        6. You will find a recap of your application setup and you can now decide to:

                          Go back to one of the previous steps and change your application settings

                          Create your application without deploying it

                          Create and deploy your application

                          Application

                        Deployment Management

                        Have a look at the Deployment Management section for more information.

                        Configuration

                        Once created, you can access the configuration of an application at any time via the Settings tab available on the application section

                        Application Settings

                        You can find below the description of each of the tabs available in this section

                        General

                        General settings section allows you to set up your application name and the source code location (git repository or image registry) .

                        Git Repository

                        If your application is built and deployed from a git repository, within this section you can:

                        • Modify the git provider where your code is stored (it can be hosted on GitHub, GitLab or Bitbucket).
                        • Modify the branch that Qovery should use for deploying your application
                        • Modify Root Application Path - base folder in which the application resides in your repository

                        General Settings Git

                        Container Registry

                        If your application is deployed from an image registry, within this section you can modify:

                        • Registry: select the container registry storing the image of your application. Note: only pre-configured registry are available in this list, check the Container Registry Management page for more information.
                        • Image name: the name of the image to be deployed with this application (example: postgres)
                        • Image tag: the tag of the image to be deployed with this application (example: 1.0).
                        • Image Entrypoint: the entrypoint to be used to launch your applicaiton (not mandatory)
                        • CMD Arguments: the arguments to be passed to launch your applicaiton (not mandatory). We expect the format to be an array. Example ["rails", "-h", "0.0.0.0", "-p", "8080", "string"]

                        General Settings Git

                        Build Mode

                        This option is available only if you have selected "Git Repository" as source

                        Option 1: Buildpacks

                        To simplify the application build for the developer, Qovery supports Buildpacks out of the box. Buildpacks determine the build process for an app and which assets and runtimes should be made available to your code at runtime. If your complex apps are running multiple languages, you can also use multiple buildpacks within a single app. +Today Qovery supports the following protocols:

                        • HTTPS (Select this protocol if you need to run Websockets)
                        • gRPC
                        • TCP
                        • UDP

                        By default ports are accessible only from inside your environment. You can also expose them publicly, making them accessible over the public network via a dedicated public domain that will be assigned to your application by Qovery during the deployment (See the Qovery Provided Domains section). Note that HTTPS/gRPC ports are always exposed over the port 443.

                        Application Ports

                        Important Informations

                        • Most of the Kubernetes Health Checks are based on the port declared in this section. Make sure you declare the right port and that you configure the health checks properly.
                        • Connections on public ports are automatically closed after 60 seconds. If you want to implement long living connection (like for websockets) please make sure to use the rigth ingress timeouts in the advanced settings section
                        • Exposing publicly TCP/UDP ports requires to create a dedicated load balancer and it takes a few minutes before having it ready (~15 minutes). Note also that this has a direct impact on your cloud provider bill.
                        • You can configure your application to use the PORT environment variable by adding the PORT on your application env variables page.
                        • A Note on Listening IPs: It is best for your application to listen on 0.0.0.0:$PORT. While most things work with 127.0.0.1 and localhost, some do not (NodeJS for example)
                      • (Optional) If a port has been defined for your application, you can define the health check probes to run in order to verify the state of your application

                        To know more about how to configure your Liveness and Readiness probes, have a look at the health-checks section

                      • You will find a recap of your application setup and you can now decide to:

                        • Go back to one of the previous steps and change your application settings
                        • Create your application without deploying it
                        • Create and deploy your application

                        Application

                    Deployment Management

                    Have a look at the Deployment Management section for more information.

                    Configuration

                    Once created, you can access the configuration of an application at any time via the Settings tab available on the application section

                    Application Settings

                    You can find below the description of each of the tabs available in this section

                    General

                    General settings section allows you to set up your application name and the source code location (git repository or image registry) .

                    Git Repository

                    If your application is built and deployed from a git repository, within this section you can:

                    • Modify the git provider where your code is stored (it can be hosted on GitHub, GitLab or Bitbucket).
                    • Modify the branch that Qovery should use for deploying your application
                    • Modify Root Application Path - base folder in which the application resides in your repository

                    General Settings Git

                    Container Registry

                    If your application is deployed from an image registry, within this section you can modify:

                    • Registry: select the container registry storing the image of your application. Note: only pre-configured registry are available in this list, check the Container Registry Management page for more information.
                    • Image name: the name of the image to be deployed with this application (example: postgres)
                    • Image tag: the tag of the image to be deployed with this application (example: 1.0).
                    • Image Entrypoint: the entrypoint to be used to launch your applicaiton (not mandatory)
                    • CMD Arguments: the arguments to be passed to launch your applicaiton (not mandatory). We expect the format to be an array. Example ["rails", "-h", "0.0.0.0", "-p", "8080", "string"]

                    General Settings Git

                    Build Mode

                    This option is available only if you have selected "Git Repository" as source

                    Option 1: Buildpacks

                    To simplify the application build for the developer, Qovery supports Buildpacks out of the box. Buildpacks determine the build process for an app and which assets and runtimes should be made available to your code at runtime. If your complex apps are running multiple languages, you can also use multiple buildpacks within a single app. Meaning, as a developer, you don't need to write a Dockerfile to build and run your app. Qovery Buildpacks takes care of everything for you.

                    Supported languages

                    languageversion
                    Node.JSany
                    Clojureany
                    Pythonany
                    Javaany
                    Gradleany
                    JVMany
                    Grailsany
                    Scalaany
                    Playany
                    PHPany
                    Goany

                    You don't find a cool language? Suggest us to support it

                    Option 2: Dockerfile

                    Qovery runs your application within the Container technology. To build and run your application, you need to provide a valid Dockerfile.

                    Valid NodeJS Dockerfile
                    FROM node:13-alpine
                    RUN mkdir -p /usr/src/app
                    WORKDIR /usr/src/app
                    COPY . .
                    RUN npm install
                    EXPOSE 3000
                    CMD node ./bin/www

                    After creating a Dockerfile, specify the location of your Dockerfile in Dockefile path field.

                    Configuration from above will make Qovery look for the Dockerfile in /timescale/Dockerfile path of your repository (Root Application Path + Dockerfile Path).

                    Auto Deploy

                    See the Deploying with auto-deploy feature section.

                    Resources

                    CPU

                    CPU

                    To configure the number of CPUs that your app needs, adjust the setting in the Resources section of the application configuration.

                    Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consumes fewer resources, the cluster will still reserve the selected amount of CPU.

                    RAM

                    To configure the amount of RAM that your app needs, adjust the setting in Resources section of the application configuration.

                    Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU. If your application requires more RAM than requested, it will be killed by the kubernetes scheduler.

                    Auto-scaling

                    Application auto-scaling is based on real-time CPU consumption. When your app goes above 60% of CPU consumption for 15 seconds, your app will be auto-scaled and more instances will be added. It is transparent. The downscale will happen if the CPU consumption is lower than 60% for at least 5 minutes. You can adjust the minimum and maximum of instances you need in your application settings. Qovery runs your application on Kubernetes and relies on metrics-server service to auto-scale your app.

                    Storage

                    Block Storage

                    The default filesystem for applications running on Qovery is ephemeral. Application data isn’t persisted across deploys and restarts, which works just fine for most apps because they use managed databases to persist data.

                    However, many applications need persistent disk storage that isn’t ephemeral. These include:

                    • Blogging platforms and CMSs like WordPress, Ghost, and Strapi.
                    • Collaboration apps like Mattermost, GitLab, and Discourse.

                    This is where Qovery block Storage comes in. Qovery applications can use storage to store data that persists across deploys and restarts, making it easy to deploy stateful applications.

                    Use cases
                    ✅ Good use cases
                    • For I/O intensive applications (E.g. database)
                    • To store temporary files
                    ❌ Bad use cases
                    • To store file > 1 TB
                    • To expose files from an application (E.g. images)
                    Types of Block Storage

                    Qovery Storage supports:

                    TypeMax IOPSMax ThroughputMin SizeMax SizeUse cases
                    fast_ssd640001GB/s5GB10GB Community / 1TB paid plansCritical business applications that require sustained IOPS like databases
                    Configuration

                    You can set up your Block Storage in Storage section of your application configuration.

                    Application Storage

                    Ports

                    Within this section you can define the port exposed by your application to the other services or even over the internet. -You can edit the existing ports or declare new ones by specifying:

                    • Application port: this is the port exposed internally by your application for the other services.
                    • Protocol: you can select the protocol used by your application : HTTP (for both standard HTTP or websocket communications), gRPC, TCP, UDP.
                    • Publicly exposed: it allows you to expose over the public network your service. A public domain will be assigned to your application during the deployment (see Connectin from the internet section)
                    • If Publicly Exposed is selected:
                      • External port: it is the port that can be used to access this service over the internet (when exposed publicly). Note that for HTTP and gRPC the port is set by default to 443.
                      • Port Name: it is the name assigned to the port. When multiple ports are exposed publicly, its value is used to route the traffic to the right port based on the called subdomain (which will contain the port name value). Since each port is exposed on the port 443, having a different subdomain is the only way to have multiple ports exposed over the internet. If not set, the default value is p<portNumber> (see Qovery Provided Domain section for more information)

                    Application Ports

                    Important Informations

                    • Most of the Kubernetes Health Checks]docs.using-qovery.configuration.service-health-checks are based on the port declared in this section. Make sure you declare the right port and that you configure the health checks properly.
                    • Connections on public ports are automatically closed after 60 seconds. If you want to implement long living connection (like for websockets) please make sure to use the rigth ingress timeouts in the advanced settings section
                    • Exposing publicly TCP/UDP ports requires to create a dedicated load balancer and it takes a few minutes before having it ready (~15 minutes). Note also that this has a direct impact on your cloud provider bill.
                    • You can configure your application to use the PORT environment variable by adding the PORT on your application env variables page.
                    • A Note on Listening IPs: It's best for your application to listen on 0.0.0.0:$PORT. While most things work with 127.0.0.1 and localhost, some do not (NodeJS for example)

                    Health Checks

                    To know more about how to configure your Liveness and Readiness probes, have a look at the health-checks section

                    Domains

                    Within this section you can customize the domain used to reach your application.

                    You can customize the domain of your application in different ways, depending on what you want to achieve:

                    • You want to use your own domain for this application
                    • You want to modify the subdomain assigned to your application by Qovery (i.e. change p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh into my-app-domain.za8ad0657.bool.sh).

                    In both cases, you can assign the new custom domain to your application press the Add Domain button.

                    Application Domains

                    Configuring your own domain

                    Once the domain is added within the Qovery console (Example: mydomain.com), you need to configure within your DNS two CNAME records pointing to the domain provided by Qovery, as shown in the UI (example: mydomain.com CNAME za7cc1b71-z4b8474b3-gtw.zc531a994.rustrocks.cloud and *.mydomain.com CNAME za7cc1b71-z4b8474b3-gtw.zc531a994.rustrocks.cloud).

                    Having a wildcard domain (example: *.mydomain.com) configured on your DNS will avoid you to modify the Qovery setup every time you want to add a new subdomain. If wildcard is not supported by your DNS provider, you will have to configure each subdomain manually.

                    If the service needs to expose more than one port publicly, you can define a dedicated subdomain to redirect the traffic on the right port by setting the “Port Name” value within the port settings.

                    From this point, Qovery will automatically handle the TLS/SSL certificate creation and renewal for the configured domain.

                    Custom Domain

                    Special case - CDN in proxy mode

                    If your service is behind a CDN using a proxy mode (i.e. the traffic is routed through the CDN to Qovery), make sure to disable the option "Generate certificate" on the domain setup. Since the certificate of your domain is directly managed by the CDN, Qovery won't be able to do that for you and it will raise warnings on your application status.

                    CDN Proxy

                    Change the auto assigned sub-domain

                    You can specify a different sub-domain for your application as long as it belongs to the assigned cluster domain (see Qovery provided domains). -Example:

                    • your current domain is zdf72de71-z709e1a85-gtw.za8ad0659.bool.sh (so your assigned cluster domain is za8ad0659.bool.sh)
                    • you can enter a new custom domain myfrontend.za8ad0659.bool.sh (since it is a subdomain of the cluster domain)

                    The application will now be accessible from both the default and the new custom domain.

                    Connecting from the internet

                    Your application can be reached from the internet by publicly exposing at least one of its ports (See the Ports section to know more). Once this is done, Qovery will generate for you a domain to reach your application from the internet. You can also customize the domain assigned to your application and manage by yourself this assignment via the Domain section.

                    Qovery provided domains

                    For each port publicly exposed, a domain is automatically assigned by Qovery to your application. Qovery will manage for you the networking and the TLS configuration for these domains.

                    Example: p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh

                    Note:

                    • each service deployed on the same cluster will have the same root domain assigned (example: za8ad0657.bool.sh)
                    • the first characters of the domain (before the -) is based on the portName given to the port associated with this domain (See the port section)
                    • a default domain (without the portName) is assigned to the default port(See the port section). Example zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh

                    Special Case - Preview Environment -For each port exposed publicly, an additional domain will be created with the following pattern portName-prId-srvName-envSourceName.cluster_domain:

                    • portName: is the port name, as explained above
                    • prID: is the id of the PR that has generated the preview environment
                    • srvName: is the name of the service
                    • envSourceName: is the name of the blueprint environment that has created the current preview environment

                    domain example: p80-123-frontend-blueprint.za8ad0657.bool.sh

                    Custom domains

                    If you prefer to assign your own domain to the application have a look at the Domain section to know more.

                    Connecting to a database

                    To know how to access your database from your application, have a look at the database section.

                    Connecting to another application

                    To know how to access your database from your application, have a look at the database section.

                    Environment Variable

                    To learn how to set up environment variables in your projects and applications, navigate to configuring Environment Variables section.

                    Secrets

                    To learn how to set up secrets in your projects and applications, navigate to configuring Secrets section.

                    Logs

                    To learn how to display your application logs, navigate to logs section

                    SSH

                    To connect to your application via SSH, please use the via the Qovery SSH command available on our CLI.

                    Clone

                    You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment.

                    Clone Service

                    The target environment can be the same as the current environment or even another one in a completely different project.

                    Important information

                    Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:

                    • same environment:
                      • custom domain: this setup is not copied into the new service (to avoid collision)
                    • another environment:
                      • custom domain: this setup is not copied into the new service (to avoid collision)
                      • environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)
                      • deployment pipeline: stage setup is not copied (since the target stage might not exist)
                      • number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)

                    Please check the configuration of the new service before deploying it.

                    Delete an Application

                    1. Choose your application

                    2. In the application overview, click on the 3 dots button and remove the application.

                      Application

                    +You can edit the existing ports or declare new ones by specifying:

                    • Application port: this is the port exposed internally by your application for the other services.
                    • Protocol: you can select the protocol used by your application : HTTP (for both standard HTTP or websocket communications), gRPC, TCP, UDP.
                    • Publicly exposed: it allows you to expose over the public network your service. A public domain will be assigned to your application during the deployment (see Connectin from the internet section)
                    • If Publicly Exposed is selected:
                      • External port: it is the port that can be used to access this service over the internet (when exposed publicly). Note that for HTTP and gRPC the port is set by default to 443.
                      • Port Name: it is the name assigned to the port. When multiple ports are exposed publicly, its value is used to route the traffic to the right port based on the called subdomain (which will contain the port name value). Since each port is exposed on the port 443, having a different subdomain is the only way to have multiple ports exposed over the internet. If not set, the default value is p<portNumber> (see Qovery Provided Domain section for more information)

                    Application Ports

                    Important Informations

                    • Most of the Kubernetes Health Checks]docs.using-qovery.configuration.service-health-checks are based on the port declared in this section. Make sure you declare the right port and that you configure the health checks properly.
                    • Connections on public ports are automatically closed after 60 seconds. If you want to implement long living connection (like for websockets) please make sure to use the rigth ingress timeouts in the advanced settings section
                    • Exposing publicly TCP/UDP ports requires to create a dedicated load balancer and it takes a few minutes before having it ready (~15 minutes). Note also that this has a direct impact on your cloud provider bill.
                    • You can configure your application to use the PORT environment variable by adding the PORT on your application env variables page.
                    • A Note on Listening IPs: It's best for your application to listen on 0.0.0.0:$PORT. While most things work with 127.0.0.1 and localhost, some do not (NodeJS for example)

                    Health Checks

                    To know more about how to configure your Liveness and Readiness probes, have a look at the health-checks section

                    Domains

                    Within this section you can customize the domain used to reach your application.

                    You can customize the domain of your application in different ways, depending on what you want to achieve:

                    • You want to use your own domain for your application
                    • You want to modify the subdomain assigned to your application by Qovery (i.e. change p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh into my-app-domain.za8ad0657.bool.sh).

                    In both cases, you can assign the new custom domain to your application press the Add Domain button.

                    Application Domains

                    Configuring your own domain

                    Once the domain is added within the Qovery console (Example: mydomain.com), you need to configure within your DNS two CNAME records pointing to the domain provided by Qovery, as shown in the UI (example: mydomain.com CNAME za7cc1b71-z4b8474b3-gtw.zc531a994.rustrocks.cloud and *.mydomain.com CNAME za7cc1b71-z4b8474b3-gtw.zc531a994.rustrocks.cloud).

                    Having a wildcard domain (example: *.mydomain.com) configured on your DNS will avoid you to modify the Qovery setup every time you want to add a new subdomain. If wildcard is not supported by your DNS provider, you will have to configure each subdomain manually.

                    If the service needs to expose more than one port publicly, you can define a dedicated subdomain to redirect the traffic on the right port by setting the “Port Name” value within the port settings.

                    From this point, Qovery will automatically handle the TLS/SSL certificate creation and renewal for the configured domain.

                    Custom Domain

                    Special case - CDN in proxy mode

                    If your service is behind a CDN using a proxy mode (i.e. the traffic is routed through the CDN to Qovery), make sure to disable the option "Generate certificate" on the domain setup. Since the certificate of your domain is directly managed by the CDN, Qovery won't be able to do that for you and it will raise warnings on your application status.

                    CDN Proxy

                    Change the auto assigned sub-domain

                    You can specify a different sub-domain for your application as long as it belongs to the assigned cluster domain (see Qovery provided domains). +Example:

                    • your current domain is zdf72de71-z709e1a85-gtw.za8ad0659.bool.sh (so your assigned cluster domain is za8ad0659.bool.sh)
                    • you can enter a new custom domain myfrontend.za8ad0659.bool.sh (since it is a subdomain of the cluster domain)

                    The application will now be accessible from both the default and the new custom domain.

                    Connecting from the internet

                    Your application can be reached from the internet by publicly exposing at least one of its ports (See the Ports section to know more). Once this is done, Qovery will generate for you a domain to reach your application from the internet. You can also customize the domain assigned to your application and manage by yourself this assignment via the Domain section.

                    Qovery provided domains

                    For each port publicly exposed, a domain is automatically assigned by Qovery to your application. Qovery will manage for you the networking and the TLS configuration for these domains.

                    Example: p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh or <service_name>-p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh for helm services.

                    Note:

                    • each service deployed on the same cluster will have the same root domain assigned (example: za8ad0657.bool.sh)
                    • the first characters of the domain (before the -) is based on the portName given to the port associated with this domain (See the port section)
                    • a default domain (without the portName) is assigned to the default port(See the port section). Example zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh

                    Special Case - Preview Environment +For each port exposed publicly, an additional domain will be created with the following pattern portName-prId-srvName-envSourceName.cluster_domain:

                    • portName: is the port name, as explained above
                    • prID: is the id of the PR that has generated the preview environment
                    • srvName: is the name of the service
                    • envSourceName: is the name of the blueprint environment that has created the current preview environment

                    domain example: p80-123-frontend-blueprint.za8ad0657.bool.sh

                    Custom domains

                    If you prefer to assign your own domain to the application, have a look at the Domain section to know more.

                    Connecting to a database

                    To know how to access your database from your application, have a look at the database section.

                    Connecting to another application

                    To know how to access your database from your application, have a look at the database section.

                    Environment Variable

                    To learn how to set up environment variables in your projects and applications, navigate to configuring Environment Variables section.

                    Secrets

                    To learn how to set up secrets in your projects and applications, navigate to configuring Secrets section.

                    Logs

                    To learn how to display your application logs, navigate to logs section

                    SSH

                    To connect to your application via SSH, please use the via the Qovery SSH command available on our CLI.

                    Clone

                    You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment.

                    Clone Service

                    The target environment can be the same as the current environment or even another one in a completely different project.

                    Important information

                    Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:

                    • same environment:
                      • custom domain: this setup is not copied into the new service (to avoid collision)
                    • another environment:
                      • custom domain: this setup is not copied into the new service (to avoid collision)
                      • environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)
                      • deployment pipeline: stage setup is not copied (since the target stage might not exist)
                      • number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)

                    Please check the configuration of the new service before deploying it.

                    Delete an Application

                    1. Choose your application

                    2. In the application overview, click on the 3 dots button and remove the application.

                      Application

                    - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/index.html b/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/index.html index 1373b72263..0a19cbd708 100644 --- a/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/index.html +++ b/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services/index.html @@ -21,61 +21,61 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                    -

                    Amazon Web Services (AWS)

                    Qovery lets you quickly deploy applications to your Amazon Web Services (AWS) account. No knowledge needed, and it takes less than 20 minutes to install Qovery on your AWS account.

                    Getting started

                    Connect your AWS account

                    To link your AWS account to Qovery you need to provide an AWS access key id and secret access key with the required IAM permissions.

                    Create your AWS credentials - access key id and secret access key

                    1. Connect to your AWS console

                    2. Go to IAM

                    3. Create Admins group without any permissions

                    4. Create one IAM user called qovery.

                    5. Setup IAM permissions to the qovery user.

                      Then, follow the arrows in AWS console to create AWS credentials with required IAM permissions:

                    6. To create an access key id and secret access key, go to the Security Credentials tab of the Qovery user and press Create access key

                      You can now save the access key id and secret access key

                    Well done!! You now have your AWS access key id and secret access key and your permissions are setups; It is time to connect Qovery to your AWS account.

                    Install a new cluster on Qovery

                    You will be able to use the credentials you just generated when creating a cluster via the Qovery console. This cluster will be linked to your Qovery organization. +

                    Amazon Web Services (AWS)

                    Qovery lets you quickly deploy applications to your Amazon Web Services (AWS) account. No knowledge needed, and it takes less than 20 minutes to install Qovery on your AWS account.

                    Getting started

                    Connect your AWS account

                    To link your AWS account to Qovery you need to provide an AWS access key id and secret access key with the required IAM permissions.

                    Create your AWS credentials - access key id and secret access key

                    1. Connect to your AWS console

                    2. Go to IAM

                    3. Create Admins group without any permissions

                    4. Create one IAM user called qovery.

                    5. Setup IAM permissions to the qovery user.

                      Then, follow the arrows in AWS console to create AWS credentials with required IAM permissions:

                    6. To create an access key id and secret access key, go to the Security Credentials tab of the Qovery user and press Create access key

                      You can now save the access key id and secret access key

                    Well done!! You now have your AWS access key id and secret access key and your permissions are setups; It is time to connect Qovery to your AWS account.

                    Install a new cluster on Qovery

                    You will be able to use the credentials you just generated when creating a cluster via the Qovery console. This cluster will be linked to your Qovery organization. Follow this documentation to create a new cluster on your organization.

                    Deployed AWS components

                    Network ServicesOptionalDescription
                    A dedicated multi AZ VPCnoEverything Qovery will deploy, will be deployed inside this VPC
                    Subnets, routing tables, subnet groups and security groups for RDS (multi AZ)noDedicated network fand security rules for RDS
                    Subnets, routing tables, subnet groups and security groups for DocumentDB (multi AZ)noDedicated network fand security rules for DocumentDB
                    Subnets, routing tables, subnet groups and security groups for Elasticache (multi AZ)noDedicated network fand security rules for Elasticache
                    An internet gateway for the VPCnoRequired to let containers having access to Internet
                    Dedicated NLB to redirect 443 traffic to Nginx IngressnoHigh Availability network load balancer, pointing to Nginx Ingress inside EKS
                    NAT gateways (multi AZ) + EIP addresses (multi AZ) + subnet groups + routing tableyesUseful to get outgoing static IP
                    Dedicated VPC routes for VPC peeringyesUseful to perform VPC peering with others VPC on the same or different account
                    Kubernetes ServicesOptionalDescription
                    A dedicated EKS cluster (multi AZ) for this VPCnoDedicated Kubernetes cluster managed by AWS with nodes (instances type) defined by the customer
                    IAM dedicated user for AWS EBS CSI to access EC2 volumes + a dedicated policynoRequired to allow EKS cluster having access to volume and mount them to containers
                    IAM dedicated user for AWS IAM User Sync + a dedicated policynoRequired to sync desired IAM account to EKS to let them connect directly ot Kubernetes
                    IAM dedicated user for a Cluster Autoscaler+ a dedicated policynoRequired to let autoscaler having access to EC2 autoscaling groups
                    IAM dedicated policies for AWS EKS CNI, EC2 container registry + EKS worker nodesnoRequired to let EKS having access to container registry and configure the Kubernetes network
                    Security group for EKS remote access (dual authentication: TLS + IAM authenticator)noRequired to have a secure remote access on the Kubernetes cluster
                    Security group for 443 port pointing to Nginx ingress inside EKSnoExternal access to web services inside the Kubernetes cluster
                    Other ServicesOptionalDescription
                    Cloudwatch log groups for the EKS clusternoKubernetes logs, useful for the AWS and EKS support to diagnose an issue
                    Dedicated S3 bucket for application's logs + a dedicated IAM accountnoApplication's logs are stored in an KMS encrypted S3 pivate bucket
                    Dedicated S3 bucket to store the kubeconfignoKubernetes Kubeconfig is stored in an KMS encrypted, private and versionned bucket, used by Qovery for application's deployment

                    Remove Qovery from your AWS account

                    To delete Qovery from your AWS account you must be the owner of the Qovery Organization and you have to delete everything in this order:

                    • Environments
                    • Clusters

                    IAM permissions

                    Qovery required IAM permissions to create, update and managed the infrastructure.

                    • IAM is used to create IAM roles
                    • S3 is used to store our generated configuration files
                    • Cloudwatch, for creating a group stream for each Kubernetes clusters
                    • Autoscaling for RDS and autoscaling rules for the Kubernetes cluster
                    • Elastic load-balancing for ELB / ALB / NLB.
                    • DynamoDB to have a distributed lock on infrastructure deployment.
                    • ECR for managing the container registry, create/update/delete repository.
                    • KMS to load and store keys (RDS, SSH, …)
                    • EKS to create and update the Kubernetes cluster.
                    Minimum IAM permission set
                    Last update: 2023-06-08

                    Below you can find the minimum permission set required by Qovery to run and deploy your applications.

                    Policies lengths are limited regarding which object they’re attached to but the one Qovery needs represent more than the maximum (~6000 characters).

                    In order to setup it up, you need to create two IAM groups, each one with one of the following policies.

                    Then we must create a user added to each of the previously created groups.

                    Once it’s done, the user’s access key and secret key can be used in Qovery.

                    {
                    "Version": "2012-10-17",
                    "Statement": [
                    {
                    "Effect": "Allow",
                    "Action": [
                    "autoscaling:SuspendProcesses",
                    "ec2:AllocateAddress",
                    "ec2:AssociateAddress",
                    "ec2:AssociateRouteTable",
                    "ec2:AttachVolume",
                    "ec2:AttachInternetGateway",
                    "ec2:AuthorizeSecurityGroupEgress",
                    "ec2:AuthorizeSecurityGroupIngress",
                    "ec2:CreateInternetGateway",
                    "ec2:CreateKeyPair",
                    "ec2:CreateLaunchTemplate",
                    "ec2:CreateLaunchTemplateVersion",
                    "ec2:CreateNatGateway",
                    "ec2:CreateRoute",
                    "ec2:CreateRouteTable",
                    "ec2:CreateSecurityGroup",
                    "ec2:CreateSubnet",
                    "ec2:CreateTags",
                    "ec2:CreateVolume",
                    "ec2:CreateVpc",
                    "ec2:DeleteInternetGateway",
                    "ec2:DeleteKeyPair",
                    "ec2:DeleteLaunchTemplate",
                    "ec2:DeleteNatGateway",
                    "ec2:DeleteRouteTable",
                    "ec2:DeleteSecurityGroup",
                    "ec2:DeleteSubnet",
                    "ec2:DeleteVolume",
                    "ec2:DeleteVpc",
                    "ec2:DescribeAddresses",
                    "ec2:DescribeAvailabilityZones",
                    "ec2:DescribeImages",
                    "ec2:DescribeInstanceAttribute",
                    "ec2:DescribeInstanceCreditSpecifications",
                    "ec2:DescribeInstances",
                    "ec2:DescribeInstanceTypes",
                    "ec2:DescribeInternetGateways",
                    "ec2:DescribeKeyPairs",
                    "ec2:DescribeLaunchTemplateVersions",
                    "ec2:DescribeLaunchTemplates",
                    "ec2:DescribeNatGateways",
                    "ec2:DescribeNetworkAcls",
                    "ec2:DescribeNetworkInterfaces",
                    "ec2:DescribeRouteTables",
                    "ec2:DescribeSecurityGroupRules",
                    "ec2:DescribeSecurityGroups",
                    "ec2:DescribeSubnets",
                    "ec2:DescribeTags",
                    "ec2:DescribeVolumes",
                    "ec2:DescribeVpcAttribute",
                    "ec2:DescribeVpcClassicLink",
                    "ec2:DescribeVpcClassicLinkDnsSupport",
                    "ec2:DescribeVpcs",
                    "ec2:DetachInternetGateway",
                    "ec2:DetachVolume",
                    "ec2:DisassociateAddress",
                    "ec2:DisassociateRouteTable",
                    "ec2:ImportKeyPair",
                    "ec2:ModifySubnetAttribute",
                    "ec2:ModifyVpcAttribute",
                    "ec2:ReleaseAddress",
                    "ec2:RevokeSecurityGroupEgress",
                    "ec2:RevokeSecurityGroupIngress",
                    "ec2:RunInstances",
                    "ec2:StopInstances",
                    "ec2:TerminateInstances",
                    "ecr:BatchCheckLayerAvailability",
                    "ecr:BatchGetImage",
                    "ecr:CompleteLayerUpload",
                    "ecr:CreateRepository",
                    "ecr:DeleteRepository",
                    "ecr:DescribeImages",
                    "ecr:DescribeRepositories",
                    "ecr:GetAuthorizationToken",
                    "ecr:GetDownloadUrlForLayer",
                    "ecr:InitiateLayerUpload",
                    "ecr:PutImage",
                    "ecr:PutLifecyclePolicy",
                    "ecr:TagResource",
                    "ecr:UploadLayerPart",
                    "eks:CreateAddon",
                    "eks:CreateCluster",
                    "eks:CreateNodegroup",
                    "eks:DeleteAddon",
                    "eks:DeleteCluster",
                    "eks:DeleteNodegroup",
                    "eks:DescribeAddon",
                    "eks:DescribeCluster",
                    "eks:DescribeNodegroup",
                    "eks:DescribeUpdate",
                    "eks:ListClusters",
                    "eks:ListNodegroups",
                    "eks:TagResource",
                    "eks:UpdateAddon",
                    "eks:UpdateClusterConfig",
                    "eks:UpdateClusterVersion",
                    "eks:UpdateNodegroupConfig",
                    "eks:UpdateNodegroupVersion",
                    "elasticache:AddTagsToResource",
                    "elasticache:CreateCacheSubnetGroup",
                    "elasticache:CreateReplicationGroup",
                    "elasticache:DeleteCacheSubnetGroup",
                    "elasticache:DeleteReplicationGroup",
                    "elasticache:DescribeCacheClusters",
                    "elasticache:DescribeCacheSubnetGroups",
                    "elasticache:DescribeReplicationGroups",
                    "elasticache:ListTagsForResource",
                    "elasticloadbalancing:DescribeLoadBalancers",
                    "elasticloadbalancing:DescribeTags"
                    ],
                    "Resource": "*"
                    }
                    ]
                    }
                    {
                    "Version": "2012-10-17",
                    "Statement": [
                    {
                    "Effect": "Allow",
                    "Action": [
                    "iam:AddRoleToInstanceProfile",
                    "iam:AttachRolePolicy",
                    "iam:AttachUserPolicy",
                    "iam:CreateAccessKey",
                    "iam:CreateInstanceProfile",
                    "iam:CreateOpenIDConnectProvider",
                    "iam:CreatePolicy",
                    "iam:CreateRole",
                    "iam:CreateServiceLinkedRole",
                    "iam:CreateUser",
                    "iam:DeleteAccessKey",
                    "iam:DeleteInstanceProfile",
                    "iam:DeleteOpenIDConnectProvider",
                    "iam:DeletePolicy",
                    "iam:DeleteRole",
                    "iam:DeleteRolePolicy",
                    "iam:DeleteUser",
                    "iam:DeleteUserPolicy",
                    "iam:DetachRolePolicy",
                    "iam:DetachUserPolicy",
                    "iam:GetInstanceProfile",
                    "iam:GetOpenIDConnectProvider",
                    "iam:GetPolicy",
                    "iam:GetPolicyVersion",
                    "iam:GetRole",
                    "iam:GetRolePolicy",
                    "iam:GetUser",
                    "iam:GetUserPolicy",
                    "iam:ListAccessKeys",
                    "iam:ListAttachedRolePolicies",
                    "iam:ListAttachedUserPolicies",
                    "iam:ListGroupsForUser",
                    "iam:ListInstanceProfilesForRole",
                    "iam:ListPolicyVersions",
                    "iam:ListRolePolicies",
                    "iam:PassRole",
                    "iam:PutRolePolicy",
                    "iam:PutUserPolicy",
                    "iam:RemoveRoleFromInstanceProfile",
                    "iam:TagInstanceProfile",
                    "iam:TagOpenIDConnectProvider",
                    "iam:TagRole",
                    "iam:TagUser",
                    "kms:CreateGrant",
                    "kms:CreateKey",
                    "kms:Decrypt",
                    "kms:DescribeKey",
                    "kms:GenerateDataKey",
                    "kms:GetKeyPolicy",
                    "kms:GetKeyRotationStatus",
                    "kms:ListResourceTags",
                    "kms:PutKeyPolicy",
                    "kms:ScheduleKeyDeletion",
                    "kms:TagResource",
                    "logs:CreateLogGroup",
                    "logs:DeleteLogGroup",
                    "logs:DescribeLogGroups",
                    "logs:ListTagsLogGroup",
                    "logs:PutRetentionPolicy",
                    "logs:TagLogGroup",
                    "rds:AddTagsToResource",
                    "rds:CreateDBCluster",
                    "rds:CreateDBInstance",
                    "rds:CreateDBParameterGroup",
                    "rds:CreateDBSubnetGroup",
                    "rds:DeleteDBCluster",
                    "rds:DeleteDBInstance",
                    "rds:DeleteDBParameterGroup",
                    "rds:DeleteDBSubnetGroup",
                    "rds:DescribeDBClusters",
                    "rds:DescribeDBInstances",
                    "rds:DescribeDBParameterGroups",
                    "rds:DescribeDBParameters",
                    "rds:DescribeDBSubnetGroups",
                    "rds:DescribeGlobalClusters",
                    "rds:ListTagsForResource",
                    "rds:ModifyDBInstance",
                    "rds:ModifyDBParameterGroup",
                    "rds:StartDBCluster",
                    "rds:StartDBInstance",
                    "rds:StopDBCluster",
                    "rds:StopDBInstance",
                    "s3:CreateBucket",
                    "s3:DeleteBucket",
                    "s3:DeleteObject",
                    "s3:DeleteObjectVersion",
                    "s3:DeleteBucketPolicy",
                    "s3:GetAccelerateConfiguration",
                    "s3:GetBucketAcl",
                    "s3:GetBucketCORS",
                    "s3:GetBucketLogging",
                    "s3:GetBucketObjectLockConfiguration",
                    "s3:GetBucketOwnershipControls",
                    "s3:GetBucketPolicy",
                    "s3:GetBucketPublicAccessBlock",
                    "s3:GetBucketRequestPayment",
                    "s3:GetBucketTagging",
                    "s3:GetBucketVersioning",
                    "s3:GetBucketWebsite",
                    "s3:GetEncryptionConfiguration",
                    "s3:GetLifecycleConfiguration",
                    "s3:GetObject",
                    "s3:GetReplicationConfiguration",
                    "s3:ListAccessPoints",
                    "s3:ListAllMyBuckets",
                    "s3:ListBucket",
                    "s3:ListBucketMultipartUploads",
                    "s3:ListBucketVersions",
                    "s3:ListMultiRegionAccessPoints",
                    "s3:ListMultipartUploadParts",
                    "s3:ListStorageLensConfigurations",
                    "s3:PutBucketAcl",
                    "s3:PutBucketOwnershipControls",
                    "s3:PutBucketPolicy",
                    "s3:PutBucketPublicAccessBlock",
                    "s3:PutBucketTagging",
                    "s3:PutBucketVersioning",
                    "s3:PutEncryptionConfiguration",
                    "s3:PutLifecycleConfiguration",
                    "s3:PutObject",
                    "s3:PutObjectRetention",
                    "secretsmanager:CreateSecret",
                    "secretsmanager:TagResource",
                    "sts:GetCallerIdentity"
                    ],
                    "Resource": "*"
                    }
                    ]
                    }

                    Regions

                    Qovery supports the following AWS regions:

                    namedescriptionsupported
                    🇺🇸us-west-2US West (Oregon)Yes
                    🇺🇸us-east-2US East (Ohio)Yes
                    🇺🇸us-east-1US East (N. Virginia)Yes
                    🇺🇸us-west-1US West (N. California)No (Only 2 Availability Zone)
                    🇿🇦af-south-1Africa (Cape Town)Yes
                    🇭🇰ap-east-1Asia Pacific (Hong Kong)Yes
                    🇮🇳ap-south-1Asia Pacific (Mumbai)Yes
                    🇯🇵ap-northeast-1Asia Pacific (Tokyo)Yes
                    🇰🇷ap-northeast-2Asia Pacific (Seoul)Yes
                    🇯🇵ap-northeast-3Asia Pacific (Osaka)Yes
                    🇸🇬ap-southeast-1Asia Pacific (Singapore)Yes
                    🇦🇺ap-southeast-2Asia Pacific (Sydney)Yes
                    🇨🇦ca-central-1Canada (Toronto)Yes
                    🇨🇳cn-north-1China (Beijing)Yes
                    🇨🇳cn-northwest-1China (Ningxia)Yes
                    🇩🇪eu-central-1Europe (Frankfurt)Yes
                    🇮🇪eu-west-1Europe (Ireland)Yes
                    🏴󠁧󠁢󠁥󠁮󠁧󠁿eu-west-2Europe (London)Yes
                    🇫🇷eu-west-3Europe (Paris)Yes
                    🇮🇹eu-south-1Europe (Milan)Yes
                    🇸🇪eu-north-1Europe (Stockholm)Yes
                    🇧🇭me-south-1Middle East (Bahrain)Yes
                    🇧🇷sa-east-1South America (São Paulo)Yes

                    Qovery supports regions where Amazon EKS is supported.

                    Manually configure VPC subnet

                    VPC subnet is automatically defined by Qovery on cluster creation. However, you may want to choose your own VPC subnet, for example to perform VPC Peering.

                    Have a look at [this section][docs.using-qovery.configuration.clusters#custom-vpc-subnet]] to know more on how to set the VPC Subnet.

                    Configure routing table

                    You may want to create and edit a network routing table to perform VPC peering. This can be done by accessing to the parameters of a cluster, in the settings of your organization.

                    Have a look at [this section][docs.using-qovery.configuration.clusters#network]] to know more on how to set the routing table.

                    How Qovery works on AWS

                    Qovery is an abstraction layer on top of AWS and Kubernetes. Qovery manages the configuration of AWS account, and helps you to deploy production ready apps in seconds. To make it works, Qovery rely on Kubernetes for stateless apps (containers), and AWS for stateful apps (databases, storage...).

                    Read more on how Qovery works behind the scene.

                    Kubernetes

                    The first time you set up your AWS account, Qovery creates a Kubernetes cluster in your chosen region. Qovery managed it for you - no action required. It takes ~15 minutes to configure and bootstrap a Kubernetes cluster. Once bootstrapped, your Kubernetes cluster runs the Qovery app and is ready to deploy your applications.

                    Managed services

                    AWS provides managed services for PostgreSQL, MySQL, Redis, MongoDB. Qovery gives you access to those services when you set the environment mode to Production. In Development mode, Qovery provides containers equivalent, which is cheaper and faster to start.

                    Security and compliance

                    Qovery runs your Kubernetes cluster and is autonomous to manage your applications, which means:

                    • Your configuration are stored on your AWS account.
                    • Your configuration is encrypted on your AWS account.
                    • Qovery can't access to your data.
                    • Suppose Qovery stops to run, your applications are not impacted.

                    FAQ

                    How to choose a region?

                    Different datacenters are located in different geographic areas, and you may want to keep your site physically close to the bulk of your user base for reduced latency.

                    I don't find a region that is provided by AWS

                    We are probably testing the support of this region, please contact us to know what's the status

                    Migrate between Cloud providers and regions

                    Today, you can't migrate an environment from one region to another after it has been created. Vote here if you need this feature.

                    - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/cloud-service-provider/digital-ocean/index.html b/docs/using-qovery/configuration/cloud-service-provider/digital-ocean/index.html index af4c84dbd3..6096b41cbd 100644 --- a/docs/using-qovery/configuration/cloud-service-provider/digital-ocean/index.html +++ b/docs/using-qovery/configuration/cloud-service-provider/digital-ocean/index.html @@ -21,30 +21,30 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                    Digital Ocean (DO)

                    Resources
                      - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform/index.html b/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform/index.html index aacf8963e3..a705e181d7 100644 --- a/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform/index.html +++ b/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                      -
                      +
                      - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/cloud-service-provider/index.html b/docs/using-qovery/configuration/cloud-service-provider/index.html index 264b957e21..9b2ec377bb 100644 --- a/docs/using-qovery/configuration/cloud-service-provider/index.html +++ b/docs/using-qovery/configuration/cloud-service-provider/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                      -
                      +
                      - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure/index.html b/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure/index.html index de9740b1c2..05095c8a4f 100644 --- a/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure/index.html +++ b/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                      -
                      +
                      - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/cloud-service-provider/other-csps/index.html b/docs/using-qovery/configuration/cloud-service-provider/other-csps/index.html index 8887252d60..0ee666b6bf 100644 --- a/docs/using-qovery/configuration/cloud-service-provider/other-csps/index.html +++ b/docs/using-qovery/configuration/cloud-service-provider/other-csps/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                      -
                      Resources
                        +
                        Resources
                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/cloud-service-provider/scaleway/index.html b/docs/using-qovery/configuration/cloud-service-provider/scaleway/index.html index 8d4c9c8145..863a592a6d 100644 --- a/docs/using-qovery/configuration/cloud-service-provider/scaleway/index.html +++ b/docs/using-qovery/configuration/cloud-service-provider/scaleway/index.html @@ -21,63 +21,63 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Scaleway (SCW)

                          Qovery lets you quickly deploy applications to your Scaleway (Scaleway) account. No knowledge needed, and it takes less than 10 minutes to install Qovery on your Scaleway account.

                          Getting started

                          Connect your Scaleway account

                          To link your Scaleway account to Qovery you need to provide a Scaleway access key id, secret access key, organization id and a project id.

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/cluster-advanced-settings/index.html b/docs/using-qovery/configuration/cluster-advanced-settings/index.html index 5086b3f7e1..0230cc2167 100644 --- a/docs/using-qovery/configuration/cluster-advanced-settings/index.html +++ b/docs/using-qovery/configuration/cluster-advanced-settings/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Cluster Advanced Settings

                          To further fine-tune your Qovery infrastructure, you can set advanced settings through the Qovery API endpoint.

                          All clusters have access to advanced settings, you can find where they are available in the documentation below with those badges mentioning for which Cloud provider they are available:

                          You will also find badges mentioning for which components it will be applied:

                          Below is the list of advanced settings currently available for clusters.

                          Logs

                          aws.cloudwatch.eks_logs_retention_days

                          TypeDescriptionDefault Value
                          integerMaximum retention days in Cloudwatch for EKS logs.
                          (possible values: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 2192, 2557, 2922, 3288, 3653)
                          90

                          aws.vpc.enable_s3_flow_logs

                          TypeDescriptionDefault Value
                          booleanEnable flow logs on the cluster VPC and store them in an s3 bucket.false

                          aws.vpc.flow_logs_retention_days

                          TypeDescriptionDefault Value
                          integerSet the number of retention days for flow logs. Unlimited retention with value 0365

                          loki.log_retention_in_week

                          TypeDescriptionDefault Value
                          integerMaximum Kubernetes pods (containers/application/jobs/cronjob) retention logs in weeks.12 (84 days)

                          Image registry

                          registry.image_retention_time

                          TypeDescriptionDefault Value
                          integerAllows you to specify an amount in seconds after which images in the default registry are deleted.31536000 (1 year)

                          registry.mirroring_mode

                          TypeDescriptionDefault Value
                          stringAllows you to specify the image mirroring mode to be used for each image deployed on this cluster. (possible values: Service or Cluster)Service

                          cloud_provider.container_registry.tags

                          TypeDescriptionDefault Value
                          Map<String, String>Add additional tags on the cluster dedicated registry

                          Network

                          Load balancer

                          load_balancer.size

                          TypeDescriptionDefault Value
                          stringAllows you to specify the load balancer size in front of your cluster. Possible values are:
                          - lb-s: 200 Mbps
                          - lb-gp-m: 500 Mbps
                          - lb-gp-l: 1 Gbps
                          - lb-gp-xl: 4 Gbps
                          lb-s

                          Nginx

                          nginx.vcpu.request_in_milli_cpu

                          TypeDescriptionDefault Value
                          integerVcpu request value in millicores assigned to Nginx pods200

                          nginx.vcpu.limit_in_milli_cpu

                          TypeDescriptionDefault Value
                          integerVcpu limit value in millicores assigned to Nginx pods700

                          nginx.memory.request_in_mib

                          TypeDescriptionDefault Value
                          integerMemory limit value in MiB assigned to Nginx pods768

                          nginx.memory.limit_in_mib

                          TypeDescriptionDefault Value
                          integerMemory limit value in MiB assigned to Nginx pods768

                          nginx.hpa.cpu_utilization_percentage_threshold

                          TypeDescriptionDefault Value
                          integerHpa (horizontal pod autoscaler) cpu threshold in percentage assigned to Nginx deployment50

                          nginx.hpa.min_number_instances

                          TypeDescriptionDefault Value
                          integerMinimum number of Nginx instances running2

                          nginx.hpa.max_number_instances

                          TypeDescriptionDefault Value
                          integerMaximum number of Nginx instances running25

                          Database access

                          database.postgresql.deny_public_access

                          TypeDescriptionDefault Value
                          booleanDeny public access to all PostgreSQL databases. When true, configure the CIDR range you want to allow within the associated allowed_cidrs parameter (default is "any IP").
                          ⚠️ Public access to managed databases will instantly be removed
                          ⚠️ Public access to container databases will be removed only after a database redeployment
                          false

                          database.postgresql.allowed_cidrs

                          TypeDescriptionDefault Value
                          booleanList of allowed CIDRS. Valid only when database.postgresql.deny_public_access is set to true["0.0.0.0/0"]

                          database.mysql.deny_public_access

                          TypeDescriptionDefault Value
                          booleanDeny public access to all MySQL databases. When true, configure the CIDR range you want to allow within the associated allowed_cidrs parameter (default is "any IP").
                          ⚠️ Public access to managed databases will instantly be removed
                          ⚠️ Public access to container databases will be removed only after a database redeployment
                          false

                          database.mysql.allowed_cidrs

                          TypeDescriptionDefault Value
                          booleanList of allowed CIDRS. Valid only when database.mysql.deny_public_access is set to true["0.0.0.0/0"]

                          database.mongodb.deny_public_access

                          TypeDescriptionDefault Value
                          booleanDeny public access to all MongoDB databases. When true, configure the CIDR range you want to allow within the associated allowed_cidrs parameter (default is "any IP").
                          ⚠️ Public access to managed databases will instantly be removed
                          ⚠️ Public access to container databases will be removed only after a database redeployment
                          false

                          database.mongodb.allowed_cidrs

                          TypeDescriptionDefault Value
                          booleanList of allowed CIDRS. Valid only when database.mongodb.deny_public_access is set to true["0.0.0.0/0"]

                          database.redis.deny_public_access

                          TypeDescriptionDefault Value
                          booleanDeny public access to all Redis databases. When true, configure the CIDR range you want to allow within the associated allowed_cidrs parameter (default is "anyone").
                          ⚠️ Public access to managed databases will instantly be removed
                          ⚠️ Public access to container databases will be removed only after a database redeployment
                          false

                          database.redis.allowed_cidrs

                          TypeDescriptionDefault Value
                          booleanList of allowed CIDRS. Valid only when database.redis.deny_public_access is set to true["0.0.0.0/0"]

                          IAM

                          aws.iam.enable_admin_group_sync

                          TypeDescriptionDefault Value
                          booleanEnable IAM admin group sync IAM permissions setup.
                          ⚠️ aws.iam.admin_group should be set.
                          true

                          aws.iam.admin_group

                          TypeDescriptionDefault Value
                          stringAllows you to specify the IAM group name associated with the Qovery user in the AWS console during the IAM permissions setup to be able to connect to the Kubernetes clusterAdmins

                          aws.iam.enable_sso

                          TypeDescriptionDefault Value
                          booleanEnable SSO sync allowing IAM users to connect to cluster using SSO. Setup SSO support for your cluster.
                          ⚠️ aws.iam.sso_role_arn should be set.
                          false

                          aws.iam.sso_role_arn

                          TypeDescriptionDefault Value
                          stringAllows you to specify the SSO role ARN to be used to connect to your cluster. Setup SSO support for your cluster""

                          Miscellaneous

                          aws.eks.ec2.metadata_imds

                          TypeDescriptionDefault Value
                          stringSpecify the IMDS version you want to use. Possible values are required (IMDS v2 only) and optional (IMDS v1 and V2)optional
                          +

                          Cluster Advanced Settings

                          To further fine-tune your Qovery infrastructure, you can set advanced settings through the Qovery API endpoint.

                          All clusters have access to advanced settings, you can find where they are available in the documentation below with those badges mentioning for which Cloud provider they are available:

                          You will also find badges mentioning for which components it will be applied:

                          Below is the list of advanced settings currently available for clusters.

                          Logs

                          aws.cloudwatch.eks_logs_retention_days

                          TypeDescriptionDefault Value
                          integerMaximum retention days in Cloudwatch for EKS logs.
                          (possible values: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 2192, 2557, 2922, 3288, 3653)
                          90

                          aws.vpc.enable_s3_flow_logs

                          TypeDescriptionDefault Value
                          booleanEnable flow logs on the cluster VPC and store them in an s3 bucket.false

                          aws.vpc.flow_logs_retention_days

                          TypeDescriptionDefault Value
                          integerSet the number of retention days for flow logs. Unlimited retention with value 0365

                          loki.log_retention_in_week

                          TypeDescriptionDefault Value
                          integerMaximum Kubernetes pods (containers/application/jobs/cronjob) retention logs in weeks.12 (84 days)

                          Image registry

                          registry.image_retention_time

                          TypeDescriptionDefault Value
                          integerAllows you to specify an amount in seconds after which images in the default registry are deleted.31536000 (1 year)

                          registry.mirroring_mode

                          TypeDescriptionDefault Value
                          stringAllows you to specify the image mirroring mode to be used for each image deployed on this cluster. (possible values: Service or Cluster)Service

                          cloud_provider.container_registry.tags

                          TypeDescriptionDefault Value
                          Map<String, String>Add additional tags on the cluster dedicated registry

                          Network

                          Load balancer

                          load_balancer.size

                          TypeDescriptionDefault Value
                          stringAllows you to specify the load balancer size in front of your cluster. Possible values are:
                          - lb-s: 200 Mbps
                          - lb-gp-m: 500 Mbps
                          - lb-gp-l: 1 Gbps
                          - lb-gp-xl: 4 Gbps
                          lb-s

                          Nginx

                          nginx.vcpu.request_in_milli_cpu

                          TypeDescriptionDefault Value
                          integerVcpu request value in millicores assigned to Nginx pods200

                          nginx.vcpu.limit_in_milli_cpu

                          TypeDescriptionDefault Value
                          integerVcpu limit value in millicores assigned to Nginx pods700

                          nginx.memory.request_in_mib

                          TypeDescriptionDefault Value
                          integerMemory limit value in MiB assigned to Nginx pods768

                          nginx.memory.limit_in_mib

                          TypeDescriptionDefault Value
                          integerMemory limit value in MiB assigned to Nginx pods768

                          nginx.hpa.cpu_utilization_percentage_threshold

                          TypeDescriptionDefault Value
                          integerHpa (horizontal pod autoscaler) cpu threshold in percentage assigned to Nginx deployment50

                          nginx.hpa.min_number_instances

                          TypeDescriptionDefault Value
                          integerMinimum number of Nginx instances running2

                          nginx.hpa.max_number_instances

                          TypeDescriptionDefault Value
                          integerMaximum number of Nginx instances running25

                          Database access

                          database.postgresql.deny_public_access

                          TypeDescriptionDefault Value
                          booleanDeny public access to all PostgreSQL databases. When true, configure the CIDR range you want to allow within the associated allowed_cidrs parameter (default is "any IP").
                          ⚠️ Public access to managed databases will instantly be removed
                          ⚠️ Public access to container databases will be removed only after a database redeployment
                          false

                          database.postgresql.allowed_cidrs

                          TypeDescriptionDefault Value
                          booleanList of allowed CIDRS. Valid only when database.postgresql.deny_public_access is set to true["0.0.0.0/0"]

                          database.mysql.deny_public_access

                          TypeDescriptionDefault Value
                          booleanDeny public access to all MySQL databases. When true, configure the CIDR range you want to allow within the associated allowed_cidrs parameter (default is "any IP").
                          ⚠️ Public access to managed databases will instantly be removed
                          ⚠️ Public access to container databases will be removed only after a database redeployment
                          false

                          database.mysql.allowed_cidrs

                          TypeDescriptionDefault Value
                          booleanList of allowed CIDRS. Valid only when database.mysql.deny_public_access is set to true["0.0.0.0/0"]

                          database.mongodb.deny_public_access

                          TypeDescriptionDefault Value
                          booleanDeny public access to all MongoDB databases. When true, configure the CIDR range you want to allow within the associated allowed_cidrs parameter (default is "any IP").
                          ⚠️ Public access to managed databases will instantly be removed
                          ⚠️ Public access to container databases will be removed only after a database redeployment
                          false

                          database.mongodb.allowed_cidrs

                          TypeDescriptionDefault Value
                          booleanList of allowed CIDRS. Valid only when database.mongodb.deny_public_access is set to true["0.0.0.0/0"]

                          database.redis.deny_public_access

                          TypeDescriptionDefault Value
                          booleanDeny public access to all Redis databases. When true, configure the CIDR range you want to allow within the associated allowed_cidrs parameter (default is "anyone").
                          ⚠️ Public access to managed databases will instantly be removed
                          ⚠️ Public access to container databases will be removed only after a database redeployment
                          false

                          database.redis.allowed_cidrs

                          TypeDescriptionDefault Value
                          booleanList of allowed CIDRS. Valid only when database.redis.deny_public_access is set to true["0.0.0.0/0"]

                          IAM

                          aws.iam.enable_admin_group_sync

                          TypeDescriptionDefault Value
                          booleanEnable IAM admin group sync IAM permissions setup.
                          ⚠️ aws.iam.admin_group should be set.
                          true

                          aws.iam.admin_group

                          TypeDescriptionDefault Value
                          stringAllows you to specify the IAM group name associated with the Qovery user in the AWS console during the IAM permissions setup to be able to connect to the Kubernetes clusterAdmins

                          aws.iam.enable_sso

                          TypeDescriptionDefault Value
                          booleanEnable SSO sync allowing IAM users to connect to cluster using SSO. Setup SSO support for your cluster.
                          ⚠️ aws.iam.sso_role_arn should be set.
                          false

                          aws.iam.sso_role_arn

                          TypeDescriptionDefault Value
                          stringAllows you to specify the SSO role ARN to be used to connect to your cluster. Setup SSO support for your cluster""

                          Miscellaneous

                          aws.eks.ec2.metadata_imds

                          TypeDescriptionDefault Value
                          stringSpecify the IMDS version you want to use. Possible values are required (IMDS v2 only) and optional (IMDS v1 and V2)optional
                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/clusters/index.html b/docs/using-qovery/configuration/clusters/index.html index 6ac25aea8a..b965cbc177 100644 --- a/docs/using-qovery/configuration/clusters/index.html +++ b/docs/using-qovery/configuration/clusters/index.html @@ -21,36 +21,36 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Clusters

                          This section brings you answers to all the questions our users usually ask about clusters:

                          What is a cluster?

                          At Qovery, when we refer to cluster, we mean Kubernetes cluster. A Kubernetes cluster is a collection of node machines that allows you to run containerized applications. It is usually made up of:

                          • Pods: think of a pod as one instance of your application. Pods are the smallest deployable objects in Kubernetes, and they are hosted by worker nodes.
                          • Worker Nodes: worker nodes essentially run your applications and workloads. When you create a cluster from your Qovery Console, it generates the set up of worker nodes (also called “instances”, “EC2 instances” for AWS users, or “droplets” for DigitalOcean users). +

                            Clusters

                            This section brings you answers to all the questions our users usually ask about clusters:

                            What is a cluster?

                            At Qovery, when we refer to cluster, we mean Kubernetes cluster. A Kubernetes cluster is a collection of node machines that allows you to run containerized applications. It is usually made up of:

                            • Pods: think of a pod as one instance of your application. Pods are the smallest deployable objects in Kubernetes, and they are hosted by worker nodes.
                            • Worker Nodes: worker nodes essentially run your applications and workloads. When you create a cluster from your Qovery Console, it generates the set up of worker nodes (also called “instances”, “EC2 instances” for AWS users, or “droplets” for DigitalOcean users). Qovery allows you to define worker nodes settings, so that you end up deploying the right type of instances on your infrastructure based on your CPU, memory, storage and network performance needs.
                            • a Control Plane (or Master Node): the control plane manages the worker nodes. Since we deploy managed Kubernetes services, the control plane is handled exclusively by your cloud provider, and left untouched by Qovery.

                            Application

                            For more information on Kubernetes clusters, see the Kubernetes documentation.

                            Why do I need a cluster?

                            Qovery is built on top of Kubernetes, which means we need Kubernetes clusters to be able to deploy and run your applications.

                            Thanks to clusters, you can easily deploy several (and many) instances of the same application, so that if one fails, the others can instantly take over. Also, clusters can auto-scale, meaning that the number of worker nodes in a cluster can automatically go up or down as traffic fluctuates on your application(s), thus ensuring high availability and performance. Clusters are also extremely useful to isolate your production environment from your staging environment.

                            In short, through the use of clusters, Kubernetes provides you with a resilient, flexible and powerful infrastructure, fit for production environment needs and requirements. And with the help of Qovery, setting up and maintaining your Kubernetes clusters has never been easier.

                            Qovery allows you to create and manage two types of clusters:

                            Managed K8S BETA - Single EC2 (K3s)
                            DescriptionA multi-node Kubernetes cluster managed by your cloud provider (EKS, Kapsule etc..)K3s Cluster running on a single EC2 instance (single-node) Available only on AWS and still in BETA
                            UsageHosting professional applications in production (resilient, scalable and powerful infrastructure). Scalable staging / preview / dev environmentsHobby projects, trying out Qovery, ephemeral environments deployment
                            Cloud provider costStarting from 200$/month, based on the chosen instance typestarting from 20$/month, based on the chosen instance type


                            What are the different instance types available when creating a cluster?

                            The range of instance types available at cluster creation depends on your cloud provider:

                            What is the default cluster?

                            The default cluster is the first cluster you installed in your organization.

                            When you create a new environment and leave the mode and cluster parameters set to the value Automatic, your environment is deployed to:

                            • the cluster defined in one of your project rules,
                            • or to the default cluster if no project rule applies.

                            For more information on deployment rules, see Project.

                            How does Qovery handle cluster updates and upgrades?

                            As far as cluster updates and upgrades to a newer version of Kubernetes are concerned, our Qovery engineering team handles everything in due time, so you don’t even need to think about it!

                            Usually, we work on a given upgrade for one month of intensive testing on our end in order to make sure everything will be smooth for you. Once we are pretty confident our stack is stable, we move on with the following steps which last approximately 3 weeks:

                            1. Notify users about new version coming in approximatively 1 month before
                            2. Upgrade clusters for a handful of beta-tester customers (1 week)
                            3. Upgrade all non-production flagged clusters (1-2 week(s))
                            4. Upgrade all clusters

                            If, somehow the planning or timeframe for the upgrade is clashing with your business needs, you will be able to contact us so we can arrange the best timeframe for you.

                            What do you do when a vulnerability is found?

                            Security is our main concern. When a vulnerability is found, here are the actions that we take:

                            1. We quickly identify how significant is the impact of the vulnerability.
                            2. We look at how we can solve or mitigate the vulnerability.
                            3. We transparently communicate with our customers about the vulnerability to help them take the right actions.

                            Managing your Clusters with Qovery

                            From the Qovery Console, you can manage the settings of the clusters you want to run on your infrastructure. The clusters are then created (or updated) by the cloud provider that hosts them.

                            Creating a Cluster

                            To create a cluster:

                            1. Open your Qovery Console.

                            2. On the left menu bar, click on the Cluster page:

                              Cluster Access

                            3. Click Add Cluster:

                              Add Cluster Button

                            4. In the Create Cluster window enter:

                              • Cluster name: enter the name of your choice for your cluster.
                              • Description: enter a description to identify better your cluster.
                              • Production cluster: select this option if your cluster will be used for production.
                              • Cloud provider: select your cloud provider.
                              • Region: select the geographical area in which you want your cluster to be hosted.
                              • Credentials: select one of the existing cloud provider credentials or add a new one by clicking on New Credentials. In the New credentials window, add the credentials that you have generated on your cloud provider console (Procedure for AWS account, Procedure for Scaleway account). Added credentials can be used later to create and manage additional cluster.

                              To confirm, click Next.

                            5. In the Set Resources window, select:

                              • Cluster: select the cluster type to use. Please refer to this section for more information.
                              • Instance type: select the type of worker nodes you want to deploy to your cluster:
                              • Disk size: select the size of the disks to be attached to your cluster instances (to locally store container images etc..). Setting available only on AWS.
                              • Node auto-scaling: define the minimum and the maximum number of worker nodes that your cluster can run. The lowest number is the number of worker nodes running on your infrastructure at any time, while the highest number is the maximum number of worker nodes that can automatically be deployed as traffic grows. Please note that a minimum of 3 worker nodes is required to deploy your EKS cluster.


                              To confirm, click Next.

                            6. (Only for AWS K8S Clusters) In the Features window, select the features you want to enable on your cluster.

                            7. (Only for Single EC2 K3S Clusters) In the Set SSH Key window:

                              The SSH key enables you (or Qovery on your behalf) to freely manage your cluster. For information on how to generate an SSH key, see Generating an SSH Key for Your Cluster.

                              You can add an SSH key to your cluster settings later, however it is recommended to do it at cluster creation to avoid downtime.

                            8. In the Ready to install your cluster window, check that the services needed to install your cluster are correct.

                              You can now press the Create and Install button.

                              Your cluster is now displayed in your organization settings, featuring the Installing... status (orange status). Once your cluster is properly installed, its status turns to green and you will be able to deploy your applications on it.

                            Managing your Cluster Settings

                            To manage the settings of an existing cluster:

                            1. Open your Qovery Console.

                            2. On the left menu bar, click on the Cluster page:

                              Cluster Access

                            3. To access your cluster settings, click on the wheel button:

                              Display Cluster Settings

                            Below you can find a description of each section

                            General

                            The General tab allows you to define high-level information on your cluster:

                            ItemDescription
                            Cluster NameTo edit the name of your cluster.
                            DescriptionTo enter or edit the description of your cluster.
                            Production ClusterTo enter or edit the production flag of your cluster.

                            Credentials

                            Here you can manage here the cloud provider credentials associated with your cluster.

                            If you need to change the credentials:

                            In the two dedicated fields, enter the credentials you created on your cloud provider account:

                            Account ProviderField Labels
                            AWSAccess Key and Secret Access Key
                            ScalewayScaleway Access Key and Scaleway Project ID

                            Once created and associated, you need to updating your cluster to apply the change.

                            Resources

                            Qovery allows you to modify the resources allocated for your cluster:

                            • In the Instance type dropdown menu, select the type of worker node(s) you want to deploy to your cluster.
                            • (AWS users only) In the Node disk size (GB) field, enter the disk capacity you want to allocate to your worker node(s) (meaning how much data, in gigabytes, you want each worker node to be able to hold).
                            • (EKS users only) On the Nodes auto-scaling, define the range of worker nodes you want to deploy to your cluster.

                            Features

                            The Features tab in your cluster settings allows you to check if the Static IP and Custom VPC subnet features are enabled on your cluster. The enabled features cannot be changed after the creation of the cluster.

                            Static IP

                            The Static IP feature is currently only available to clusters deployed on AWS and can only be enabled at cluster creation.

                            By default, when your cluster is created, its worker nodes are allocated public IP addresses, which are used for external communication. For improved security and control, the Static IP feature allows you to ensure that outbound traffic from your cluster uses specific IP addresses.

                            Here is what will be deployed on AWS:

                            • Nat Gateways
                            • Elastic IPs
                            • Private subnets

                            Once set up, here is the procedure to find your static IP addresses:

                            • On your AWS account, select the VPC service.
                            • On the left menu, you’ll find Elastic IP addresses. Once on it, in the Allocated IPv4 address column, you’ll have your public IPs.
                            Custom VPC Subnet

                            The VPC feature is currently only available to clusters deployed on AWS and can only be enabled at cluster creation.

                            Virtual Private Cloud (VPC) peering allows you to set up a connection between your Qovery VPC and another VPC on your AWS account. This way, you can access resources stored on your AWS VPC directly from your Qovery applications.

                            A VPC can only be used if it has at least one range of IP addresses called a subnet. When you create a cluster, Qovery automatically picks a default subnet for it. However, to perform VPC peering, you may want to define which specific VPC subnet you want to use, so that you can avoid any conflicting settings. To do so, you can enable the Custom VPC Subnet feature on your cluster. For more information on how to set up VPC peering, see our dedicated tutorial.

                            Network

                            The Network tab in your cluster settings allows you to update your Qovery VPC route table so that you can perform VPC peering. For step-by-step guidelines on how to set up VPC peering, see our dedicated tutorial.

                            Performing Actions on your Clusters

                            Qovery allows you to update, stop, restart or delete your clusters at organization level.

                            ActionDescription
                            Updating a clusterTo redeploy your cluster after a change has been made to it.
                            Stopping a clusterTo temporarily stop your cluster. Some services you have subscribed to via your cloud provider may still be active and incur costs when your cluster is stopped. For more information, see Stopping a cluster.
                            Restarting a clusterTo restart your cluster after it has been temporarily stopped.
                            Deleting a clusterTo delete your cluster. This is final and needs to be done properly to ensure all the services deployed by Qovery on your cloud provider's account are disabled, with no leftover cloud-related costs. For more information, see Deleting a cluster.

                            To access these actions:

                            1. Open your Qovery Console.

                            2. On the left menu bar, click on the Cluster page:

                              Cluster Access

                            3. To view your cluster actions, click Play button:

                              Cluster Actions Menu

                              A dropdown menu unfolds, featuring all the actions available on your cluster.

                            You can follow the execution of the action via the cluster status and/or by accessing the Cluster Logs

                            Updating a Cluster

                            If you made a change on your cluster, you need to run an update on your cluster to propagate remotely the new configuration.

                            To update your cluster, select the action Update from the drop-down menu.

                            A confirmation pop-up window opens before triggering the action.

                            Once confirmed, the status of your cluster turns Updating... (orange status).

                            Once the update is complete, the status dot next to your cluster turns green.

                            Stopping a Cluster

                            Qovery allows you to temporarily stop your cluster instead of deleting it.

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/cronjob/index.html b/docs/using-qovery/configuration/cronjob/index.html index 3b351532e3..b1d571a9c0 100644 --- a/docs/using-qovery/configuration/cronjob/index.html +++ b/docs/using-qovery/configuration/cronjob/index.html @@ -21,63 +21,63 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Cronjob

                          A cronjob is a workload that runs on your kubernetes cluster on a regular bases depending on the configured schedule (See Cronjob on Kubernetes for more info). It is useful to execute tasks on a regular bases, like pulling data from an external service every hour or process the last 24hrs of data in your database.

                          Qovery allows you to create and deploy cronjobs from two different sources: Git Repository or Container Registry

                          Deploying from a Git Repository

                          In this configuration, Qovery will pull the code from the chosen repository, build the application and deploy it on your kubernetes cluster.

                          The list of Git repositories available during the setup is strictly tied to the permissions of your git account (by default Qovery can access all your repositories). If you want to restrict the Qovery access only to a few repositories, user the GitHub Qovery Application (only for Github).

                          Deploying from a Container Registry

                          In this configuration, Qovery will pull the chosen container registry an image you have pre-built and deploy it on your kubernetes cluster.

                          To improve the security and avoid deploying images from non-authorized registries, we have decided to restrict the list of Container Registry you can use during the setup process. Only an administrator with the right permissions can manage it from the Container Registry Management page

                          Create a Cronjob

                          1. Go into the chosen environment and press the "New Service" button and then the "Create Cronjob" button

                            Creation

                          2. Select the following fields:

                            • Name: give a name to your applicaiton
                            • Source: Chose between Git Repository or Container Registry, depending on the source location of your application

                            If you want to deploy a cronjob from a Git Repository you will have to select:

                            • Git Repository: Select the git provider hosting your code (it can be hosted on GitHub, GitLab or Bitbucket).
                            • Branch: Select branch that Qovery should use to deploy your code
                            • Root Application Path: base folder in which the code resides in your repository
                            • Build Mode: only Docker is supported

                            If you want to deploy a cronjob from a Container Registry you will have to select:

                            • Registry: select the container registry storing the image of your job. Note: only pre-configured registry are available in this list, check the Container Registry Management page for more information.
                            • Image name: the name of the image to be deployed with this job (example: postgres)
                            • Image tag: the tag of the image to be deployed with this job (example: 12)

                            Auto Deploy

                            See the Deploying with auto-deploy feature section.

                          3. Specify the configuration of your job: - CRON Schedule: specify a valid CRON expression (see [Crontab guru](https://crontab.guru/) for help). After being deployed, the job will be executed following the defined schedule. - Image Entrypoint: the entrypoint to be used to launch your job (not mandatory) - CMD Arguments: the arguments to be passed to launch your job (not mandatory). We expect the format to be an array. Example ["rails", "-h", "0.0.0.0", "-p", "8080", "string"] - Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure) - Max duration time in seconds: Maximum duration allowed for the job to run before killing it and mark it as failed - Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally
                          4. Within this section, you will need to define the resources to be assigned to your job at run time.
                            • vCPU: the vCPU assigned to each instance of your application. The default is 500m (0.5 vCPU).
                            • RAM: the amount of RAM assigned to each instance of your application. The default is 512MB.
                          5. Define any input variable required by your job to run. Any declared variable will be injected as environment variables based on the selected scope (project, environment, service) +

                            Cronjob

                            A cronjob is a workload that runs on your kubernetes cluster on a regular bases depending on the configured schedule (See Cronjob on Kubernetes for more info). It is useful to execute tasks on a regular bases, like pulling data from an external service every hour or process the last 24hrs of data in your database.

                            Qovery allows you to create and deploy cronjobs from two different sources: Git Repository or Container Registry

                            Deploying from a Git Repository

                            In this configuration, Qovery will pull the code from the chosen repository, build the application and deploy it on your kubernetes cluster.

                            The list of Git repositories available during the setup is strictly tied to the permissions of your git account (by default Qovery can access all your repositories). If you want to restrict the Qovery access only to a few repositories, user the GitHub Qovery Application (only for Github).

                            Deploying from a Container Registry

                            In this configuration, Qovery will pull the chosen container registry an image you have pre-built and deploy it on your kubernetes cluster.

                            To improve the security and avoid deploying images from non-authorized registries, we have decided to restrict the list of Container Registry you can use during the setup process. Only an administrator with the right permissions can manage it from the Container Registry Management page

                            Create a Cronjob

                            1. Go into the chosen environment and press the "New Service" button and then the "Create Cronjob" button

                              Creation

                            2. Select the following fields:

                              • Name: give a name to your applicaiton
                              • Source: Chose between Git Repository or Container Registry, depending on the source location of your application

                              If you want to deploy a cronjob from a Git Repository you will have to select:

                              • Git Repository: Select the git provider hosting your code (it can be hosted on GitHub, GitLab or Bitbucket).
                              • Branch: Select branch that Qovery should use to deploy your code
                              • Root Application Path: base folder in which the code resides in your repository
                              • Build Mode: only Docker is supported

                              If you want to deploy a cronjob from a Container Registry you will have to select:

                              • Registry: select the container registry storing the image of your job. Note: only pre-configured registry are available in this list, check the Container Registry Management page for more information.
                              • Image name: the name of the image to be deployed with this job (example: postgres)
                              • Image tag: the tag of the image to be deployed with this job (example: 12)

                              Auto Deploy

                              See the Deploying with auto-deploy feature section.

                            3. Specify the configuration of your job: - CRON Schedule: specify a valid CRON expression (see [Crontab guru](https://crontab.guru/) for help). After being deployed, the job will be executed following the defined schedule. - Image Entrypoint: the entrypoint to be used to launch your job (not mandatory) - CMD Arguments: the arguments to be passed to launch your job (not mandatory). We expect the format to be an array. Example ["rails", "-h", "0.0.0.0", "-p", "8080", "string"] - Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure) - Max duration time in seconds: Maximum duration allowed for the job to run before killing it and mark it as failed - Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally
                            4. Within this section, you will need to define the resources to be assigned to your job at run time.
                              • vCPU: the vCPU assigned to each instance of your application. The default is 500m (0.5 vCPU).
                              • RAM: the amount of RAM assigned to each instance of your application. The default is 512MB.
                            5. Define any input variable required by your job to run. Any declared variable will be injected as environment variables based on the selected scope (project, environment, service) Any additional environment variable can be added later from the environment variable section

                              Input Variables

                            6. You will find a recap of your job setup and you can now decide to: 1. Go back to one of the previous steps and change your settings 2. Create your job without deploying it 3. Create and deploy your job

                              Recap

                            Deployment Management

                            Have a look at the Deployment Management section for more information.

                            Force Run

                            You can force the execution of a job independently its deployment status by:

                            1. Select the job that you want to force

                            2. click on the Play button of the cronjob you want to force and select the Force Run option. Note: the same option is available on the service list as well

                            3. Once you click, the job will be deployed and executed once. You will be able to follow its execution within the application logs

                            Configuration

                            Once created, you can access the configuration at any time via the Settings tab available on the service section

                            Settings

                            You can find below the description of each of the tabs available in this section

                            General

                            General settings section allows you to set up your application name and the source code location (git repository or image registry) .

                            Git Repository

                            If your job is built and deployed from a git repository, within this section you can:

                            • Modify the git provider where your code is stored (it can be hosted on GitHub, GitLab or Bitbucket).
                            • Modify the branch that Qovery should use for deploying your code
                            • Modify Root Application Path - base folder in which the application resides in your repository

                            Container Registry

                            If your application is deployed from an image registry, within this section you can modify:

                            • Registry: select the container registry storing the image of your application. Note: only pre-configured registry are available in this list, check the Container Registry Management page for more information.
                            • Image name: the name of the image to be deployed with this application (example: postgres)
                            • Image tag: the tag of the image to be deployed with this application (example: 12)

                            Build Mode

                            This option is available only if you have selected "Git Repository" as source. Only Docker is supported

                            Qovery runs your application within the Container technology. To build and run your application, you need to provide a valid Dockerfile.

                            Valid NodeJS Dockerfile
                            FROM node:13-alpine
                            RUN mkdir -p /usr/src/app
                            WORKDIR /usr/src/app
                            COPY . .
                            RUN npm install
                            EXPOSE 3000
                            CMD node ./bin/www

                            After creating a Dockerfile, specify the location of your Dockerfile in Dockefile path field.

                            Configuration from above will make Qovery look for the Dockerfile in /timescale/Dockerfile path of your repository (Root Application Path + Dockerfile Path).

                            Auto Deploy

                            See the Deploying with auto-deploy feature section.

                            JOB Configuration

                            You can modify here the configuration of your job:

                            • CRON Schedule: specify a valid CRON expression (see Crontab guru for help). After being deployed, the job will be executed following the defined schedule.
                            • Image Entrypoint: the entrypoint to be used to launch your job (not mandatory)
                            • CMD Arguments: the arguments to be passed to launch your job (not mandatory). We expect the format to be an array. Example ["rails", "-h", "0.0.0.0", "-p", "8080", "string"]
                            • Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure)
                            • Max duration time in seconds: Maximum duration allowed for the job to run before killing it and mark it as failed
                            • Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally

                            Resources

                            CPU

                            To configure the number of CPUs that your job needs, adjust the setting in the Resources section.

                            Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU.

                            RAM

                            To configure the amount of RAM that your app needs, adjust the setting in Resources section.

                            Please note that in this section you configure the CPU allocated by the cluster for your application and that cannot consume more than this value. Even if the application is underused and consume less resources, the cluster will still reserve the selected amount of CPU. If your application requires more RAM than requested, it will be killed by the kubernetes scheduler.

                            Health Checks

                            To know more about how to configure your Liveness and Readiness probes, have a look at the health-checks section

                            Environment Variable

                            To learn how to set up environment variables in your projects and applications, navigate to configuring Environment Variables section.

                            Secrets

                            To learn how to set up secrets in your projects and applications, navigate to configuring Secrets section.

                            Logs

                            To learn how to display your application logs, navigate to logs section

                            Clone

                            You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment.

                            Clone Service

                            The target environment can be the same as the current environment or even another one in a completely different project.

                            Important information

                            Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:

                            • same environment:
                              • custom domain: this setup is not copied into the new service (to avoid collision)
                            • another environment:
                              • custom domain: this setup is not copied into the new service (to avoid collision)
                              • environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)
                              • deployment pipeline: stage setup is not copied (since the target stage might not exist)
                              • number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)

                            Please check the configuration of the new service before deploying it.

                            Delete a job

                            1. Select the job you want to delete

                            2. In the overview, click on the 3 dots button and remove the job. Note: the same option is available on the service list as well

                              Application

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/database/index.html b/docs/using-qovery/configuration/database/index.html index 7a2cbf5007..83c1ba9c36 100644 --- a/docs/using-qovery/configuration/database/index.html +++ b/docs/using-qovery/configuration/database/index.html @@ -21,60 +21,60 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Databases

                          Qovery natively lets you deploy and access the most popular SQL and NoSQL databases available on the major cloud providers. Reliability and resiliency are at the heart of their services, so you don't have to worry about your data on Qovery.

                          Qovery natively supports the following databases:

                          • PostgreSQL
                          • MySQL
                          • MongoDB
                          • Redis

                          Qovery can natively operate a database in two different ways (called "Mode"):

                          • Container mode: preferred for testing and development
                          • Managed mode: preferred for production, limited configuration parameters (see the Configuration section).

                          If the natively supported databases or operation modes are not enough for you, depending on your use case you have the following alternative solutions:

                          • Use an existing DB on a dedicated VPC: your applications can access this database via VPC peering. Have a look at this guide for more information.
                          • Create your custom database via Qovery: You will be able to deploy any kind of database through Qovery by using a lifecycle jobs. For example, you can use a terraform script to deploy your custom RDS instance on AWS via Terraform (have a look at this example).

                          The following sections will show you how you can create and manage the databases natively supported by Qovery. For any other use case, please refer to the guides provided above.

                          Container mode

                          The database is created as a container with attached persistent storage directly on your Kubernetes cluster (1 instance). They are perfect for development and testing, as they are significantly cheaper than services provided by cloud providers.

                          Managed mode

                          Qovery creates and manages the lifecycle of a cloud provider managed database instance (for example an RDS instance on AWS). These are perfect for production since they guarantee the right level of resilience, performance and data security best practices.

                          Applying changes to a managed database

                          Once you request to change the version, instance type or disk size of your Managed database, the cloud provider applies the update based on its own internal rules and might cause downtime of your database.

                          For example, by default AWS doesn't apply major updates immediately on the database and instead, it waits for a maintenance window. This means that your change will not be applied immediately but you can always force the change directly from your AWS console AFTER having applied the change on Qovery (to avoid configuration drifts).

                          Have a look at your cloud provider documentation to know more about how version upgrades are managed:

                          Create a database

                          1. Navigate to Console

                          2. Select your project and environment

                          3. Click Add Database button

                            Database

                          4. Select database type, name, description (optional), version, mode and accessibility

                            General Information

                          5. Within the "Resources" step you will find different configurations based on the selected mode:

                            • If you are using the database in Container mode, you can set the CPU, RAM and storage that will be assigned to the instance running the docker image of the database.
                            • If you are using the database in Managed mode, you can select the instance type and the storage that will be assigned to the instance running the database. Note, the instance selected instance type has a direct impact on your cloud provider cost.

                            Resources

                          6. At the end a recap will allow you to just create the database or create and deploy it

                            Recap

                          Configuration

                          Once created, you can access the configuration of a database at any time via the Settings tab available on the database page

                          Database Settings

                          You can find below the description of each of the tabs available in this section

                          General

                          Modes

                          As described at the beginning of this document, databases can operate in two modes:

                          • Managed
                          • Container

                          Managed databases are perfect for production - they are provided and managed by major cloud providers like AWS to make sure your production data is well managed.

                          Container databases are managed by Qovery as Docker containers with attached persistent storage directly on your Kubernetes cluster (1 instance). They are perfect for development and testing, as they are significantly cheaper than services provided by cloud providers.

                          Please refer to the dedicated database sub-pages to get more information on the supported mode for each cloud provider.

                          Versions

                          We regularly update the version available for each database. Please refer to the dedicated database sub-pages to get more information on the supported version for each database types and cloud provider.

                          You can upgrade the version of your database directly from the Qovery interface.

                          Accessibility

                          This parameter lets you decide whether to expose publicly or not your database.

                          • Public access will make your database accessible via the public network
                          • Private access will make your database accessible only by applications in your environment

                          Resources

                          CPU / Memory

                          This configuration is available only for databases in Container mode

                          You can select the CPU assigned to the Kuerbetes pod running the database instance

                          Instance Type

                          This configuration is available only for databases in Managed mode

                          You can modify the CPU assigned to the instance running your database (And thus, its resources).

                          Storage

                          You can select the size of the persistent storage attached to the container database.

                          Credentials and connectivity

                          When a database is created in your environment, Qovery will automatically create and inject a set of BUILT_IN environment variables containing all the parameters necessary to your application to connect to the database.

                          This is the list of environment variables and secrets that will be automatically created:

                          NameDescriptionExample
                          QOVERY<DATABASE_TYPE><DBID>_DEFAULT_DATABASE_NAMEEnv Var containing the default database namepostgres
                          QOVERY<DATABASE_TYPE><DBID>_HOSTEnv Var containing the external hostname of the database (if you need access from the outside and the DB is configured with visibility "PUBLIC")zf5206c84-postgresql.oom.sh
                          QOVERY<DATABASE_TYPE><DBID>_HOST_INTERNALEnv Var containing the internal hostname of the database (if you need access it from within the cluster network)zf5206c84-postgresql
                          QOVERY<DATABASE_TYPE><DBID>_LOGINEnv Var containing the username of the DBsuperuser
                          QOVERY<DATABASE_TYPE><DBID>_PORTEnv Var containing the port to be used for connecting to the DB5432
                          QOVERY<DATABASE_TYPE><DBID>_HOSTSecret containing the external URI to be used for connecting to the DB (if you need access from the outside and the DB is configured with visibility "PUBLIC")sql://root:xxxx@z4a58c1e2-postgresql.oom.sh:27017/admin
                          QOVERY<DATABASE_TYPE><DBID>_HOST_INTERNALSecret containing the internal URI to be used for connecting to the DB (if you need access it from within the cluster network)sql://root:xxxx@z4a58c1e2-postgresql:27017/admin
                          QOVERY<DATABASE_TYPE><DBID>_PASSWORDSecret containing the password of the DBdbsecret

                          Please note that the built-in variables follow the naming pattern: QOVERY_DATABASETYPE + <your_db_name> + <type_of_variable> where:

                          • <your_db_name> is the name of your database
                          • <type_of_variable> is the type of variable we inject, e.g. PASSWORD, VERSION, CONNECTION_URI and so on.

                          To know how to access your database from your application, have a look at the database section.

                          Clone

                          You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment.

                          Clone Service

                          The target environment can be the same as the current environment or even another one in a completely different project.

                          Important information

                          Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:

                          • same environment:
                            • custom domain: this setup is not copied into the new service (to avoid collision)
                          • another environment:
                            • custom domain: this setup is not copied into the new service (to avoid collision)
                            • environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)
                            • deployment pipeline: stage setup is not copied (since the target stage might not exist)
                            • number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)

                          Please check the configuration of the new service before deploying it.

                          Delete your database instance

                          1. Navigate to Console

                          2. Select your environment and database

                          3. In database overview, click on Action remove button

                            Database Remove

                          Available Databases

                          Mongodb
                          Mysql
                          Postgresql
                          Redis
                          +

                          Databases

                          Qovery natively lets you deploy and access the most popular SQL and NoSQL databases available on the major cloud providers. Reliability and resiliency are at the heart of their services, so you don't have to worry about your data on Qovery.

                          Qovery natively supports the following databases:

                          • PostgreSQL
                          • MySQL
                          • MongoDB
                          • Redis

                          Qovery can natively operate a database in two different ways (called "Mode"):

                          • Container mode: preferred for testing and development
                          • Managed mode: preferred for production, limited configuration parameters (see the Configuration section).

                          If the natively supported databases or operation modes are not enough for you, depending on your use case you have the following alternative solutions:

                          • Use an existing DB on a dedicated VPC: your applications can access this database via VPC peering. Have a look at this guide for more information.
                          • Create your custom database via Qovery: You will be able to deploy any kind of database through Qovery by using a lifecycle jobs. For example, you can use a terraform script to deploy your custom RDS instance on AWS via Terraform (have a look at this example).

                          The following sections will show you how you can create and manage the databases natively supported by Qovery. For any other use case, please refer to the guides provided above.

                          Container mode

                          The database is created as a container with attached persistent storage directly on your Kubernetes cluster (1 instance). They are perfect for development and testing, as they are significantly cheaper than services provided by cloud providers.

                          Managed mode

                          Qovery creates and manages the lifecycle of a cloud provider managed database instance (for example an RDS instance on AWS). These are perfect for production since they guarantee the right level of resilience, performance and data security best practices.

                          Applying changes to a managed database

                          Once you request to change the version, instance type or disk size of your Managed database, the cloud provider applies the update based on its own internal rules and might cause downtime of your database.

                          For example, by default AWS doesn't apply major updates immediately on the database and instead, it waits for a maintenance window. This means that your change will not be applied immediately but you can always force the change directly from your AWS console AFTER having applied the change on Qovery (to avoid configuration drifts).

                          Have a look at your cloud provider documentation to know more about how version upgrades are managed:

                          Create a database

                          1. Navigate to Console

                          2. Select your project and environment

                          3. Click Add Database button

                            Database

                          4. Select database type, name, description (optional), version, mode and accessibility

                            General Information

                          5. Within the "Resources" step you will find different configurations based on the selected mode:

                            • If you are using the database in Container mode, you can set the CPU, RAM and storage that will be assigned to the instance running the docker image of the database.
                            • If you are using the database in Managed mode, you can select the instance type and the storage that will be assigned to the instance running the database. Note, the instance selected instance type has a direct impact on your cloud provider cost.

                            Resources

                          6. At the end a recap will allow you to just create the database or create and deploy it

                            Recap

                          Configuration

                          Once created, you can access the configuration of a database at any time via the Settings tab available on the database page

                          Database Settings

                          You can find below the description of each of the tabs available in this section

                          General

                          Modes

                          As described at the beginning of this document, databases can operate in two modes:

                          • Managed
                          • Container

                          Managed databases are perfect for production - they are provided and managed by major cloud providers like AWS to make sure your production data is well managed.

                          Container databases are managed by Qovery as Docker containers with attached persistent storage directly on your Kubernetes cluster (1 instance). They are perfect for development and testing, as they are significantly cheaper than services provided by cloud providers.

                          Please refer to the dedicated database sub-pages to get more information on the supported mode for each cloud provider.

                          Versions

                          We regularly update the version available for each database. Please refer to the dedicated database sub-pages to get more information on the supported version for each database types and cloud provider.

                          You can upgrade the version of your database directly from the Qovery interface.

                          Accessibility

                          This parameter lets you decide whether to expose publicly or not your database.

                          • Public access will make your database accessible via the public network
                          • Private access will make your database accessible only by applications in your environment

                          Resources

                          CPU / Memory

                          This configuration is available only for databases in Container mode

                          You can select the CPU assigned to the Kuerbetes pod running the database instance

                          Instance Type

                          This configuration is available only for databases in Managed mode

                          You can modify the CPU assigned to the instance running your database (And thus, its resources).

                          Storage

                          You can select the size of the persistent storage attached to the container database.

                          Credentials and connectivity

                          When a database is created in your environment, Qovery will automatically create and inject a set of BUILT_IN environment variables containing all the parameters necessary to your application to connect to the database.

                          This is the list of environment variables and secrets that will be automatically created:

                          NameDescriptionExample
                          QOVERY<DATABASE_TYPE><DBID>_DEFAULT_DATABASE_NAMEEnv Var containing the default database namepostgres
                          QOVERY<DATABASE_TYPE><DBID>_HOSTEnv Var containing the external hostname of the database (if you need access from the outside and the DB is configured with visibility "PUBLIC")zf5206c84-postgresql.oom.sh
                          QOVERY<DATABASE_TYPE><DBID>_HOST_INTERNALEnv Var containing the internal hostname of the database (if you need access it from within the cluster network)zf5206c84-postgresql
                          QOVERY<DATABASE_TYPE><DBID>_LOGINEnv Var containing the username of the DBsuperuser
                          QOVERY<DATABASE_TYPE><DBID>_PORTEnv Var containing the port to be used for connecting to the DB5432
                          QOVERY<DATABASE_TYPE><DBID>_HOSTSecret containing the external URI to be used for connecting to the DB (if you need access from the outside and the DB is configured with visibility "PUBLIC")sql://root:xxxx@z4a58c1e2-postgresql.oom.sh:27017/admin
                          QOVERY<DATABASE_TYPE><DBID>_HOST_INTERNALSecret containing the internal URI to be used for connecting to the DB (if you need access it from within the cluster network)sql://root:xxxx@z4a58c1e2-postgresql:27017/admin
                          QOVERY<DATABASE_TYPE><DBID>_PASSWORDSecret containing the password of the DBdbsecret

                          Please note that the built-in variables follow the naming pattern: QOVERY_DATABASETYPE + <your_db_name> + <type_of_variable> where:

                          • <your_db_name> is the name of your database
                          • <type_of_variable> is the type of variable we inject, e.g. PASSWORD, VERSION, CONNECTION_URI and so on.

                          To know how to access your database from your application, have a look at the database section.

                          Clone

                          You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment.

                          Clone Service

                          The target environment can be the same as the current environment or even another one in a completely different project.

                          Important information

                          Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:

                          • same environment:
                            • custom domain: this setup is not copied into the new service (to avoid collision)
                          • another environment:
                            • custom domain: this setup is not copied into the new service (to avoid collision)
                            • environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)
                            • deployment pipeline: stage setup is not copied (since the target stage might not exist)
                            • number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)

                          Please check the configuration of the new service before deploying it.

                          Delete your database instance

                          1. Navigate to Console

                          2. Select your environment and database

                          3. In database overview, click on Action remove button

                            Database Remove

                          Available Databases

                          Mongodb
                          Mysql
                          Postgresql
                          Redis
                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/database/mongodb/index.html b/docs/using-qovery/configuration/database/mongodb/index.html index 66660543d7..caca15da53 100644 --- a/docs/using-qovery/configuration/database/mongodb/index.html +++ b/docs/using-qovery/configuration/database/mongodb/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          MongoDB

                          MongoDB is a cross-platform document-oriented database program. Classified as a NoSQL, MongoDB uses JSON-like documents with schema.

                          Supported Versions and Cloud Providers

                          You can find the supported versions directly within the Qovery Console.

                          Availability of the Container version or Cloud Provider Managed versions depends on the chosen Cloud Provider

                          Cloud providerContainer supportedManaged supported
                          AWSYesYes
                          ScalewayYesNo

                          Credentials

                          Have a look at the Database page to know more about the database creation and setup.

                          +

                          MongoDB

                          MongoDB is a cross-platform document-oriented database program. Classified as a NoSQL, MongoDB uses JSON-like documents with schema.

                          Supported Versions and Cloud Providers

                          You can find the supported versions directly within the Qovery Console.

                          Availability of the Container version or Cloud Provider Managed versions depends on the chosen Cloud Provider

                          Cloud providerContainer supportedManaged supported
                          AWSYesYes
                          ScalewayYesNo

                          Credentials

                          Have a look at the Database page to know more about the database creation and setup.

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/database/mysql/index.html b/docs/using-qovery/configuration/database/mysql/index.html index 5c6456328b..0d7cf110ed 100644 --- a/docs/using-qovery/configuration/database/mysql/index.html +++ b/docs/using-qovery/configuration/database/mysql/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          MySQL

                          MySQL is the world's most popular open source database. Whether you are a fast growing web property, technology ISV or large enterprise, MySQL can cost-effectively help you deliver high performance, scalable database applications.

                          Supported Versions and Cloud Providers

                          You can find the supported versions directly within the Qovery Console.

                          Availability of the Container version or Cloud Provider Managed versions depends on the chosen Cloud Provider

                          Cloud providerContainer supportedManaged supported
                          AWSYesYes (RDS)
                          ScalewayYesNo

                          Have a look at the Database page to know more about the database creation and setup.

                          +

                          MySQL

                          MySQL is the world's most popular open source database. Whether you are a fast growing web property, technology ISV or large enterprise, MySQL can cost-effectively help you deliver high performance, scalable database applications.

                          Supported Versions and Cloud Providers

                          You can find the supported versions directly within the Qovery Console.

                          Availability of the Container version or Cloud Provider Managed versions depends on the chosen Cloud Provider

                          Cloud providerContainer supportedManaged supported
                          AWSYesYes (RDS)
                          ScalewayYesNo

                          Have a look at the Database page to know more about the database creation and setup.

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/database/postgresql/index.html b/docs/using-qovery/configuration/database/postgresql/index.html index e630ca171d..898ba60574 100644 --- a/docs/using-qovery/configuration/database/postgresql/index.html +++ b/docs/using-qovery/configuration/database/postgresql/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          PostgreSQL

                          PostgreSQL is a powerful, open source object-relational database system with over 30 years of active development that has earned it a strong reputation for reliability, feature robustness, and performance.

                          Supported Versions and Cloud Providers

                          You can find the supported versions directly within the Qovery Console.

                          Availability of the Container version or Cloud Provider Managed versions depends on the chosen Cloud Provider

                          Cloud providerContainer supportedManaged supported
                          AWSYesYes (RDS)
                          ScalewayYesNo

                          Have a look at the Database page to know more about the database creation and setup.

                          +

                          PostgreSQL

                          PostgreSQL is a powerful, open source object-relational database system with over 30 years of active development that has earned it a strong reputation for reliability, feature robustness, and performance.

                          Supported Versions and Cloud Providers

                          You can find the supported versions directly within the Qovery Console.

                          Availability of the Container version or Cloud Provider Managed versions depends on the chosen Cloud Provider

                          Cloud providerContainer supportedManaged supported
                          AWSYesYes (RDS)
                          ScalewayYesNo

                          Have a look at the Database page to know more about the database creation and setup.

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/database/redis/index.html b/docs/using-qovery/configuration/database/redis/index.html index 46d1df2365..40f7dacddd 100644 --- a/docs/using-qovery/configuration/database/redis/index.html +++ b/docs/using-qovery/configuration/database/redis/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Redis

                          Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams.

                          Supported Versions and Cloud Providers

                          You can find the supported versions directly within the Qovery Console.

                          Availability of the Container version or Cloud Provider Managed versions depends on the chosen Cloud Provider

                          Cloud providerContainer supportedManaged supported
                          AWSYesYes
                          ScalewayYesNo

                          Have a look at the Database page to know more about the database creation and setup.

                          +

                          Redis

                          Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams.

                          Supported Versions and Cloud Providers

                          You can find the supported versions directly within the Qovery Console.

                          Availability of the Container version or Cloud Provider Managed versions depends on the chosen Cloud Provider

                          Cloud providerContainer supportedManaged supported
                          AWSYesYes
                          ScalewayYesNo

                          Have a look at the Database page to know more about the database creation and setup.

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/deployment-rule/index.html b/docs/using-qovery/configuration/deployment-rule/index.html index 8c5f5132b2..a6b0a44852 100644 --- a/docs/using-qovery/configuration/deployment-rule/index.html +++ b/docs/using-qovery/configuration/deployment-rule/index.html @@ -21,36 +21,36 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Deployment Rule

                          A Deployment Rules lets you configure the lifecycle of your Environments.

                          Why using Deployment Rule?

                          Cloud cost optimization

                          Using the Deployment Rules is a good practice to drastically reduce your cost. Indeed, Qovery knows how to optimize your Cloud resources +

                          Deployment Rule

                          A Deployment Rules lets you configure the lifecycle of your Environments.

                          Why using Deployment Rule?

                          Cloud cost optimization

                          Using the Deployment Rules is a good practice to drastically reduce your cost. Indeed, Qovery knows how to optimize your Cloud resources when your applications are not running. Then you can expect to reduce your Cloud cost up to 60% by using the Deployment Rules.

                          Time optimization

                          Configuring your environments, managing, starting, shutting down all takes valuable time from your developers. Deployment Rules allow you to declaratively set up how your resources should be used, let Qovery do the dirty job, allowing your employees to focus on important things.

                          Examples

                          Shutting down environments

                          Developers in your company work from 9-to-5, five days a week. During the weekend, at night, and of the working hours, keeping all development environments running may be a huge expense that gives you no benefits.

                          Deployment Rules address this problem very effectively - all you need to do is to define when you need your environments to be running, @@ -61,27 +61,27 @@ Starting from the top, the rules are ranked from highest to lowest priority.

                          Reorder priority rules

                          Environment Deployment Rules

                          Setting up Deployment Rules at the Enviornment level allows you to make all necessary adjustments applied by your default rules from the Project level.

                          Have a look at [this section][docs.using-qovery.configuration.environment#deployment-rule]] to know more.

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/environment-variable/index.html b/docs/using-qovery/configuration/environment-variable/index.html index fbb3790428..53703cb24b 100644 --- a/docs/using-qovery/configuration/environment-variable/index.html +++ b/docs/using-qovery/configuration/environment-variable/index.html @@ -21,36 +21,36 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Environment Variable & Secrets

                          Qovery makes Environment Variables available to your services at runtime, as well as during builds and deploys.

                          If your projects and applications rely on sensitive data like credentials, API keys, certificates, Qovery offers you a way to store them as a Secret. Secrets are special environment variable safely encrypted, and their values can not be retrieved via Qovery API - they are only accessible for your application during build and runtime.

                          Qovery automatically generates for you some special environment variable (called BUILT_IN) which allows you to setup your service interconnection. See the BUILT_IN Section section.

                          Environment Variable definition

                          An environment variable is defined by:

                          • A type: two types are supported today
                            • Variable: classic key/value pairs where the value can be retrieved at build and run time by using its name (key). Example: Key = THIRD_PARTY_URL, Value = https://mythirdparty.com
                            • Variable as File: key/value/path triplets where the value will be stored as a file on the specified path. Your application can then retrieve the path of the file at run +

                              Environment Variable & Secrets

                              Qovery makes Environment Variables available to your services at runtime, as well as during builds and deploys.

                              If your projects and applications rely on sensitive data like credentials, API keys, certificates, Qovery offers you a way to store them as a Secret. Secrets are special environment variable safely encrypted, and their values can not be retrieved via Qovery API - they are only accessible for your application during build and runtime.

                              Qovery automatically generates for you some special environment variable (called BUILT_IN) which allows you to setup your service interconnection. See the BUILT_IN Section section.

                              Environment Variable definition

                              An environment variable is defined by:

                              • A type: two types are supported today
                                • Variable: classic key/value pairs where the value can be retrieved at build and run time by using its name (key). Example: Key = THIRD_PARTY_URL, Value = https://mythirdparty.com
                                • Variable as File: key/value/path triplets where the value will be stored as a file on the specified path. Your application can then retrieve the path of the file at run time by using the variable name (key). Only text files are supported. Example: Key = MY_CONFIG, Path = /tmp/config.json Value = {"key1":"value1","key2":"value2"}
                              • A scope: the accessibility level of this variable: application, environment, project (see scopes section below)
                              • A secret flag: it determines if the variable value needs to be encrypted and should be accessed ONLY by your applications (no access via the API/UI)

                              Environment variable vs Environment variable as file

                              Depending on your use case, you might decide to use a simple key value environment variable or instead use the environment variable as a file.

                              Environment Variable

                              If you need to store a simple value that needs to be retrieved at build or run time, than you can use a key/value environment variable

                              Example: You have a 3rd party application running on the endpoint https://mythirdparty.com. You can create an environment variable called THIRD_PARTY_URL that will contain the 3rd party URL:

                              Variable

                              Your application will then be able to retrieve the url by getting the value of the environment variable THIRD_PARTY_URL.

                              Environment Variable as file

                              If your application needs to load configuration files at run time, than you can use the environment variable as file.

                              Example: Grafana allows you to override the default configuration by setting a few environment variables pointing to your own configuration files. By default, the variable GF_PATHS_CONFIG points to '/etc/grafana/grafana.ini' but in case you want to specify a different configuration, you can create an environment variable as file like this:

                              Variable as file

                              When the grafana container will load the env var GF_PATHS_CONFIG, it will retrieve the path where the configuration file is stored and load its content.

                              Scopes

                              The scope of a variable allows you to define at which level this environment variable can be accessed (e.g. : only by one specific service).

                              There are three scopes for the Environment Variables:

                              ScopeLevelDescription
                              PROJECT1Variables at the project level are shared across all environments and all applications of the project
                              ENVIRONMENT2Variables at the environment level are shared across all applications of the project in one, given environment
                              APPLICATION3Variables available for one application in one environment

                              BUILT_IN variables

                              Qovery automatically generates some variables (called BUILT_IN) which allow you to easily configure your service interconnection or to access some of the environment/application information.

                              By default, every environment contains the following BUILT_IN variables:

                              NameDescription
                              QOVERY_PROJECT_IDCurrent project ID
                              QOVERY_ENVIRONMENT_IDCurrent environment ID
                              QOVERY_APPLICATION_IDCurrent service ID (for application with source = git repository)
                              QOVERY_CONTAINER_IDCurrent service ID (for application with source = container registry)
                              QOVERY_JOB_IDCurrent service ID (for lifecycle job and cronjob)
                              QOVERY_CLOUD_PROVIDER_REGIONCloud provider region of the Kubernetes cluster running this environment
                              QOVERY_KUBERNETES_NAMESPACE_NAMENamespace used in Kubernetes to run the application of this environment
                              QOVERY_KUBERNETES_CLUSTER_NAMEName of the Kubernetes cluster running this environment

                              For any service within your environment (database, application, job), your application get access to a set of BUILT_IN variables. These can be used, to configure the interconnection between your services.

                              Naming Convention:

                              We use the following naming convention for additional built-in variables:

                              QOVERY_<SERVICE_TYPE>_<SERVICE_ID>_<SPEC>

                              For more information on how to use the BUILT_IN environment variables to:

                              Aliases and overrides

                              For a given environment variable, you can create aliases and overrides:

                              • Alias: it defines an alias for the environment variable. You can access its value by its original name or by its alias name.
                              • Override: it overrides the value of the environment variable. Example: you have an environment variable with scope = project having a particular value but you want to define a special value only for one environment. Instead of creating a separate environment variable only for that project, you can create an override of that variable within the environment requiring the special value.

                              Variables Interpolation

                              You can define an environment variable as a composition of text and other environment variables value (environment variables interpolation). @@ -65,27 +65,27 @@ The different cases are described below.

                              Imported variable has same name as BUILT_IN variable

                              TypeNameValueScope
                              Existing variables
                              VALUEMY_VAR42Built_in
                              Variables to import
                              VALUEMY_VAR10Application

                              Built_in environment variables are generated and managed by Qovery and will not be overwritten, even if the overwriting option is activated.

                              Imported variable has same name as an existing ALIAS

                              TypeNameValueScope
                              Existing variables
                              VALUEMY_VAR42Environment
                              ALIASMY_VAR_ALIASMY_VARApplication
                              Variables to import
                              VALUEMY_VAR_ALIAS10Application

                              The value cannot be rewritten because the link between the original variable and the alias would be lost.

                              Imported variable has same name as an existing secret (or vice versa)

                              TypeNameValueScopeSecret
                              Existing variables
                              VALUEMY_VAR1ApplicationYe
                              Variables to import
                              VALUEMY_VAR2ApplicationNo

                              The value cannot be imported because this will overwrite the existing secret.

                              Overwriting and limitations

                              Some overwriting cases are not supported for now. They are summarized in the following table.

                              Existing variable scopeImported variable scopeSupported
                              PROJECTPROJECT / ENVIRONMENT / APPLICATIONYES
                              ENVIRONMENTPROJECTNO
                              ENVIRONMENTENVIRONMENT / APPLICATIONYES
                              APPLICATIONPROJECT / ENVIRONMENTNO
                              APPLICATIONAPPLICATIONYES

                              Service interconnection

                              Connecting to a database

                              To access a database managed by Qovery from your application, you can use the BUILT_IN environment variables and secrets that have been automatically created by Qovery during the database creation process. You can find all the BUILT_IN variables on the Qovery console within the Environment Variable section of your application (see the credentials and connectivity section for the full list).

                              In order to match the naming convention of the database connection variables used within your code, you can create an alias for each variable in the Qovery console so that you don't need to change your code.

                              Once you have defined an alias for each variable, you can redeploy the application and check that it has finally access to the database.

                              Example

                              You have created a postgres database on the Qovery console. Within the code of your application you need some environment variables containing the connection parameters of the database: DATABASE_URL, DATABASE_USER, DATABASE_PASSWORD, DATABASE_PORT, DATABASE_NAME

                              example.py
                              DB_NAME = os.getenv("DATABASE_NAME", "nemo")
                              DB_USER = os.getenv("DATABASE_USER", "nemo")
                              DB_PASSWORD = os.getenv("DATABASE_PASSWORD", "password")
                              DB_HOST = os.getenv("DATABASE_HOST", "localhost")
                              DB_PORT = os.getenv("DATABASE_PORT", "5432")

                              To match your internal naming convention, you can create aliases for each of the corresponding variables in this way:

                              Env Var Aliases

                              Connecting to another application

                              To access another application managed by Qovery, you can use the BUILT_IN environment variables that have been automatically created by Qovery during the creation of that particular application. You can find all the BUILT_IN variables on the Qovery console within the Environment Variable section of your application.

                              Please note that two BUILT_IN might exist:

                              • QOVERY_APPLICATION_<APPID>_HOST_INTERNAL : it contains the INTERNAL host of the application that can be used inside your Kubernetes cluster (and thus by any application running on it)
                              • QOVERY_APPLICATION_<APPID>_HOST_EXTERNAL : it contains the EXTERNAL host of the application that can be used to reach your application from outside your Kubernetes cluster (if the application is publicly exposing one of its ports)

                              In order to match the naming convention of the connection variables used within your code, you can create an alias for the HOST_INTERNAL variable so that you don't need to change your code.

                              Once you have defined an alias for each variable, you can redeploy the application and check that it can reach the other application.

                              Example

                              You have created a backend application on the Qovery console and a BUILD_IN variable has been created containing the application HOST called QOVERY_APPLICATION_Z9D8DAA08_HOST_INTERNAL. Within the code of your front-end application you need some environment variables containing the host of the backend application (BACKEND_HOST)

                              To match your internal naming convention, you can create alias for the corresponding variable in this way:

                              Env Var Aliases

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/environment/index.html b/docs/using-qovery/configuration/environment/index.html index 00cac4193e..09b0c0f423 100644 --- a/docs/using-qovery/configuration/environment/index.html +++ b/docs/using-qovery/configuration/environment/index.html @@ -21,61 +21,61 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Environment

                          An Environment is a group of applications and databases running within the same namespace. A Project can have multiple Environments.

                          Types of environment

                          There are different types of environments that can be defined within Qovery. Types of environment are also called mode, to label it and share with others in the organization how to use it. +

                          Environment

                          An Environment is a group of applications and databases running within the same namespace. A Project can have multiple Environments.

                          Types of environment

                          There are different types of environments that can be defined within Qovery. Types of environment are also called mode, to label it and share with others in the organization how to use it. Here is the mode you should set depending of the use of your Environment.

                          environment moderecommended modewhy
                          ProductionProduction environment should not be stopped or deleted by anyone.
                          StagingStaging environment reflects how things work and is sometimes as critical as production for companies.
                          DevelopmentDevelopment environment is a working environment that could be used to develop and test new features and fixes.

                          A special mode Preview exists and it is automatically set when a Preview Environment is created on a new pull request. Have a look at this section to know more about preview environments.

                          Create an environment

                          You can create a new environment by clicking on the Create environment button of the Environment list page.

                          Create an environment

                          A modal will appear that will allow you to specify following parameters

                          • name: Give a name to your environment that is easily recognizable by anyone from your team. It is good practice to name your environment production, main or master, staging, dev, fix/xxx, feat/xxx, depending on the purpose of your environment.
                          • mode: Specify environment mode. See Types of environment section. If automatic is chosen, the mode will be automatically selected based on the configured deployment rules. See the Project Deployment Rules section
                          • cluster : Specify the organization cluster on which this new environment will be deployed. If automatic is chosen, the cluster will be automatically selected based on the configured deployment rules. See the Project Deployment Rules section

                          Create an environment - Modal

                          Once created you can start adding your services within it depending on your need:

                          Create Service

                          Editing the environment settings

                          You can access the environment settings by opening the SETTINGS tab.

                          Environment settings tab

                          General settings

                          On the General tab, you will be able to update your environment name. It will also display the environment mode and the cluster assigned to your environment.

                          Deployment Rule

                          Using Deployment Rules is a good practice to drastically reduce your cost. To know more of the benefit of using them, have a look at the Deployment Rules section.

                          A default deployment configuration is applied to your environment when it's created but you can modify this default behaviour by creating a dedicated rule at project level that will affect any new environment created and matching the condition.

                          Once created, you can edit the deployment rule of the environment from the deployment rules settings.

                          Below you can find the description of the deployment rule settings that can be modified for a specific environment

                          Start & Stop

                          The start and stop section allow you to override the default settings applied by the project rule to precisely set up when the environment should be deployed and cleaned up.

                          Deployment Pipeline

                          This section allows you to configure the deployment pipeline to be executed when a deployment on the environment is triggered. More in particular, you can define the deployment order of each service within your environment.

                          Deployment Pipeline

                          You can get more information about the Qovery deployment pipeline and how it works within this section.

                          Editing deployment order

                          You can edit the order simply by drag and drop the service from one stage to another.

                          You can also modify the order of an entire stage by opening the 3 dots menu of the stage and clicking on Edit order

                          Adding a new stage

                          You can add a new stage by pressing the Add stage button. A name and a description are required to create the new stage.

                          Editing deployment stage

                          You can modify the name and the description of a stage by opening the 3 dots menu of the stage and clicking on Edit order

                          Preview environment

                          Use Preview Environment to get early feedback on your application changes by creating a dedicated environment for each of your pull requests. Your production environment runs 24/7, where your other environments may not need to run all day long. E.g. you may need to run Environments to get early feedback on your application changes before the changes are merged into production. This is what we call Preview Environment.

                          Sometimes Preview Environment is also known as Ephemeral Environment, Temporary Environment, Development Environment, Review App.

                          The preview environment section allows you to manage the complete setup of your preview environment feature

                          Preview Environment Settings

                          Turn on Preview Environments

                          it allows you to enable the preview environment feature for the current environment. Any PR opened on a service belonging to this environment will trigger the preview environment flow.

                          Create on demand

                          You can define the behaviour to follow for the creation of the preview environments:

                          • On Demand (Flag enabled)
                          • On every PR (Flag disabled)

                          On Demand Flow

                          1. A message is dropped on the PR asking you if you want to create a preview environment or not. You will get the list of environments where the preview env feature is activated (in case you have multiple environments) and the command to add as a comment of your PR to trigger the preview.
                          2. you will decide weather to create a preview environment or not by typing the right command as a comment within the PR
                          3. once the command is added in the comments, the preview creation is triggered and your preview environment is created and its deployment starts
                          4. once the deployment is completed, an additional comment will be posted in the PR, providing you with URLs to access your services.

                          Preview Environment Settings

                          On every PR Flow Same as above but the preview environment creation flow is triggered automatically without any user intervention (only step 3 and 4)

                          Preview Environment Github Bot Message

                          Auto-delete

                          Auto-delete feature allows you to control if your applications should be, by default, automatically deleted after branch merging or deletion.

                          Service List

                          By default the preview environment feature is activated on any services of the environment connected to a git repository. In this sectoin you can decide to activate/desactivate the feature for a specific service.

                          Clone environment

                          Cloning an existing environnment is convenient for those use cases:

                          • Make a demo without impacting the original environment.
                          • Validate a feature on a dedicated environment.

                          Cloning an environment is possible directly from the 3 dots menu of your environment.

                          Environment Clone

                          When cloning an environment, every configuration of the original environment will be copied except for:

                          Terraform exporter

                          You can export the configuration of your environment as a Terraform manifest via the Export as Terraform option. This is helpful when you want to manage your configuration via Terraform: instead of creating the terraform manifest by hand, you can build the setup via the Qovery interface and export is as a Terraform file

                          The export will contain the Terraform definition of the environment, the services within it but as well all the other resources linked to the environment (organization, cluster, project).

                          You can decide wether or not the export should contain or not the secrets defined within the Qovery console.

                          Here's a video explaining how it works:

                          Deploy an environment

                          Have a look at the Deployment Management section for more information on how to deploy your environment.

                          Delete an environment

                          To delete your environment, you must go in the settings > Danger zone and delete your Environment.

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/helm/index.html b/docs/using-qovery/configuration/helm/index.html new file mode 100644 index 0000000000..3259ac9561 --- /dev/null +++ b/docs/using-qovery/configuration/helm/index.html @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + +Helm | Docs | Qovery + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          +

                          Helm

                          A helm is one of the service types that can be deployed within an Environment. Via the helm service you can deploy any helm chart from a git repository or helm repository directly on the kubernetes cluster.

                          Qovery allows you to create and deploy helms from two different sources: Git Repository or Helm Repository

                          Deploying from a Git Repository

                          In this configuration, Qovery will pull the chart from the chosen repository and install it on your kubernetes cluster.

                          Deploying from a Helm Repository

                          In this configuration, Qovery will pull the chosen helm repository a chart and install it on your kubernetes cluster.

                          To improve security and avoid deploying charts from non-authorized repositories, we have decided to restrict the list of Helm Repositories you can use during the setup process. Only an administrator with the right permissions can manage it from the Helm Repository Management page

                          Create a Helm

                          1. Go into the chosen environment and press the "New Service" button and then the "Create helm" button

                          2. Select the following fields:

                            • Helm chart Name: give a name to your helm
                            • Description (Optional): write a text to describe your helm service
                            • Helm chart Source: Chose between Git Repository or Helm Repository, depending on the source location of your application

                            If you want to deploy a helm from a Git Repository you will have to select:

                            • Git Repository: Select the git provider and the git repository hosting your code (it can be hosted on GitHub, GitLab or Bitbucket).
                            • Branch: Select branch that Qovery should use to deploy your helm
                            • Root Helm Path: base folder in which the helm chart resides in your repository

                            If you want to deploy a helm from a Helm Repository you will have to select:

                            • Helm repository: select the helm repository storing the helm chart. Note: only pre-configured registry are available in this list, check the Helm Repository Management page for more information.

                            • Chart name: the name of the helm to be deployed with this application (example: jenkins)

                            • Chart version: the version of the chart to be deployed with this application (example: 1.0.0).

                            • Helm arguments: specify the helm arguments to be used during the helm install/upgrade.

                            • Helm timeout: specify the value to wait for Kubernetes commands to complete. This defaults to 5mins.

                            • Allow cluster-wide resources: Allow this chart to deploy resources outside of the environment namespace. You must have the full-access permissions on the cluster, the right is present by default in Admin, Devops and Owner roles. Example: if you want to create a new CRD or a new ClusterRole, check this flag.

                            Auto Deploy

                            Available only if you have selected a git repository as helm source. +See the Deploying with auto-deploy feature section.

                          3. By default, the values.yaml next to your chart.yaml is used. But you can override it with another file. +Select the following field:

                            • File source: Chose between Git Repository or Raw YAML, depending on the source location of your values file. Git repository source is recommended as the raw yaml is not versioned.

                            If you want to override it from another already existing values file from a Git Repository (it can be the same as the one hosting the helm chart) you will have to select:

                            • Git Repository: Select the git provider and git repository hosting your values override (it can be hosted on GitHub, GitLab or Bitbucket).
                            • Branch: Select branch that Qovery should use to deploy your helm
                            • Overrides path: the path of the values files (example: ci/values_ci.yaml). You can specify multiple paths by separating them with a semi-colon.

                            If you want to override it with a raw yaml you will have to click on Create override. A new editor modal will be opened, to let you write your yaml override. The default values.yaml content will be displayed on the right to help you to respect the structure.

                            You can use the Qovery environment variables as overrides by using the placeholder “qovery.env.<env_var_name>” (Example: qovery.env.DB_URL. Qovery will manage the replacement of those placeholders at deployment time.

                          4. if you want to specify one by one your overrides, you can pass them as arguments. These will be passed to the helm command via the --set, --set-string or --set-json arguments:

                            • Variable: the variable name
                            • Value type:
                              • Select Generic to pass configuration from the command line
                              • Select String if you want to pass a string type (and avoid weird numeric conversions like 021341 interpreted as a number and thus the 0 is removed)
                              • Select Json to set json values (scalars/objects/arrays) from the command line
                            • Value
                          5. You can now expose publicly one or more ports for your services defined in the helm chart by specifying:

                            • Service name: this is the kubernetes service name in your helm chart
                            • Namespace (only if Allow cluster-wide resources was enabled): this is the kubernetes namespace used by your helm chart to deploy the pods behind the chosen service
                            • Service port: this is the port exposed internally by your service
                            • Protocol: you can select the protocol used by your service. Today Qovery supports the following protocols:
                              • HTTPS (Select this protocol if you need to run Websockets)
                              • gRPC
                            • External port: it is the port that can be used to access this service over the internet (when exposed publicly). Note that for HTTP and gRPC the port is set by default to 443.
                            • Port Name: it is the name assigned to the port. When multiple ports are exposed publicly, its value is used to route the traffic to the right port based on the called subdomain (which will contain the port name value). Since each port is exposed on the port 443, having a different subdomain is the only way to have multiple ports exposed over the internet. If not set, the default value is p<portNumber> (see Qovery Provided Domain section for more information)

                            By default services are accessible only from inside your namespace(s). You can expose them publicly, making them accessible over the public network via a dedicated public domain that will be assigned to your application by Qovery during the deployment (See the Qovery Provided Domains section). Note that HTTPS/gRPC ports are always exposed over the port 443.

                            Helm Ports

                            Important Informations

                            • Connections on public ports are automatically closed after 60 seconds. If you want to implement long living connection (like for websockets) please make sure to use the rigth ingress timeouts in the advanced settings section
                          6. You will find a recap of your helm setup and you can now decide to:

                            • Go back to one of the previous steps and change your helm settings (1)
                            • Create your helm without deploying it (2)
                            • Create and deploy your helm (3)

                            Helm

                          Deployment Management

                          Have a look at the Deployment Management section for more information.

                          Configuration

                          Once created, you can access the configuration of a helm at any time via the Settings tab available on the helm section

                          You can find below the description of each of the tabs available in this section

                          General

                          General settings section allows you to set up the name and the source of your helm (git repository or helm repository) .

                          Git Repository

                          If your heml is from a git repository, within this section you can:

                          • Modify the git provider where your code is stored (it can be hosted on GitHub, GitLab or Bitbucket).
                          • Modify the branch that Qovery should use for deploying your application
                          • Modify Root Helm Path - base folder in which the helm chart resides in your repository

                          Helm Repository

                          If your helm is deployed from a helm repository, within this section you can modify:

                          • Helm repository: select the helm repository storing the helm chart. Note: only pre-configured registry are available in this list, check the Helm Repository Management page for more information.
                          • Chart name: the name of the helm to be deployed with this application (example: jenkins)
                          • Chart version: the version of the chart to be deployed with this application (example: 1.0.0).

                          Arguments

                          For both kind of helm source, within this section yoiu can modify:

                          • Helm arguments: specify the helm arguments to be used during the helm install/upgrade.
                          • Helm timeout: specify the value to wait for Kubernetes commands to complete. This defaults to 5mins.

                          Auto Deploy

                          See the Deploying with auto-deploy feature section.

                          Values

                          Within this section you can modify the values override. +Select the following field:

                          • File source: Chose between Git Repository or Raw YAML, depending on the source location of your values file

                          If you want to override it from another already existing values file from a Git Repository you will have to select:

                          • Git Repository: Select the git provider and git repository hosting your code (it can be hosted on GitHub, GitLab or Bitbucket).
                          • Branch: Select branch that Qovery should use to deploy your helm
                          • Overrides path: the path of the values files (example: ci/values_ci.yaml). You can specify multiple paths by separating them with a semi-colon.

                          If you want to override it with a raw yaml you will have to click on Create override. A new editor modal will be opened, to let you write your yaml override. The default values.yaml content will be displayed on the right to help you to respect the structure.

                          Ports

                          Within this section you can define the port exposed publicly. +You can edit the existing ports or declare new ones by specifying:

                          • Service name: this is the kubernetes service name in your helm chart
                          • Namespace (only if Allow cluster-wide resources was enabled): this is the kubernetes namespace used by your helm chart to deploy the pods behind the chosen service
                          • Service port: this is the port exposed internally by your service for the other services
                          • Protocol: you can select the protocol used by your service. Today Qovery supports the following protocols:
                            • HTTPS (Select this protocol if you need to run Websockets)
                            • gRPC
                          • External port: it is the port that can be used to access this service over the internet (when exposed publicly). Note that for HTTP and gRPC the port is set by default to 443.
                          • Port Name: it is the name assigned to the port. When multiple ports are exposed publicly, its value is used to route the traffic to the right port based on the called subdomain (which will contain the port name value). Since each port is exposed on the port 443, having a different subdomain is the only way to have multiple ports exposed over the internet. If not set, the default value is p<portNumber> (see Qovery Provided Domain section for more information)

                          Important Informations

                          • Connections on public ports are automatically closed after 60 seconds. If you want to implement long living connection (like for websockets) please make sure to use the rigth ingress timeouts in the advanced settings section

                          Domains

                          Within this section you can customize the domain used to reach your helm services.

                          You can customize the domain of your helm services in different ways, depending on what you want to achieve:

                          • You want to use your own domain for your helm services
                          • You want to modify the subdomain assigned to your helm services by Qovery (i.e. change p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh into my-app-domain.za8ad0657.bool.sh).

                          In both cases, you can assign the new custom domain to your helm services press the Add Domain button.

                          Application Domains

                          Configuring your own domain

                          Once the domain is added within the Qovery console (Example: mydomain.com), you need to configure within your DNS two CNAME records pointing to the domain provided by Qovery, as shown in the UI (example: mydomain.com CNAME za7cc1b71-z4b8474b3-gtw.zc531a994.rustrocks.cloud and *.mydomain.com CNAME za7cc1b71-z4b8474b3-gtw.zc531a994.rustrocks.cloud).

                          Having a wildcard domain (example: *.mydomain.com) configured on your DNS will avoid you to modify the Qovery setup every time you want to add a new subdomain. If wildcard is not supported by your DNS provider, you will have to configure each subdomain manually.

                          If the service needs to expose more than one port publicly, you can define a dedicated subdomain to redirect the traffic on the right port by setting the “Port Name” value within the port settings.

                          From this point, Qovery will automatically handle the TLS/SSL certificate creation and renewal for the configured domain.

                          Custom Domain

                          Special case - CDN in proxy mode

                          If your service is behind a CDN using a proxy mode (i.e. the traffic is routed through the CDN to Qovery), make sure to disable the option "Generate certificate" on the domain setup. Since the certificate of your domain is directly managed by the CDN, Qovery won't be able to do that for you and it will raise warnings on your application status.

                          CDN Proxy

                          Change the auto assigned sub-domain

                          You can specify a different sub-domain for your helm services as long as it belongs to the assigned cluster domain (see Qovery provided domains). +Example:

                          • your current domain is zdf72de71-z709e1a85-gtw.za8ad0659.bool.sh (so your assigned cluster domain is za8ad0659.bool.sh)
                          • you can enter a new custom domain myfrontend.za8ad0659.bool.sh (since it is a subdomain of the cluster domain)

                          The helm services will now be accessible from both the default and the new custom domain.

                          Connecting from the internet

                          Your helm services can be reached from the internet by publicly exposing at least one of its ports (See the Ports section to know more). Once this is done, Qovery will generate for you a domain to reach your application from the internet. You can also customize the domain assigned to your application and manage by yourself this assignment via the Domain section.

                          Qovery provided domains

                          For each port publicly exposed, a domain is automatically assigned by Qovery to your helm services. Qovery will manage for you the networking and the TLS configuration for these domains.

                          Example: p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh or <service_name>-p80-zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh for helm services.

                          Note:

                          • each service deployed on the same cluster will have the same root domain assigned (example: za8ad0657.bool.sh)
                          • the first characters of the domain (before the -) is based on the portName given to the port associated with this domain (See the port section)
                          • a default domain (without the portName) is assigned to the default port(See the port section). Example zdf72de72-z709e1a88-gtw.za8ad0657.bool.sh

                          Special Case - Preview Environment +For each port exposed publicly, an additional domain will be created with the following pattern portName-prId-srvName-envSourceName.cluster_domain:

                          • portName: is the port name, as explained above
                          • prID: is the id of the PR that has generated the preview environment
                          • srvName: is the name of the service
                          • envSourceName: is the name of the blueprint environment that has created the current preview environment

                          domain example: p80-123-frontend-blueprint.za8ad0657.bool.sh

                          Custom domains

                          If you prefer to assign your own domain to the helm services, have a look at the Domain section to know more.

                          Logs

                          To learn how to display your helm logs, navigate to logs section

                          Clone

                          You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment.

                          Clone Service

                          The target environment can be the same as the current environment or even another one in a completely different project.

                          Important information

                          Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:

                          • same environment:
                            • custom domain: this setup is not copied into the new service (to avoid collision)
                          • another environment:
                            • custom domain: this setup is not copied into the new service (to avoid collision)
                            • environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)
                            • deployment pipeline: stage setup is not copied (since the target stage might not exist)
                            • number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)

                          Please check the configuration of the new service before deploying it.

                          Delete a Helm

                          1. Choose your helm

                          2. In the helm overview, click on the 3 dots button and remove the helm.

                          +
                          + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/using-qovery/configuration/index.html b/docs/using-qovery/configuration/index.html index 9580db7557..5b4f73574c 100644 --- a/docs/using-qovery/configuration/index.html +++ b/docs/using-qovery/configuration/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -
                          +
                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/lifecycle-job/index.html b/docs/using-qovery/configuration/lifecycle-job/index.html index 509910ab17..c00320e76d 100644 --- a/docs/using-qovery/configuration/lifecycle-job/index.html +++ b/docs/using-qovery/configuration/lifecycle-job/index.html @@ -21,36 +21,36 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Lifecycle Job

                          A Lifecycle Job is a job that runs on your kubernetes cluster with the following characteristics:

                          • it is executed ONLY when the selected environment event occurs (unless its execution is forced, see the Force execution section).
                          • any output file created at the end of the execution will be automatically injected as environment variable to any service within the same environment (see the Job Output section).

                          Given its characteristics, lifecycle jobs are particularly useful for:

                          • Seed your database on your preview environment: you can create a custom job that will seed a database when the preview environment is deployed
                          • Create an external resources not natively managed by Qovery: you can create a custom job that will create the external resource. By writing the connection strings in an output file, those information will be injected as environment variables on any service of the environment (so that they can consume this new resource).

                          A lifecycle job can be executed on the following environment events:

                          • Start: the job is executed when the environment starts. Note that a start event is generated on both the "Deploy" and "Redeploy" actions so you should take care of managing this in your code to avoid executing it twice (on the first deploy and on the re-deploy).
                          • Stop: the job is executed when the environment stops.
                          • Delete: the job is executed when the environment is deleted.

                          Qovery allows you to create and deploy jobs from two different sources: Git Repository or Container Registry

                          Deploying from a Git Repository

                          In this configuration, Qovery will pull the code from the chosen repository, build the application and deploy it on your kubernetes cluster.

                          The list of Git repositories available during the setup is strictly tied to the permissions of your git account (by default Qovery can access all your repositories). If you want to restrict the Qovery access only to a few repositories, user the GitHub Qovery Application (only for Github).

                          Deploying from a Container Registry

                          In this configuration, Qovery will pull the chosen container registry an image you have pre-built and deploy it on your kubernetes cluster.

                          To improve the security and avoid deploying images from non-authorized registries, we have decided to restrict the list of Container Registry you can use during the setup process. Only an administrator with the right permissions can manage it from the Container Registry Management page

                          Create a Job

                          1. Go into the chosen environment and press the "New Service" button and then the "Create Lifecycle job" button

                            Creation

                          2. Select the following fields:

                            • Name: give a name to your application
                            • Source: Chose between Git Repository or Container Registry, depending on the source location of your application

                            If you want to deploy a cronjob from a Git Repository you will have to select:

                            • Git Repository: Select the git provider hosting your code (it can be hosted on GitHub, GitLab or Bitbucket).
                            • Branch: Select branch that Qovery should use to deploy your code
                            • Root Application Path: base folder in which the code resides in your repository
                            • Build Mode: only Docker is supported

                            If you want to deploy a job from a Container Registry you will have to select:

                            • Registry: select the container registry storing the image of your job. Note: only pre-configured registry are available in this list, check the Container Registry Management page for more information.
                            • Image name: the name of the image to be deployed with this job (example: postgres)
                            • Image tag: the tag of the image to be deployed with this job (example: 12)

                            Auto Deploy

                            See the Deploying with auto-deploy feature section.

                          3. Specify the configuration of your job:

                            • Event: select the environment event which should trigger the execution of the job (Environment start, stop, delete)
                            • Image Entrypoint: the entrypoint to be used to launch your job (not mandatory).
                            • CMD Arguments: the arguments to be passed to launch your job (not mandatory). We expect the format to be an array. Example ["rails", "-h", "0.0.0.0", "-p", "8080", "string"]
                            • Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure)
                            • Max duration time in seconds: Maximum duration allowed for the job to run before killing it and mark it as failed
                            • Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally
                          4. Within this section, you will need to define the resources to be assigned to your job at run time.
                            • vCPU: the vCPU assigned to each instance of your application. The default is 500m (0.5 vCPU).
                            • RAM: the amount of RAM assigned to each instance of your application. The default is 512MB.
                          5. Define any input variable required by your job to run. Any declared variable will be injected as environment variables based on the selected scope (project, environment, service) +

                            Lifecycle Job

                            A Lifecycle Job is a job that runs on your kubernetes cluster with the following characteristics:

                            • it is executed ONLY when the selected environment event occurs (unless its execution is forced, see the Force execution section).
                            • any output file created at the end of the execution will be automatically injected as environment variable to any service within the same environment (see the Job Output section).

                            Given its characteristics, lifecycle jobs are particularly useful for:

                            • Seed your database on your preview environment: you can create a custom job that will seed a database when the preview environment is deployed
                            • Create an external resources not natively managed by Qovery: you can create a custom job that will create the external resource. By writing the connection strings in an output file, those information will be injected as environment variables on any service of the environment (so that they can consume this new resource).

                            A lifecycle job can be executed on the following environment events:

                            • Start: the job is executed when the environment starts. Note that a start event is generated on both the "Deploy" and "Redeploy" actions so you should take care of managing this in your code to avoid executing it twice (on the first deploy and on the re-deploy).
                            • Stop: the job is executed when the environment stops.
                            • Delete: the job is executed when the environment is deleted.

                            Qovery allows you to create and deploy jobs from two different sources: Git Repository or Container Registry

                            Deploying from a Git Repository

                            In this configuration, Qovery will pull the code from the chosen repository, build the application and deploy it on your kubernetes cluster.

                            The list of Git repositories available during the setup is strictly tied to the permissions of your git account (by default Qovery can access all your repositories). If you want to restrict the Qovery access only to a few repositories, user the GitHub Qovery Application (only for Github).

                            Deploying from a Container Registry

                            In this configuration, Qovery will pull the chosen container registry an image you have pre-built and deploy it on your kubernetes cluster.

                            To improve the security and avoid deploying images from non-authorized registries, we have decided to restrict the list of Container Registry you can use during the setup process. Only an administrator with the right permissions can manage it from the Container Registry Management page

                            Create a Job

                            1. Go into the chosen environment and press the "New Service" button and then the "Create Lifecycle job" button

                              Creation

                            2. Select the following fields:

                              • Name: give a name to your application
                              • Source: Chose between Git Repository or Container Registry, depending on the source location of your application

                              If you want to deploy a cronjob from a Git Repository you will have to select:

                              • Git Repository: Select the git provider hosting your code (it can be hosted on GitHub, GitLab or Bitbucket).
                              • Branch: Select branch that Qovery should use to deploy your code
                              • Root Application Path: base folder in which the code resides in your repository
                              • Build Mode: only Docker is supported

                              If you want to deploy a job from a Container Registry you will have to select:

                              • Registry: select the container registry storing the image of your job. Note: only pre-configured registry are available in this list, check the Container Registry Management page for more information.
                              • Image name: the name of the image to be deployed with this job (example: postgres)
                              • Image tag: the tag of the image to be deployed with this job (example: 12)

                              Auto Deploy

                              See the Deploying with auto-deploy feature section.

                            3. Specify the configuration of your job:

                              • Event: select the environment event which should trigger the execution of the job (Environment start, stop, delete)
                              • Image Entrypoint: the entrypoint to be used to launch your job (not mandatory).
                              • CMD Arguments: the arguments to be passed to launch your job (not mandatory). We expect the format to be an array. Example ["rails", "-h", "0.0.0.0", "-p", "8080", "string"]
                              • Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure)
                              • Max duration time in seconds: Maximum duration allowed for the job to run before killing it and mark it as failed
                              • Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally
                            4. Within this section, you will need to define the resources to be assigned to your job at run time.
                              • vCPU: the vCPU assigned to each instance of your application. The default is 500m (0.5 vCPU).
                              • RAM: the amount of RAM assigned to each instance of your application. The default is 512MB.
                            5. Define any input variable required by your job to run. Any declared variable will be injected as environment variables based on the selected scope (project, environment, service) Any additional environment variable can be added later from the environment variable section

                              Input Variables

                            6. You will find a recap of your job setup and you can now decide to: 1. Go back to one of the previous steps and change your settings 2. Create your job without deploying it @@ -59,27 +59,27 @@ Let's say that the code of our job creates a PostgreSQL RDS on AWS. At the end of its execution, the job should know the connection Once created, the job should know the connection string of the PostgreSQL. The job can now create a file /qovery-output/qovery-output.json with the following structure:

                              {
                              "POSTGRES_DB_HOST": {
                              "sensitive": False,
                              "value": "zf138d9c8-postgresql"
                              },
                              "POSTGRES_DB_USER": {
                              "sensitive": False,
                              "value": "root"
                              },
                              "POSTGRES_DB_PASS": {
                              "sensitive": True,
                              "value": "mypassword"
                              },
                              "POSTGRES_DB_TABLE": {
                              "sensitive": False,
                              "value": "MYDB"
                              },
                              "POSTGRES_DB_PORT": {
                              "sensitive": False,
                              "value": "3600"
                              }
                              }

                              This file will be processed by Qovery and the following environment variables will be created:

                              Var QOVERY_OUTPUT_JOB_<JOBID>_POSTGRES_DB_HOST

                              • Value: "zf138d9c8-postgresql"
                              • Secret: false
                              • Alias: POSTGRES_DB_HOST

                              Var QOVERY_OUTPUT_JOB_<JOBID>_POSTGRES_DB_USER

                              • Value: "root"
                              • Secret: false
                              • Alias: POSTGRES_DB_USER

                              Var QOVERY_OUTPUT_JOB_<JOBID>_POSTGRES_DB_PASS

                              • Value: "mypassword"
                              • Secret: true
                              • Alias: POSTGRES_DB_PASS

                              Var QOVERY_OUTPUT_JOB_<JOBID>_POSTGRES_DB_TABLE

                              • Value: "MYDB"
                              • Secret: false
                              • Alias: POSTGRES_DB_TABLE

                              Var QOVERY_OUTPUT_JOB_<JOBID>_DB_PORT

                              • Value: "3600"
                              • Secret: false
                              • Alias: POSTGRES_DB_PORT

                              Once the execution of the job is terminated and the environment variables are created, any application within the same environment will be able to access those environment variables and thus connect to the postgres instance.

                              Clone

                              You can create a clone of the service via the clone feature. A new service with the same configuration (see below for exceptions) will be created into the target environment.

                              Clone Service

                              The target environment can be the same as the current environment or even another one in a completely different project.

                              Important information

                              Not every configuration parameter will be copied within the new service for consistency reasons. The configuration is fully or partially copied depending on the target environment:

                              • same environment:
                                • custom domain: this setup is not copied into the new service (to avoid collision)
                              • another environment:
                                • custom domain: this setup is not copied into the new service (to avoid collision)
                                • environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)
                                • deployment pipeline: stage setup is not copied (since the target stage might not exist)
                                • number of instances: if the target environment runs on a Qovery EC2 cluster, the max number of instances is set to 1 (Qovery EC2 constraint)

                              Please check the configuration of the new service before deploying it.

                              Delete a job

                              1. Select the job you want to delete

                              2. In the overview, click on the 3 dots button and remove the job. Note: the same option is available on the service list as well

                                Application

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/object-storage/index.html b/docs/using-qovery/configuration/object-storage/index.html index a4296d7134..98f44e2eda 100644 --- a/docs/using-qovery/configuration/object-storage/index.html +++ b/docs/using-qovery/configuration/object-storage/index.html @@ -21,36 +21,36 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Object Storage

                          The default filesystem for applications running on Qovery is ephemeral. Application data isn’t persisted across deploys and restarts, which works just fine for most apps because they use managed databases to persist data. +

                          Object Storage

                          The default filesystem for applications running on Qovery is ephemeral. Application data isn’t persisted across deploys and restarts, which works just fine for most apps because they use managed databases to persist data. If, however, your application needs persistent storage across restarts or needs to store large amounts of data that doesn't really fit well to be stored in databases, Object Storage might fit your needs.

                          Examples of applications:

                          • Music streaming services like Spotify
                          • Photo-heavy apps like Instagram, Facebook
                          • Storing backups/archives over long periods

                          Use cases

                          ✅ Good use cases

                          • Storing large amounts of read-only data
                          • High availability
                          • High scalability
                          • Unstructured data like music, photos, videos
                          • Geographical distribution of data

                          ❌ Bad use cases

                          • For I/O intensive applications (e.g. databases)
                          • Frequent data updates
                          • Temporary files
                          • Transactional data

                          Pros & Cons

                          Pros

                          • Reduce infrastructure costs of storing data
                          • Reduce management time because of the easiness of scalability

                          Cons

                          • Not suited for frequently changing data
                          • Eventual consistency of data might be not enough for certain types of applications that require strong consistency

                          Using Object Storage

                          Using Object Storage with Qovery is very simple. All you need to do is to set up a bucket in the cloud provider of your choice and configure your application to use it using secrets or environment variables.

                          AWS

                          1. Navigate to AWS S3 Console

                          2. Click Create bucket button

                            Storage

                          3. Set up your bucket settings, like name, permissions, cloud region

                          4. Connect your application to your bucket (example using Node.js)

                            // Load dependencies
                            const aws = require('aws-sdk');
                            const express = require('express');
                            const multer = require('multer');
                            const multerS3 = require('multer-s3');
                            const app = express();
                            @@ -64,27 +64,27 @@
                            // Change bucket property to your Bucket name
                            const upload = multer({
                            storage: multerS3({
                            s3: s3,
                            bucket: 'your-bucket-here',
                            acl: 'public-read',
                            key: function (request, file, cb) {
                            console.log(file);
                            cb(null, file.originalname);
                            }
                            })
                            }).array('upload', 1);

                            If your bucket is private, all you need to do is to set up those environment variables for your application:

                            • AWS_ACCESS_KEY_ID
                            • AWS_SECRET_ACCESS_KEY

                            Follow Scaleway guide to get your credentials. You can set up secrets in your application by following our guide.

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/organization/api-token/index.html b/docs/using-qovery/configuration/organization/api-token/index.html index 63e6cccd9d..a94e921e0c 100644 --- a/docs/using-qovery/configuration/organization/api-token/index.html +++ b/docs/using-qovery/configuration/organization/api-token/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          API Token

                          API token allows third-party applications or script to access your organization via the Qovery API (CI/CD, Terraform script, Pulumi etc..).

                          You can manage the API tokens attached to your organization directly from the Qovery console.

                          You can access the token API configuration by opening the Token API section within the organization settings.

                          How to access your organization settings

                          How to access your Token API section

                          Create a new token

                          You can create a new token API by pressing the Add button. You need to provide:

                          • A name
                          • A description
                          • A role: this allows to manage the permission assigned to the new API Token. The permission is managed via the Qovery RBAC system

                          Once validated the token value will be displayed on the interface.

                          Delete a token

                          You can create a new token API by pressing the Bin button next to the Token you want to delete.

                          Edit a token

                          This functionality is not yet available

                          +

                          API Token

                          API token allows third-party applications or script to access your organization via the Qovery API (CI/CD, Terraform script, Pulumi etc..).

                          You can manage the API tokens attached to your organization directly from the Qovery console.

                          You can access the token API configuration by opening the Token API section within the organization settings.

                          How to access your organization settings

                          How to access your Token API section

                          Create a new token

                          You can create a new token API by pressing the Add button. You need to provide:

                          • A name
                          • A description
                          • A role: this allows to manage the permission assigned to the new API Token. The permission is managed via the Qovery RBAC system

                          Once validated the token value will be displayed on the interface.

                          Delete a token

                          You can create a new token API by pressing the Bin button next to the Token you want to delete.

                          Edit a token

                          This functionality is not yet available

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/organization/container-registry/index.html b/docs/using-qovery/configuration/organization/container-registry/index.html index 55e8cf5ebe..acde1e0ddd 100644 --- a/docs/using-qovery/configuration/organization/container-registry/index.html +++ b/docs/using-qovery/configuration/organization/container-registry/index.html @@ -21,60 +21,60 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Container Registry

                          This section allows you to define the list of container registries that can be used within your organization. Only images stored on those container registries are allowed to be deployed on your cluster.

                          You can access this section by opening the Organization Settings -> Container Registries

                          How to access your organization settings

                          Application

                          Create a Container Registry

                          Application

                          By clicking on "Add Registry" you will be able to create a new Container Registry by filling these information:

                          • Registry Name
                          • Description
                          • Registry Url: the base url of the registry (example: https://docker.io, https://public.ecr.aws etc..)
                          • Registry type: you can chose among DockerHub, Public ECR, ECR (AWS private CR), Scaleway CR (Scaleway private CR), Github Packages, Gitlab CR, Generic.
                          • Credentials: these depends on the chosen registry type. If a container registry is public, you don't need to fill this part.

                          Important information:

                          • If you select Docker Hub, we encourage you to set credentials to increase the limits on the pull rate. See here for more details
                          • If the registry you need is not in the list and it supports the docker login format you can use the “Generic” registry.

                          Now that you have created the registry, you can start using it in order to create and deploy a service using the images stored within it.

                          Modify or Delete an existing registry

                          You can modify an existing container registry by clicking on the "Wheel" button next to it -You can delete an existing container registry by clicking on the "Trash" button next to it

                          Application

                          +

                          Container Registry

                          This section allows you to define the list of container registries that can be used within your organization. Only images stored on those container registries are allowed to be deployed on your cluster.

                          You can access this section by opening the Organization Settings -> Container Registries

                          How to access your organization settings

                          Application

                          Create a Container Registry

                          Application

                          By clicking on "Add Registry" you will be able to create a new Container Registry by filling these information:

                          • Registry Name
                          • Description
                          • Registry Url: the base url of the registry (example: https://docker.io, https://public.ecr.aws etc..)
                          • Registry type: you can chose among DockerHub, Public ECR, ECR (AWS private CR), Scaleway CR (Scaleway private CR), Github Packages, Gitlab CR, Generic.
                          • Credentials: these depends on the chosen registry type. If a container registry is public, you don't need to fill this part.

                          Important information:

                          • If you select Docker Hub, we encourage you to set credentials to increase the limits on the pull rate. See here for more details
                          • If the registry you need is not in the list and it supports the docker login format you can use the “Generic” registry.

                          Now that you have created the registry, you can start using it in order to create and deploy a service using the images stored within it.

                          Modify or Delete an existing registry

                          You can modify an existing container registry by clicking on the "Wheel" button next to it +You can delete an existing container registry by clicking on the "Trash" button next to it

                          Application

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/organization/git-repository-access/index.html b/docs/using-qovery/configuration/organization/git-repository-access/index.html index 25aaf1b6bf..aa798704e4 100644 --- a/docs/using-qovery/configuration/organization/git-repository-access/index.html +++ b/docs/using-qovery/configuration/organization/git-repository-access/index.html @@ -21,36 +21,36 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Git Repository access

                          On you first sign in to the Qovery Console, you need to login via your Git provider account. This allows you to manage the access permission within your Qovery organization but it also allows Qovery to access the repositories linked to your Git account.

                          When you create an application on the repository X within the Qovery console, Qovery bounds your git account to the application and creates a webhook on your git repository X to receive the events happening on it (push, PR creation, commit etc..).

                          This is the default behaviour but if you want to manage the permission access in a centralized way and decoupled from the users belonging to your organization, you can instead use the Git Token feature.

                          Git Tokens

                          Git tokens are configured within the Git provider interface and then added to your Qovery organization to manage the access permission to your repositories.

                          In the following sections you will understand how to:

                          • create a token within your git provider
                          • access the token configuration within the Qovery console
                          • add/modify and delete the tokens within the Qovery console

                          Managing tokens on your git provider

                          The process to create a token and the permissions to assign depend on the chosen git provider

                          Github

                          GitHub offers two types of tokens: Personal access tokens (classic) and Fine-grained personal access tokens. You can read more about them and how to create them here.

                          Depending on the selected token type, the required permission is slightly different.

                          Personal access tokens (classic)

                          • Repository: full control of private repositories
                          • Admin:repo_hook: read + write

                          Github Classic

                          Fine-grained Personal access tokens

                          • Contents: Read-only
                          • Webhooks: Read and write
                          • Pull requests: Read and write

                          Github fine grained

                          Gitlab

                          GitLab provides multiple types of tokens but Qovery supports two: Project Tokens and Group Tokens. You can find how to create them within these sections:

                          The permission configuration is the same for the two types:

                          • Role: Maintainer or Owner
                          • scopes: api, read_repository

                          Gitlab token

                          Bitbucket

                          Bitbucket offers two types of tokens: Repository access tokens and Workspace access tokens (only with Bitbucket Cloud Premium plan). You can read more about them and how to create them here:

                          The permission configuration is the same for the two types:

                          • Repositories: Read (Write auto set by Pull requests Write)
                          • Pull requests: Read & Write
                          • Webhooks: Read and write

                          Bitbucket token

                          Token expiration

                          Most of the time, the tokens created within your git provider have an associated expiration date. Once the expiration date is reached, Qovery will lose access to your git account so be sure to renovate your git token before its expiration (usually the git provider sends you a reminder email).

                          If your token reaches its expiration date but your git provider account does not support the expiration date extension, you can: +

                          Git Repository access

                          On you first sign in to the Qovery Console, you need to login via your Git provider account. This allows you to manage the access permission within your Qovery organization but it also allows Qovery to access the repositories linked to your Git account.

                          When you create an application on the repository X within the Qovery console, Qovery bounds your git account to the application and creates a webhook on your git repository X to receive the events happening on it (push, PR creation, commit etc..).

                          This is the default behaviour but if you want to manage the permission access in a centralized way and decoupled from the users belonging to your organization, you can instead use the Git Token feature.

                          Git Tokens

                          Git tokens are configured within the Git provider interface and then added to your Qovery organization to manage the access permission to your repositories.

                          In the following sections you will understand how to:

                          • create a token within your git provider
                          • access the token configuration within the Qovery console
                          • add/modify and delete the tokens within the Qovery console

                          Managing tokens on your git provider

                          The process to create a token and the permissions to assign depend on the chosen git provider

                          Github

                          GitHub offers two types of tokens: Personal access tokens (classic) and Fine-grained personal access tokens. You can read more about them and how to create them here.

                          Depending on the selected token type, the required permission is slightly different.

                          Personal access tokens (classic)

                          • Repository: full control of private repositories
                          • Admin:repo_hook: read + write

                          Github Classic

                          Fine-grained Personal access tokens

                          • Contents: Read-only
                          • Webhooks: Read and write
                          • Pull requests: Read and write

                          Github fine grained

                          Gitlab

                          GitLab provides multiple types of tokens but Qovery supports two: Project Tokens and Group Tokens. You can find how to create them within these sections:

                          The permission configuration is the same for the two types:

                          • Role: Maintainer or Owner
                          • scopes: api, read_repository

                          Gitlab token

                          Bitbucket

                          Bitbucket offers two types of tokens: Repository access tokens and Workspace access tokens (only with Bitbucket Cloud Premium plan). You can read more about them and how to create them here:

                          The permission configuration is the same for the two types:

                          • Repositories: Read (Write auto set by Pull requests Write)
                          • Pull requests: Read & Write
                          • Webhooks: Read and write

                          Bitbucket token

                          Token expiration

                          Most of the time, the tokens created within your git provider have an associated expiration date. Once the expiration date is reached, Qovery will lose access to your git account so be sure to renovate your git token before its expiration (usually the git provider sends you a reminder email).

                          If your token reaches its expiration date but your git provider account does not support the expiration date extension, you can: 1. Create a new token on your git account 2. Modify the existing token on the Qovery console by updating its value with the token created in step 1.

                          Managing the tokens on Qovery

                          Tokens are centrally managed within your organization settings under the Git repository access section:

                          1. Open your Qovery Console and access your organization settings:

                          How to access your organization settings

                          1. In the Organization settings menu, click Git Repositories Access:

                          Git Repositories Access

                          Create the token

                          1. Press the Add new Token button
                          2. Fill the form with:
                          • your git provider
                          • Token name: this is the display name used in every Qovery interface.
                          • Description (optional)
                          • Token Value: the token value as returned by your git provider.
                          • Workspace: Only for bitbucket, provide the workspace where the token has been created.
                          1. Press the Create button.

                          Using the token

                          Once the token is created, you can configure your Qovery services.

                          In the creation flow of your service, you will be able to either select your own git account or one of the git tokens configured within your organization.

                          Git Source Selection

                          If a git token is selected, Qovery will use that token to access the git repository as long as the token does not expire (see the Token expiration section)

                          Update the token

                          1. Press the wheel button on the token you want to modify.
                          2. Modify the token.
                          3. Press the Save button.

                          Note: If you want to modify the git token configured in Qovery, you can directly edit the token value. It will prevent you from manually updating every application using the old token.

                          Delete the token

                          1. Press the bin button next to the token you want to delete
                          2. Confirm the operation by writing delete

                          Deprecated - Qovery Github App

                          For better control, as a GitHub user, you can install the Qovery Github App, and define which Github repositories Qovery can access.

                          Installing the Qovery Github App

                          To install the Qovery Github App:

                          1. Open your Qovery Console and access your organization settings:

                            How to access your organization settings

                          2. In the Organization settings menu, click Git Repository Access:

                            Git Repository Access

                          3. To start the installation process click Install:

                            A new window opens in your browser so you can install the Qovery Github App on your Github account.

                          4. Click the Github account on which you want to install the Qovery Github App:

                            Application

                          5. Click Only select repositories and, in the dropdown menu, define which Github repositories you want to give Qovery access to:

                            Application

                          Managing the Github permissions

                          To add or remove access to one of your repositories:

                          1. Open your Qovery Console and access your organization settings:

                            Qovery - delete organization

                          2. In the Organization settings menu, click Git Permission:

                            Application

                          3. Next to your Git provider account, click Manage permission:

                            Application

                          4. Click the Github account on which you want to manage the Qovery Github App access:

                            Application

                          5. Add or remove the repositories you want to give Qovery access to:

                            Application

                          Uninstalling the Qovery Github App

                          To uninstall the Qovery Github App:

                          1. Open your Qovery Console and access your organization settings:

                            Qovery - delete organization

                          2. In the Organization settings menu, click Git Permission:

                            Application

                          3. Next to your Git provider account, click Disconnect:

                            Application

                            The list of authorized Github repositories is updated, meaning Qovery now has access to all of your Github repositories again.

                          4. From your browser, access your Github account and open your Settings:

                            Application

                          5. In the navigation menu, click Applications:

                            Application

                          6. At the bottom of the page, click Uninstall:

                            Application

                            A confirmation pop-up window opens.

                          7. Click OK:

                            The Qovery Github App is uninstalled.

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/organization/helm-repository/index.html b/docs/using-qovery/configuration/organization/helm-repository/index.html new file mode 100644 index 0000000000..13b0d79c7c --- /dev/null +++ b/docs/using-qovery/configuration/organization/helm-repository/index.html @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + +Helm Repository | Docs | Qovery + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          +

                          Helm Repository

                          This section allows you to define the list of helm repositories that can be used within your organization. Only helm charts stored on those helm repositories are allowed to be deployed on your cluster.

                          You can access this section by opening the Organization Settings -> Helm Repositories

                          How to access your organization settings

                          Helm

                          Create a Helm Repository

                          Helm

                          By clicking on "Add Repository" you will be able to create a new Helm Repository by filling these information:

                          • Repository Name
                          • Description
                          • Kind:
                            • HTTP: for standard helm repository
                            • OCI_ECR: for AWS private OCI-based registries
                            • OCI_SCALEWAY: for Scaleway OCI-based registries
                            • OCI_DOCKER_HUB: for Docker Hub OCI-based registries
                            • OCI_PUBLIC_ECR: for AWS public OCI-based registries
                            • OCI_GENERIC_CR: for Generic OCI-based registries
                            • OCI_GITHUB_CR: for Github OCI-based registries
                            • OCI_GITLAB_CR: for Gitlab OCI-based registries
                          • Repository Url: the url of the repository (example: oci://registry-1.docker.io/repository, https://helm.datadoghq.com etc..)
                          • Credentials: these depend on the chosen repository type. If a helm repository is public, you don't need to fill this part.
                          • Skip TLS verification: to activate the helm argument --insecure-skip-tls-verify

                          Now that you have created the repository, you can start using it in order to create and deploy a helm chart using the images stored within it.

                          Modify or Delete an existing repository

                          You can modify an existing helm repository by clicking on the "Wheel" button next to it +You can delete an existing helm repository by clicking on the "Trash" button next to it

                          Helm

                          +
                          + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/using-qovery/configuration/organization/index.html b/docs/using-qovery/configuration/organization/index.html index 15c039d108..7154a3fb25 100644 --- a/docs/using-qovery/configuration/organization/index.html +++ b/docs/using-qovery/configuration/organization/index.html @@ -21,61 +21,61 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Organization

                          An organization is a shared account where developers can collaborate across many projects at once. Owners and organization administrators +

                          Organization

                          An organization is a shared account where developers can collaborate across many projects at once. Owners and organization administrators can manage every aspect of the organization, from the clusters up to the member access.

                          Creating an Organization

                          When Signing Up

                          When signing up for Qovery, you need to sign in through your Git provider (GitHub, GitLab or Bitbucket).

                          Once this is done, you can create your first organization and the first project within it. Before completing the creation process, you need to choose one of our 3 plans:

                          • Free
                          • Team
                          • Enterprise

                          For more information, see our pricing page.

                          After Signing Up

                          Qovery lets you create as many as you want organizations. Each organization is independent of the others. -To create a new organization:

                          1. Click on your profile icon button on the left navbar.
                          2. Click on the + button in the top right corner of the dropdown.

                          Qovery - create organization after signing up

                          Change an Organization

                          As a user, you can have access to one or many organizations. Use the dropdown on the bottom left of the navbar to change your organization.

                          Qovery - change organization

                          Delete an Organization

                          To delete your organization, you need to go into the Danger Zone within your organization settings.

                          Billing

                          This section allows you to retrieve your invoices and as well manage the credit card used for the payments.

                          Organization admin settings

                          You can access the organization settings using the Wheel button on the left nav bar

                          How to access your organization settings

                          General Information

                          In the General Information tab:

                          • Company name: enter the name of your company.
                          • Description: enter a description of your organization.
                          • Website: enter the website of your company.
                          • Admin contact emails: enter one or several email addresses (separated by commas) on which you want to receive important communications from Qovery.

                          Don't forget to click Update to save your organization information!

                          Other Settings

                          You can find below a dedicated page for each of the admin settings that can be managed within this section.

                          Api token
                          Container registry
                          Git repository access
                          Members rbac
                          +To create a new organization:

                          1. Click on your profile icon button on the left navbar.
                          2. Click on the + button in the top right corner of the dropdown.

                          Qovery - create organization after signing up

                          Change an Organization

                          As a user, you can have access to one or many organizations. Use the dropdown on the bottom left of the navbar to change your organization.

                          Qovery - change organization

                          Delete an Organization

                          To delete your organization, you need to go into the Danger Zone within your organization settings.

                          Billing

                          This section allows you to retrieve your invoices and as well manage the credit card used for the payments.

                          Organization admin settings

                          You can access the organization settings using the Wheel button on the left nav bar

                          How to access your organization settings

                          General Information

                          In the General Information tab:

                          • Company name: enter the name of your company.
                          • Description: enter a description of your organization.
                          • Website: enter the website of your company.
                          • Admin contact emails: enter one or several email addresses (separated by commas) on which you want to receive important communications from Qovery.

                          Don't forget to click Update to save your organization information!

                          Other Settings

                          You can find below a dedicated page for each of the admin settings that can be managed within this section.

                          Api token
                          Container registry
                          Git repository access
                          Helm repository
                          Members rbac
                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/organization/members-rbac/index.html b/docs/using-qovery/configuration/organization/members-rbac/index.html index dbd0411d2e..be975e76ce 100644 --- a/docs/using-qovery/configuration/organization/members-rbac/index.html +++ b/docs/using-qovery/configuration/organization/members-rbac/index.html @@ -21,62 +21,62 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Members and RBAC

                          You can manage from the organization settings the members capable to access your organization and as well their permission via an RBAC system.

                          You can access the organization settings using the Wheel button on the left nav bar

                          How to access your organization settings

                          Organization members

                          This section allows you to manage the members of your organization (add / remove) and as well assign a role to each of them.

                          You can invite someone to join your organization by email. Then he will get access to your projects and will be able to contribute.

                          Qovery - List all members within an organization

                          Roles-Based access control (RBAC)

                          Qovery allows you to control the access to your cluster and environment resources by defining and assigning roles to your users.

                          By default, five roles are created within your organization (Basic Roles):

                          • Owner: the user has full access on the organization
                          • Admin: same as the owner, the has full access to the organization but he cannot delete it
                          • DevOps: the user can manage the organization infrastructure (clusters/registry/webhook setup) and manage the deployments of any environment within the organization.
                          • Billing Manager: the user can only manage the billing of the organization
                          • Viewer: the user has read-only access to any section of the organization

                          More in detail, you can find the associated permissions below:

                          ActionOwnerAdminDevOpsBilling ManagerViewer
                          Read organizationyesyesyesyesyes
                          Edit organizationyesyesnonono
                          Delete organizationyesnononono
                          Manage billingyesyesnoyesno
                          Manage members & rolesyesyesnonono
                          Manage cluster & container registryyesyesyesnono
                          Manage organization setup (webhooks, Git and API tokens etc..)yesyesyesnono
                          Read ANY projectyesyesyesnoyes
                          Edit/Delete ANY projectyesyesnonono
                          Create projectyesyesnonono
                          Read ANY environmentyesyesyesnoyes
                          Edit/Delete ANY environment or serviceyesyesnonono
                          Create environment or serviceyesyesnonono
                          Add/Edit/Delete environment variables and secretsyesyesyesnono
                          Deploy/Stop ANY environment or serviceyesyesyesnono
                          Connect via shell to ANY applicationyesyesyesnono

                          Custom roles

                          If the basic roles are not enough given your internal organization, Qovery allows you to customize the accesses to your clusters, projets and environments by defining Custom Roles.

                          A Custom role allows you to customize:

                          • Cluster Level Permissions: you can specify the access to the existing computing resources (manage cluster X, create environments on cluster Y, read-only access on cluster K)
                          • Project Level Permissions: you can specify the access to the projects and their environments by environment type (deploy type X, create type K etc..)

                          To create a custom role, go in the Roles & Permissions section press "Add new Role"

                          For the new role, you will be able to specify:

                          • The name of the role
                          • A description
                          • Cluster Level permissions
                          • Project Level Permissions

                          Cluster Level Permissions

                          This section allows you to fine tune the access to the computing resources. For each cluster of your organization, you will be able to specify an access permission (ordered by permission level):

                          NamePermission Type
                          Read-OnlyThe user can access the cluster information (name, region etc..). Minimum permission level.
                          Create EnvironmentThe user can create environments on this cluster. Only users with this role could allocate resources for their environments on this cluster. Further environment level permissions (like deployment rights) are managed via the "Project Permissions", see below
                          Full AccessThe user can create create environments on this cluster and as well manage the cluster's settings (start/stop, change number and type of nodes etc..). This permission allows a group of users to manage by themselves a specific cluster
                          • Project Level Permissions +

                            Members and RBAC

                            You can manage from the organization settings the members capable to access your organization and as well their permission via an RBAC system.

                            You can access the organization settings using the Wheel button on the left nav bar

                            How to access your organization settings

                            Organization members

                            This section allows you to manage the members of your organization (add / remove) and as well assign a role to each of them.

                            You can invite someone to join your organization by email. Then he will get access to your projects and will be able to contribute.

                            Qovery - List all members within an organization

                            Roles-Based access control (RBAC)

                            Qovery allows you to control the access to your cluster and environment resources by defining and assigning roles to your users.

                            By default, five roles are created within your organization (Basic Roles):

                            • Owner: the user has full access on the organization
                            • Admin: same as the owner, the has full access to the organization but he cannot delete it
                            • DevOps: the user can manage the organization infrastructure (clusters/registry/webhook setup) and manage the deployments of any environment within the organization.
                            • Billing Manager: the user can only manage the billing of the organization
                            • Viewer: the user has read-only access to any section of the organization

                            More in detail, you can find the associated permissions below:

                            ActionOwnerAdminDevOpsBilling ManagerViewer
                            Read organizationyesyesyesyesyes
                            Edit organizationyesyesnonono
                            Delete organizationyesnononono
                            Manage billingyesyesnoyesno
                            Manage members & rolesyesyesnonono
                            Manage cluster & container registryyesyesyesnono
                            Manage organization setup (webhooks, Git and API tokens etc..)yesyesyesnono
                            Read ANY projectyesyesyesnoyes
                            Edit/Delete ANY projectyesyesnonono
                            Create projectyesyesnonono
                            Read ANY environmentyesyesyesnoyes
                            Edit/Delete ANY environment or serviceyesyesnonono
                            Create environment or serviceyesyesnonono
                            Add/Edit/Delete environment variables and secretsyesyesyesnono
                            Deploy/Stop ANY environment or serviceyesyesyesnono
                            Connect via shell to ANY applicationyesyesyesnono

                            Custom roles

                            If the basic roles are not enough given your internal organization, Qovery allows you to customize the accesses to your clusters, projets and environments by defining Custom Roles.

                            A Custom role allows you to customize:

                            • Cluster Level Permissions: you can specify the access to the existing computing resources (manage cluster X, create environments on cluster Y, read-only access on cluster K)
                            • Project Level Permissions: you can specify the access to the projects and their environments by environment type (deploy type X, create type K etc..)

                            To create a custom role, go in the Roles & Permissions section press "Add new Role"

                            For the new role, you will be able to specify:

                            • The name of the role
                            • A description
                            • Cluster Level permissions
                            • Project Level Permissions

                            Cluster Level Permissions

                            This section allows you to fine tune the access to the computing resources. For each cluster of your organization, you will be able to specify an access permission (ordered by permission level):

                            NamePermission Type
                            Read-OnlyThe user can access the cluster information (name, region etc..). Minimum permission level.
                            Create EnvironmentThe user can create environments on this cluster. Only users with this role could allocate resources for their environments on this cluster. Further environment level permissions (like deployment rights) are managed via the "Project Permissions", see below
                            Full AccessThe user can create create environments on this cluster and as well manage the cluster's settings (start/stop, change number and type of nodes etc..). This permission allows a group of users to manage by themselves a specific cluster
                            • Project Level Permissions This section allows you to fine tune the access to the projects and their environments. The environment access is managed by "Environment Type" to simplify the configuration (Production, Staging, Development, Preview). For each project of your organization and by environment type, you will be able to specify an access permission (ordered by permission level):
                            NamePermission Type
                            No AccessThe user has no access to this environment type. If the user has "No Access" on all the environment types, he will not have access to the project
                            Read-OnlyAccess in read-only to this environment type. Useful to restrict access on sensitive environments
                            DeployManage the deployments of this environment type, access the logs, connect via SSH to the application and manage its environment variables
                            ManageManage the deployments and the settings of this environment type (including adding or removing services)
                            Full AccessThe user is admin of the project and can do everything he wants on it (no matter the environment type)

                            Qovery - custom role

                            Once the role is created, you can assign it to a member of your organization within the "Members" section. You can also update the permissions by editing the role from the Roles&Permissions screen

                            Examples

                            Within this section, we will try to provide you some example of roles & permission setup

                            Example 1, simple setup

                            An organization has 3 clusters ("prod cluster", “staging cluster”, “dev cluster”) and 1 project P1. The organization has a CTO, a devops and some developers. The roles & permissions could be configured in this way:

                            • CTO = Owner
                            • Devops = Devops or Admin
                            • Developers: we want these users capable of accessing the project, having read access to the prod clusters/env, managing deployments on the staging cluster (but not creating new environments on it) and doing whatever they want for the development environments on the dev cluster. So the configuration will look like:
                              • Create a new Role “developer” with the following permissions:
                                • Cluster Level Permissions:
                                  • Prod cluster → Read-Only
                                  • Staging cluster → Read-Only
                                  • Dev cluster → Create Environment (they can create environments on this cluster)
                                • Project Level Permissions for the project "P1":
                                  • Environment access (by env type)
                                    • prod = Read-Only
                                    • staging = deploye (i.e. they can deploy env of type “staging”)
                                    • development = Full Access (i.e. they can manage and create env of type “dev”)

                            Example 2, advanced setup

                            An organization with 4 dev clusters (“prod cluster”, “staging clyster”, 2 Dev clusters called “dev cluster team 1” and "dev cluster team 2”) and 2 projects P1 and P2. The organization has a CTO, a devops, 2 dev teams with an “acting dev-ops” in it who manages the dev cluster on behalf of the devops. The roles & permissions could be configured in this way:

                            • CTO = Owner
                            • Devops = Devops or Admin
                            • Dev team 1: we want these users capable of accessing the project P1, having no access to the prod env and managing their deployments only on the "dev cluster Dev team 1" for their development environments.So the config will look like:
                              • Create a new Role “Dev Team 1”
                                • Cluster Level Permissions:
                                  • Prod cluster → Read-Only
                                  • Staging cluster → Read-Only
                                  • Dev cluster team 1 → Create Environment (they can create envs only on their dev cluster)
                                  • Dev cluster team 2 → Read-Only
                                • Project Level Permissions:
                                  • Config on the project “P1”
                                    • Environment access (by env type)
                                      • prod = no-access
                                      • staging = deploy
                                      • dev = Full Access (i.e. they can do whatever they want on env of type “dev”)
                                  • Config on the project “P2” (i.e. they can't access P2)
                                    • Environment access (by env type)
                                      • prod = no-access
                                      • staging = no-access
                                      • dev = no-access
                            • Dev team 2: we want these users capable of accessing the project P2, having no access to the prod env and managing their deployments only on the "dev cluster team 2" for their development environments. So the config will look like:
                              • Create a new Role “Dev Team 2”
                                • Cluster Level Permissions:
                                  • Prod cluster → Read-Only
                                  • Staging cluster → Read-Only
                                  • Dev cluster team 1 → Read-Only
                                  • Dev cluster team 2 → Create Environment (they can create envs only on their dev cluster)
                                • Project Level Permissions:
                                  • Config on the project “P1” (i.e. they can't access P1)
                                    • Environment access (by env type)
                                      • prod = no-access
                                      • staging = no-access
                                      • dev = no-access
                                  • Config on the project “P2”
                                    • Environment access (by env type)
                                      • prod = no-access
                                      • staging = deploy
                                      • dev = Full Access (i.e. they can do whatever they want on env of type “dev”)
                            • Acting DevOps user: we want this user capable of accessing the project, having read access to the prod env, managing the dev clusters and all the environments on it. So the config will look like this:
                              • Create a new Group “Acting DevOps”
                                • Cluster Level Permissions:
                                  • Prod cluster → Read-Only
                                  • Staging cluster → Create Environment
                                  • Dev1 cluster → Full Access
                                  • Dev2 cluster → Full Access
                                • Project permissions settings
                                  • Config on the project “P1”
                                    • Admin (i.e.: full access to the project)
                                  • Config on the project “P2”
                                    • Admin (i.e.: full access to the project)
                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/project/index.html b/docs/using-qovery/configuration/project/index.html index 479b84a822..5bf929ee62 100644 --- a/docs/using-qovery/configuration/project/index.html +++ b/docs/using-qovery/configuration/project/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Project

                          A project allows you to group together a set of environments with the objective to run the same application (see the Environment page for more information).

                          When creating a new organization, a project is created by default. You can customize the access to your project thanks to our RBAC system.

                          Create a new project

                          If you need to create an additional project, go into the organization settings and press on the NEW button.

                          Project Creation

                          The modal will ask you to provide a name and a description.

                          Edit project general information

                          General information of a project can be updated by:

                          • opening the settings page
                          • selecting the project
                          • opening the GENERAL section.

                          Project Update

                          Delete a project

                          You can delete a project by:

                          • opening the settings page
                          • selecting the project
                          • opening the DANGER section and pressing the Delete Project button.

                          Project Delete

                          +

                          Project

                          A project allows you to group together a set of environments with the objective to run the same application (see the Environment page for more information).

                          When creating a new organization, a project is created by default. You can customize the access to your project thanks to our RBAC system.

                          Create a new project

                          If you need to create an additional project, go into the organization settings and press on the NEW button.

                          Project Creation

                          The modal will ask you to provide a name and a description.

                          Edit project general information

                          General information of a project can be updated by:

                          • opening the settings page
                          • selecting the project
                          • opening the GENERAL section.

                          Project Update

                          Delete a project

                          You can delete a project by:

                          • opening the settings page
                          • selecting the project
                          • opening the DANGER section and pressing the Delete Project button.

                          Project Delete

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/provider/index.html b/docs/using-qovery/configuration/provider/index.html index c03a23f1a5..65a8da9448 100644 --- a/docs/using-qovery/configuration/provider/index.html +++ b/docs/using-qovery/configuration/provider/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          - +
                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/provider/kubernetes/index.html b/docs/using-qovery/configuration/provider/kubernetes/index.html index d870bf8d10..d4bfd0b243 100644 --- a/docs/using-qovery/configuration/provider/kubernetes/index.html +++ b/docs/using-qovery/configuration/provider/kubernetes/index.html @@ -21,36 +21,36 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Kubernetes

                          Qovery Self-Managed or BYOK (Bring Your Own Kubernetes) is a self-hosted version of Qovery. It allows you to install Qovery on your own Kubernetes cluster. +

                          Kubernetes

                          Qovery Self-Managed or BYOK (Bring Your Own Kubernetes) is a self-hosted version of Qovery. It allows you to install Qovery on your own Kubernetes cluster. Read this article to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery Managed/BYOK is for Kubernetes experts who want to manage their own Kubernetes cluster. In this version, Qovery does not manage the Kubernetes cluster for you.

                          This page explains how to install and configure Qovery on your Kubernetes cluster. If you are looking for a quick step-by-step guide, please follow the Kubernetes guide.

                          Components

                          How Qovery works with Self Managed Kubernetes cluster

                          They are two types of components:

                          Qovery components:

                          • Qovery Control Plane: the Qovery Control Plane is the brain of Qovery. It is responsible for managing your applications and providing the API to interact with Qovery.
                          • Qovery Engine: the Qovery Engine is responsible for managing your applications on your Kubernetes cluster. It is installed on your Kubernetes cluster.
                          • Qovery Cluster Agent (optional): the Qovery Cluster Agent is responsible for securely forwarding logs and metrics from your Kubernetes cluster to Qovery control plane.
                          • Qovery Shell Agent (optional): the Qovery Shell Agent is responsible for giving you a secure remote shell access to your Kubernetes pods if you need it. E.g. when using qovery shell command.

                          Third-party components:

                          • NGINX Ingress Controller (optional)
                          • External DNS (optional)
                          • Loki (optional)
                          • Promtail (optional)
                          • Cert Manager (optional)
                          • ...

                          You can chose what you want to install and manage, and you will have a description of what services are usedi, and responsible for. You can disable them if you don't want to use them. And you can even install other components if you want to.

                          What's the requirements?

                          Qovery requires a Kubernetes cluster with the following requirements:

                          • Kubernetes version 1.26 or higher
                          • Helm version 3.0 or higher
                          • 2 CPU
                          • 4 GB RAM
                          • 20 GB disk space
                          • Being able to access to the Internet

                          Install Qovery

                          1. Install Helm command line tool.

                          2. Add Qovery Helm repository.

                            helm repo add qovery https://helm.qovery.com
                            helm repo update
                          3. Login to the Qovery console, create a cluster until it's asked to save informations in the values.yaml file.

                          4. You will find several values.yaml files. Depending on you need, select the one you want and update the configuration accordingly:

                            • values-demo.yaml: this version is to locally test with k3s or minikube
                            • values-<provider-name>.yaml: find versions made for some providers

                            Here is an example of how the chart works:

                            values-demo.yaml
                            ## Services you can enable or disable
                            services:
                            qovery:
                            qovery-cluster-agent:
                            enabled: true
                            qovery-shell-agent:
                            enabled: true
                            qovery-engine:
                            enabled: true
                            ingress:
                            ingress-nginx:
                            enabled: true
                            dns:
                            external-dns:
                            enabled: true
                            logging:
                            loki:
                            enabled: true
                            promtail:
                            enabled: true
                            certificates:
                            cert-manager:
                            enabled: true
                            qovery-cert-manager-webhook:
                            enabled: true
                            cert-manager-configs:
                            enabled: true
                            observability:
                            metrics-server:
                            enabled: true
                            ## Qovery Common config
                            # Past information from Qovery cluster console creation
                            @@ -59,27 +59,27 @@ You'll then be able to later add your custom DNS record (no matter the provider) to point to your Qovery DNS sub-domain.

                            External DNS

                            Here is one example with Qoery DNS provider:

                            external-dns:
                            fullnameOverride: external-dns
                            # set pdns for Qovery DNS managed (or you can use any supported provider by external-dns)
                            provider: pdns
                            # will use the domain name given by Qovery during the cluster setup phease
                            domainFilters: [*domain]
                            # an owner ID is set to avoid conflicts in case of multiple Qovery clusters
                            txtOwnerId: *shortClusterId
                            # a prefix to help Qovery to debug in case of issues
                            txtPrefix: *externalDnsPrefix
                            # set the Qovery DNS provider configuration
                            pdns:
                            apiUrl: *qoveryDnsUrl
                            apiKey: *jwtToken
                            apiPort: 443

                            Logging

                            Qovery uses Loki to store your logs and Promtail to collect your logs.

                            Loki

                            loki:
                            fullnameOverride: loki
                            loki:
                            # no auth is set for internal cluster usage
                            auth_enabled: false
                            ingester:
                            lifecycler:
                            ring:
                            kvstore:
                            # we store it in memory for the demo, you'll lose history once Loki restarts
                            store: inmemory
                            replication_factor: 1
                            schema_config:
                            configs:
                            - from: 2020-05-15
                            store: boltdb-shipper
                            object_store: filesystem
                            schema: v11
                            index:
                            prefix: index_
                            period: 24h
                            monitoring:
                            # all the monitoring part is disabled to reduce resource footprint for the demo usage
                            dashboards:
                            enabled: false
                            rules:
                            enabled: false
                            serviceMonitor:
                            enabled: false
                            metricsInstance:
                            enabled: false
                            selfMonitoring:
                            enabled: false
                            grafanaAgent:
                            installOperator: false
                            grafanaAgent:
                            enabled: false
                            lokiCanary:
                            enabled: false
                            test:
                            enabled: false
                            gateway:
                            enabled: false
                            # we use a single binary to reduce resource footprint for the demo usage
                            singleBinary:
                            replicas: 1
                            persistence:
                            enabled: false
                            extraVolumes:
                            - name: data
                            emptyDir: {}
                            - name: storage
                            emptyDir: {}
                            extraVolumeMounts:
                            - name: data
                            mountPath: /data
                            - name: storage
                            mountPath: /var/loki

                            Promtail

                            promtail:
                            fullnameOverride: promtail
                            # promtail requires to be spawned in kube-system namespace
                            namespace: kube-system
                            priorityClassName: system-node-critical
                            config:
                            clients:
                            # forward logs to Loki
                            - url: *promtailLokiUrl
                            snippets:
                            extraRelabelConfigs:
                            - action: labelmap
                            # required to be able to watch logs from Qovery console interface
                            regex: __meta_kubernetes_pod_label_(qovery_com_service_id|qovery_com_service_type|qovery_com_environment_id)

                            Certificates

                            Qovery uses Cert Manager to automatically get TLS certificates for your applications.

                            Cert Manager

                            cert-manager:
                            fullnameOverride: cert-manager
                            # CRD are required
                            installCRDs: true
                            replicaCount: 1
                            startupapicheck:
                            jobAnnotations:
                            helm.sh/hook: post-install,post-upgrade
                            rbac:
                            annotations:
                            helm.sh/hook: post-install,post-upgrade
                            serviceAccount:
                            annotations:
                            helm.sh/hook: post-install,post-upgrade

                            Qovery Cert Manager Webhook

                            qovery-cert-manager-webhook:
                            fullnameOverride: qovery-cert-manager-webhook
                            certManager:
                            namespace: qovery
                            serviceAccountName: cert-manager
                            secret:
                            apiUrl: *qoveryDnsUrl
                            apiKey: *jwtToken

                            Cert Manager Configs

                            This is the configuration of Cert Manager itself. It is used by all Cert Manager components.

                            cert-manager-configs:
                            fullnameOverride: cert-manager-configs
                            # set pdns to use Qovery DNS provider
                            externalDnsProvider: pdns
                            managedDns: [*domain]
                            acme:
                            letsEncrypt:
                            emailReport: *acmeEmailAddr
                            # As it's a demo cluster, we use the staging environment to avoid rate limit issues
                            acmeUrl: https://acme-staging-v02.api.letsencrypt.org/directory
                            provider:
                            # set the provider of your choice or use the Qovery DNS provider
                            pdns:
                            apiPort: 443
                            apiUrl: *qoveryDnsUrl
                            apiKey: *jwtToken

                            Qovery uses Metrics Server to collect metrics from your Kubernetes cluster and scale your applications automatically based on custom metrics.

                            Observability

                            Metrics Server

                            metrics-server:
                            fullnameOverride: metrics-server
                            defaultArgs:
                            - --cert-dir=/tmp
                            - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
                            - --kubelet-use-node-status-port
                            - --metric-resolution=15s
                            - --kubelet-insecure-tls
                            apiService:
                            create: false

                            FAQ

                            I have a non-covered use case. What should I do?

                            Please contact us. We will be happy to help you.

                            Can I host the Qovery control plane on my own?

                            At the momement, you can't. But please contact us to discuss about it. We will be happy to help you.

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/service-health-checks/index.html b/docs/using-qovery/configuration/service-health-checks/index.html index 17e3cb49cb..00500202f6 100644 --- a/docs/using-qovery/configuration/service-health-checks/index.html +++ b/docs/using-qovery/configuration/service-health-checks/index.html @@ -21,63 +21,63 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          Service Health Checks

                          Health checks are automatic procedures checking the status of your application, deciding if it is ready to receive traffic or if it needs to be restarted. Since Qovery relies on Kubernetes to deploy and run your application, we use the Kubernetes probes to regularly verify the status of your application during the deployment and/or running phases.

                          Kubernetes allows you to configure two probes:

                          • Liveness probe: to check if the application container is alive (passing) or dead (failing). If the check fails, the dead container is restarted to attempt to heal the application. For example, liveness probes could catch a deadlock, where an application is running, but unable to make progress. Restarting a container in such a state can help to make the application more available despite bugs.
                          • Readiness probe: to check if the application container is ready to receive requests (as even alive containers can enter phases where they cannot handle incoming traffic). Kubernetes only routes traffic to the application if the check succeeds. One use of this signal is to control which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balancers.

                          Kubernetes Probes Workflow

                          During the deployment phase, the liveness and readiness probes play an important role on determining if the deployment succeeds or not. If you have both the liveness and readiness probes configured, both of them need to succeed before considering the deployment to be completed successfully.

                          Example: +

                          Service Health Checks

                          Health checks are automatic procedures checking the status of your application, deciding if it is ready to receive traffic or if it needs to be restarted. Since Qovery relies on Kubernetes to deploy and run your application, we use the Kubernetes probes to regularly verify the status of your application during the deployment and/or running phases.

                          Kubernetes allows you to configure two probes:

                          • Liveness probe: to check if the application container is alive (passing) or dead (failing). If the check fails, the dead container is restarted to attempt to heal the application. For example, liveness probes could catch a deadlock, where an application is running, but unable to make progress. Restarting a container in such a state can help to make the application more available despite bugs.
                          • Readiness probe: to check if the application container is ready to receive requests (as even alive containers can enter phases where they cannot handle incoming traffic). Kubernetes only routes traffic to the application if the check succeeds. One use of this signal is to control which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balancers.

                          Kubernetes Probes Workflow

                          During the deployment phase, the liveness and readiness probes play an important role on determining if the deployment succeeds or not. If you have both the liveness and readiness probes configured, both of them need to succeed before considering the deployment to be completed successfully.

                          Example: You have a liveness probe configured on port 80 of your application. If during the deployment of your application the probes can't connect to port 80 and we reach a timeout, the deployment fails.

                          Qovery allows you to manage these probes directly from within the Qovery console during the setup of your application, letting you decide their activation, configuration and check frequency.

                          Probes can be configured for:

                          • Applications
                          • Cronjobs
                          • Lifecycle Jobs

                          Probes Configuration

                          The following configuration parameters are valid for both the Liveness and the Readiness probes.

                          Type

                          Allows you to specify the type of probe you want to run against your application:

                          • NONE if NONE is selected, the probe is disabled and thus Kubernetes won't be able to verify the state of your application and take the right corrective actions.
                          • HTTP probes are the most common probe type. You can use them if your application is a HTTP server, or if you create a lightweight HTTP server inside your application specifically to respond to such probes. When using a HTTP probe, you need to configure:

                            • a port
                            • a path Once configured, Kubernetes pings a path (for example: /healthz ) at a given port. If it gets a response in the 200 or 300 range, the check is passed. Otherwise, it is considered as failed and Kubernetes takes the necessary corrective actions.
                          • TCP probes are most often used when HTTP or command probes aren't an option. When using a TCP Liveness probe, Kubernetes tries to establish a connection on the specified port. If the connection is successful, the application is considered healthy. Otherwise, it is considered dead and the container is restarted.

                          • gRPC probes When using a gRCP Liveness probe, Kubernetes tries to establish a connection on the specified port and service. If the connection is successful, the application is considered healthy. Otherwise, it is considered dead and the container is restarted.

                          • EXEC probes Exec probes allow to define a command to be executed within your container. If the command execution fails, the probe is considered as failed.

                          Initial Delay (in seconds)

                          Allows you to specify an interval, in seconds, between the application container start and the first liveness check.

                          Allowing additional time for the application to start can be useful when boot time usually takes too long (due to long boot operations), or when the application opens the port before being ready to receive traffic on it (due to a still ongoing boot operation).

                          Period (in seconds)

                          Allows you to specify an interval, in seconds, between each probe.

                          Timeout (in seconds)

                          Allows you to specify the interval, in seconds, after which the probe times out.

                          Success Threshold

                          Allows you to specify how many consecutive successes are needed, as a minimum, for the probe to be considered successful after having failed previously.

                          Failure Threshold

                          Allows you to specify how many consecutive failures are needed, as a minimum, for the probe to be considered failed after having succeeded previously.

                          Configuiration for Long-starting application

                          If your application has a long boot operation to run, your deployment might be marked as failed since the probe can't verify the state of your application within the specified time frame. In this case, you will find in your deployment logs a warning message Liveness probe failed: dial tcp xx.xx.xx.xx:xx: connect: connection refused , telling you that the probe is failing.

                          If your application needs more time to boot, increase the Initial Delay in seconds of the probes to match the application boot time.

                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/user-account/index.html b/docs/using-qovery/configuration/user-account/index.html index 71e236de73..c56f3309fa 100644 --- a/docs/using-qovery/configuration/user-account/index.html +++ b/docs/using-qovery/configuration/user-account/index.html @@ -21,61 +21,61 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                          -

                          User Account

                          You can manage a few settings linked to your account from the User Account section.

                          To access this section, you have to: +

                          User Account

                          You can manage a few settings linked to your account from the User Account section.

                          To access this section, you have to: 1. click on the user icon on the bottom left side 2. click on your user

                          Access user account

                          General account settings

                          This section shows you some basic information about your account like:

                          • First name: retrieved from your git account, it can't be changed.
                          • Last name: retrieved from your git account, it can't be changed.
                          • Account email: retrieved from your git account, it can't be changed.
                          • Communication email: this email will be used by Qovery to communicate you any update or issue ongoing on the product. Make sure to set the communication email with a valid email adress
                          Resources
                            - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/deployment/deploying-with-auto-deploy/index.html b/docs/using-qovery/deployment/deploying-with-auto-deploy/index.html index ef2bb3f244..02638439e4 100644 --- a/docs/using-qovery/deployment/deploying-with-auto-deploy/index.html +++ b/docs/using-qovery/deployment/deploying-with-auto-deploy/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                            -

                            Deploying with the auto-deploy feature

                            Once you have configured your services and deployed them for the first time, you can decide to automatically update the applications to the latest version of your git branch thanks to the auto-deploy feauture.

                            Each time a commit is pushed on your git repository, Qovery receives a webhook call containing the commit information (who did it, what changed, which branch etc..). Thanks to this information, Qovery is able to determine which application should be automatically re-deployed with the new version.

                            How to activate it

                            The auto-deploy feature can be activated from the application settings, by switching on the auto-deploy flag.

                            Auto-deploy settings

                            It can also be activated on the first step of the service creation flow

                            Auto-deploy creation flow

                            Once this flag is activated, every new commit pushed on the branch of the application will trigger an automatic deployment of the new version.

                            Auto-deploy and container images

                            The auto-deploy feature can be activated as well if you directly deploy your container images but it requires some additional integration via your CI/CD. Your CI/CD has to inform Qovery that a new version of the image (a new tag) is available for a specific container image. Thanks to this information, Qovery can find any application that uses this container image and automatically trigger a deployment of the new image tag.

                            To inform Qovery of the new version, your CI/CD needs to call the following endpoints, depending on the service type:

                            +

                            Deploying with the auto-deploy feature

                            Once you have configured your services and deployed them for the first time, you can decide to automatically update the applications to the latest version of your git branch thanks to the auto-deploy feauture.

                            Each time a commit is pushed on your git repository, Qovery receives a webhook call containing the commit information (who did it, what changed, which branch etc..). Thanks to this information, Qovery is able to determine which application should be automatically re-deployed with the new version.

                            How to activate it

                            The auto-deploy feature can be activated from the application settings, by switching on the auto-deploy flag.

                            Auto-deploy settings

                            It can also be activated on the first step of the service creation flow

                            Auto-deploy creation flow

                            Once this flag is activated, every new commit pushed on the branch of the application will trigger an automatic deployment of the new version.

                            Auto-deploy and container images

                            The auto-deploy feature can be activated as well if you directly deploy your container images but it requires some additional integration via your CI/CD. Your CI/CD has to inform Qovery that a new version of the image (a new tag) is available for a specific container image. Thanks to this information, Qovery can find any application that uses this container image and automatically trigger a deployment of the new image tag.

                            To inform Qovery of the new version, your CI/CD needs to call the following endpoints, depending on the service type:

                            - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/deployment/deploying-with-ci-cd/index.html b/docs/using-qovery/deployment/deploying-with-ci-cd/index.html index 8460c6291c..50de16b829 100644 --- a/docs/using-qovery/deployment/deploying-with-ci-cd/index.html +++ b/docs/using-qovery/deployment/deploying-with-ci-cd/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                            -

                            Deploying with your CI/CD

                            Once you have configured your environments and services, you can decide to manage the deployments via the UI or directly from your CI/CD.

                            You can find more information on how to integrate your CI/CD within this section.

                            Resources
                              +

                              Deploying with your CI/CD

                              Once you have configured your environments and services, you can decide to manage the deployments via the UI or directly from your CI/CD.

                              You can find more information on how to integrate your CI/CD within this section.

                              Resources
                                - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/deployment/deployment-actions/index.html b/docs/using-qovery/deployment/deployment-actions/index.html index e033de492c..4c3093c957 100644 --- a/docs/using-qovery/deployment/deployment-actions/index.html +++ b/docs/using-qovery/deployment/deployment-actions/index.html @@ -21,62 +21,62 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                -

                                Deployment Actions

                                Qovery allows you to manage the deployment lifecycle of your services and environments via a set of Deployment actions (example: deploy, redeploy, restart, stop etc..). These actions can be triggered via the Qovery web console, via the Qovery API, via the Qovery CLI or from your CI/CD depending on your integration type.

                                You can imagine the deployment lifecycle of a service or environment like a state machine:

                                • each state is identified by a Deployment Status
                                • the execution of a deployment action will modify the state of the service/environment until it reaches a final status (ok or error)
                                • the list of allowed Deployment action depends on the current Deployment Status. Example: if the deployment status is Deployment Ok, you can trigger only the action Stop. This will stop the execution of the service (deployment status Stopped).

                                Example: +

                                Deployment Actions

                                Qovery allows you to manage the deployment lifecycle of your services and environments via a set of Deployment actions (example: deploy, redeploy, restart, stop etc..). These actions can be triggered via the Qovery web console, via the Qovery API, via the Qovery CLI or from your CI/CD depending on your integration type.

                                You can imagine the deployment lifecycle of a service or environment like a state machine:

                                • each state is identified by a Deployment Status
                                • the execution of a deployment action will modify the state of the service/environment until it reaches a final status (ok or error)
                                • the list of allowed Deployment action depends on the current Deployment Status. Example: if the deployment status is Deployment Ok, you can trigger only the action Stop. This will stop the execution of the service (deployment status Stopped).

                                Example: When a new application is created within Qovery, the application will have the deployment status Ready. Once the action Deploy is executed on the service, the service will go through the statuses Queued, Building, Deploying and then finally on the status Deployed (meaning that the application is correctly deployed).

                                You can find the deployment status directly in the Qovery console in the service or environment list:

                                Deployment Statuses

                                Note that the deployment status of the environment is built based on the deployment statuses of each service within it.

                                You can decide to execute a deployment action on:

                                • an environment: the action will be executed on each service within the environment. To know more about the deployment order of your services, have a look at the Deployment Pipeline
                                • a single service: the action will be executed only on the selected service.

                                The deployment actions are accessible through the Play button available at service or environment level.

                                Deployment Actions

                                You can trigger the deployment actions via the UI but also via any interface described within this section.

                                Deployment Actions

                                You can find below a description of each deployment action, including its purpose and the deployment status your environment and/or service will go through.

                                Deploy

                                The Deploy action allows you to create the resource necessary to run your code on your Kubernetes cluster. This action is available only if the service or environment have never been deployed.

                                Based on the configuration of your services within, a certain number of Pods will be created in a dedicated Namespace of the target Kubernetes cluster.

                                Once triggered, the deployment of a service goes through the following deployment statuses:

                                • QUEUED : the deployment has been queued and it is waiting for the necessary resources to be allocated to manage your request
                                • BUILDING : the Qovery engine is downloading the git repository and building your code. At the end of this step an image is built and pushed to a registry available on your cloud account. The status will become BUILD ERROR in case of issues on building your code
                                • DEPLOYING : the pods are being created on your cluster based on the image built on the previous step. The status will become DEPLOYMENT ERROR in case of issues on deploying your service. A service is considered un-healthy if the Kubernetes readiness probe check is never OK (more info on readiness probe).
                                • DEPLOYMENT OK : all the requested pods have been created and the service is correctly running (liveness and readiness probes are ok).

                                If the deployment was triggered on the entire environment, the environment will go through the following deployment statuses:

                                • QUEUED : at least one service is in status QUEUED
                                • BUILDING : at least one service is in status BUILDING
                                • DEPLOYING : at least one service is in status DEPLOYING
                                • DEPLOYMENT OK : at least one service is in status DEPLOYMENT OK but none of them is in error (BUILD ERROR or DEPLOYMENT ERROR)
                                • DEPLOYMENT ERROR : at least one service is in status DEPLOYMENT ERROR

                                Redeploy

                                The Redeploy action allows you to update the remote configuration of your services based on their configuration on Qovery side. If any difference exists (vCPU, number of instances, code version etc..), a new set of pod will be created with the new configuration and replace the existing ones. If there are no configuration differences, nothing will happen on the pods running on your cluster (not even a restart, please use the Restart Service feature). This action is available only if the Deploy action has been triggered at least once on the service or environment.

                                When replacing the pods of your application, Qovery uses the rolling-restart deployment logic:

                                1) Deploy new version of instance #1.

                                2) New version of instance #1 is running => kill previous version of instance #1.

                                3) Deploy new version of instance #2.

                                4) New version of instance #2 is running => kill previous version of instance #2.

                                And so on...

                                You can trigger the re-deployment of a service or of the entire environment. The service or environment goes through the same deployment statuses described in the deployment section.

                                Stop

                                The Stop action allows you to stop the execution on the cluster of the selected service or environment (deployment status = Stopped). This action is available only if the current deployment status is Deployment OK or Deployment Error.

                                The effect on your cluster of the stop operation is different depending on the type of service:

                                • Application, Container, Container DB : Pods of those services are stopped. Any attached storage is preserved
                                • Cloud provider Managed DB: the database is paused (only for AWS, not working on Redis)

                                Restart Service

                                The Restart Service action allows you to restart the pods of your service without applying any configuration change. This action is available only if the current deployment status is Deployment OK and only for a single service.

                                Once triggered, the deployment status service goes through the following statuses:

                                • RESTARTING : the request to restart has been received
                                • RESTARTED : all the pods of the service have been restarted
                                • RESTART ERROR : Qovery couldn't process the restart request

                                Cancel Deployment

                                The Cancel Deployment action allows you to abort any Deploy or Redeploy action. This action is available only if the current deployment status is Queued or Building or Deploying.

                                Deploy other version

                                The Deploy other version action allows you to deploy a different version for your service. This action is available no matter the deployment status of the service.

                                Once you click on the action, this panel will appear, and you will be able to choose the version you wish to update/rollback (either git commit or image Tag).

                                Deploy Other Version

                                By pressing on the Deploy button, a deployment of the service will be triggered using the selected version.

                                Deploy latest version

                                The Deploy latest version action allows you to deploy the latest version for any of your services within the environment. This action is available no matter the deployment status of the service and only at environment level

                                Once you click on the action, this panel will appear, and you will be able to choose the services you wish to update to the latest version (only for services with source = git repository).

                                Deploy Latest Version

                                By pressing on the Deploy button, a deployment of the service will be triggered using the selected version.

                                - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/deployment/deployment-history/index.html b/docs/using-qovery/deployment/deployment-history/index.html index 0254792704..3c8ee82ee9 100644 --- a/docs/using-qovery/deployment/deployment-history/index.html +++ b/docs/using-qovery/deployment/deployment-history/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                -

                                Deployment History

                                You can access the deployments history of your environment or service by opening the Deployments tab on either the environment or service page.

                                Deployment history access

                                For each deployment triggered in the past, you will find

                                • The execution id: an internal id assigned to each deployment. You can share this id with the Qovery team in case of errors in one of your deployments
                                • Each service that has been deployed during this deployment together with their deployment status and the version that has been deployed
                                Resources
                                  +

                                  Deployment History

                                  You can access the deployments history of your environment or service by opening the Deployments tab on either the environment or service page.

                                  Deployment history access

                                  For each deployment triggered in the past, you will find

                                  • The execution id: an internal id assigned to each deployment. You can share this id with the Qovery team in case of errors in one of your deployments
                                  • Each service that has been deployed during this deployment together with their deployment status and the version that has been deployed
                                  Resources
                                    - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/deployment/deployment-pipeline/index.html b/docs/using-qovery/deployment/deployment-pipeline/index.html index 8fd71b9094..34f6676983 100644 --- a/docs/using-qovery/deployment/deployment-pipeline/index.html +++ b/docs/using-qovery/deployment/deployment-pipeline/index.html @@ -21,60 +21,60 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                    -

                                    Deployment Pipeline

                                    When the deployment of an environment is triggered, Qovery executes what we call Deployment Pipeline. It basically defines the operations shall be performed to properly deploy every service defined within your environment (build the code of service X, push the image on a registry, deploy service X on the Kubernetes cluster etc..)

                                    A pipeline is composed of an ordered list of Deployment Stages. Each Stage has an execution order assigned within the pipeline: If a stage A has an execution order lower than stage B then B can be executed only if the execution of stage A is completed.

                                    Each service of your environment belongs to one (and only one) Deployment Stage. This allows you to define at which moment of the deployment pipeline a service should be deployed and thus respect any service inter-dependency (e.g. your front-end needs to be started after the back-end, your db needs to be started before your back-end etc..).

                                    Below you can find a visual example of how the pipeline looks like:

                                    Deployment Pipeline

                                    Deployment of a stage

                                    When the deployment pipeline execute the deployment of a stage, the services within it will go through the Build and Deployment phases.

                                    The Building process is managed by the Qovery CI which downloads your repository and generates the final image that will be run on your Kubernetes cluster.

                                    The build and deploy operation of each service within a deployment stage are executed in parallel with a parallism of 4.

                                    Example +

                                    Deployment Pipeline

                                    When the deployment of an environment is triggered, Qovery executes what we call Deployment Pipeline. It basically defines the operations shall be performed to properly deploy every service defined within your environment (build the code of service X, push the image on a registry, deploy service X on the Kubernetes cluster etc..)

                                    A pipeline is composed of an ordered list of Deployment Stages. Each Stage has an execution order assigned within the pipeline: If a stage A has an execution order lower than stage B then B can be executed only if the execution of stage A is completed.

                                    Each service of your environment belongs to one (and only one) Deployment Stage. This allows you to define at which moment of the deployment pipeline a service should be deployed and thus respect any service inter-dependency (e.g. your front-end needs to be started after the back-end, your db needs to be started before your back-end etc..).

                                    Below you can find a visual example of how the pipeline looks like:

                                    Deployment Pipeline

                                    Deployment of a stage

                                    When the deployment pipeline execute the deployment of a stage, the services within it will go through the Build and Deployment phases.

                                    The Building process is managed by the Qovery CI which downloads your repository and generates the final image that will be run on your Kubernetes cluster.

                                    The build and deploy operation of each service within a deployment stage are executed in parallel with a parallism of 4.

                                    Example If you have 6 applications to be deployed within a stage, Qovery will:

                                    • build 4 applications in parallel. Once the build of one application is terminated, Qovery will start immediately another one until all the applications are built.
                                    • deploy 4 applications in parallel on your Kubernetes cluster. Once the deployment of one application is terminated, Qovery will start immediately another one until all the applications are deployed.

                                    Default Pipeline Setup

                                    By default, the deployment pipeline is constituted of 4 deployment stages with a default service assignment rule:

                                    • "0.DEFAULT DATABASE": any new service of type DATABASE will be added to this stage.
                                    • "1.DEFAULT JOB": any new service of type JOB will be added to this stage.
                                    • "2.DEFAULT CONTAINER": any new service of type CONTAINER will be added to this stage (application deployed from a container image).
                                    • "3.DEFAULT APPLICATION": any new service of type APPLICATION will be added to this stage (application deployed from a git repository).

                                    Default Deployment Pipeline

                                    Once the service is created, the assigned stage can be modified afterwards. See this section for more information.

                                    Visualizing and Modifying the Pipeline

                                    You can access and modify the pipeline configuration from the environment settings. Have a look at this section to know more.

                                    - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/deployment/deployment-strategies/index.html b/docs/using-qovery/deployment/deployment-strategies/index.html index 2c2f417a4d..c2ae99e9d6 100644 --- a/docs/using-qovery/deployment/deployment-strategies/index.html +++ b/docs/using-qovery/deployment/deployment-strategies/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                    -

                                    Deployment Strategies

                                    Qovery supports 2 ways of application deployment:

                                    • RollingUpdate (default): Qovery will gracefully rollout new versions. It will automatically rollback if the new version fails to start | Useful to avoid downtime and load spikes during update
                                    • Recreate: Qovery will stop all current versions and create new ones once all old ones have been shutdown.

                                    To make it more clear, here is a representation of the 2 strategies. First and default one, the RollingUpdate strategy:

                                    Rolling update strategy

                                    And Recreate deployment strategy:

                                    Recreate strategy

                                    Resources
                                      +

                                      Deployment Strategies

                                      Qovery supports 2 ways of application deployment:

                                      • RollingUpdate (default): Qovery will gracefully rollout new versions. It will automatically rollback if the new version fails to start | Useful to avoid downtime and load spikes during update
                                      • Recreate: Qovery will stop all current versions and create new ones once all old ones have been shutdown.

                                      To make it more clear, here is a representation of the 2 strategies. First and default one, the RollingUpdate strategy:

                                      Rolling update strategy

                                      And Recreate deployment strategy:

                                      Recreate strategy

                                      Resources
                                        - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/deployment/image-mirroring/index.html b/docs/using-qovery/deployment/image-mirroring/index.html index fb19726d07..7b0046f062 100644 --- a/docs/using-qovery/deployment/image-mirroring/index.html +++ b/docs/using-qovery/deployment/image-mirroring/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                        -

                                        Image Mirroring

                                        When a cluster is deployed on your cloud account, a dedicated image registry is created to serve as a mirroring system.

                                        This mirroring registry is also available within the Qovery interface

                                        Mirroring Registry

                                        How does it work

                                        Every time an application needs to be deployed on your cluster, the application image is mirrored on the mirroring registry.

                                        Application built via the Qovery pipeline

                                        Images within the mirroring registry are organized by "Qovery service", each service has its own repository (or namespace, naming depends on the cloud provider). This means that each service build and mirroring process is completely isolated from the others.

                                        Before building the application A1, Qovery checks within mirroring registry at the repository of the application A1 if an image has already being built with the same version (commit id and environment variables).

                                        If the image already exists, the built is skipped and Qovery starts the deployment of that image on the Kubernetes cluster.

                                        Otherwise, the image is built by the Qovery pipeline the resulting image is pushed on the mirroring registry at the repository of the application A1, deleting any previous image.

                                        Mirroring built image

                                        Given this isolation mechanism, if the same application is cloned (via the clone or preview environment feature), Qovery will re-build the application since the environment variables have changed (the ones at environment level).

                                        Application deployed from a container registry

                                        The Qovery behaviour in this case will depend on the chosen mirroring mode within the cluster advanced settings.

                                        Two mirroring modes are available when deploying a service from a container registry:

                                        Service (Default)

                                        Images within the mirroring registry are organized by "Qovery service", each service has its own repository (or namespace, naming depends on the cloud provider). This means that each service mirroring process is completely isolated from the others.

                                        At the beginning of the deployment of the application A1, Qovery checks within mirroring registry at the repository of the application A1 if an image with the same image name and tag exists.

                                        If the image already exists, the mirroring process is skipped and Qovery starts the deployment of that image on the Kubernetes cluster.

                                        Otherwise, the image is pulled from the source registry and pushed on the mirroring registry at the repository of the application A1, deleting any previous image.

                                        Mirroring image from registry - Service case

                                        Pro:

                                        • Images are automatically deleted when not needede anymore

                                        Cons:

                                        • If the same image is used across environments or service, Qovery will mirror multiple time the same image, reducing the deployment speed

                                        Cluster

                                        Images within the mirroring registry are organized by "Qovery cluster", meaning that the application deployed on the same cluster are all mirrored on the same repository.

                                        At the beginning of the deployment of the application A1, Qovery checks within mirroring registry at the repository of the cluster C1 if an image with the same image name and tag exists.

                                        If the image already exists, the mirroring process is skipped and Qovery starts the deployment of that image on the Kubernetes cluster.

                                        Otherwise, the image is pulled from the source registry and pushed on the mirroring registry at the repository of the cluster C1.

                                        Mirroring image from registry - Cluster case

                                        Pro:

                                        • If the same image is used across environments or service, this setup will avoid to mirror multiple time the same image, increasing the deployment speed.

                                        Cons:

                                        • Qovery can't automatically delete the images mirrored on the mirroring registry. This will increase the cloud provider cost of your image registry since it will store more data. To reduce the amount data stored you can reduce the image TTL via the cluster advanced settings registry.image_retention_time

                                        Why image mirroring is necessary

                                        Image mirroring is a general best practice: you don't want your system to be strictly coupled on a third party.

                                        Let's say that you run an application on your production environment and Kubernetes needs to pull again the image to spawn a new instance for the application. In this case, you don't want to make this fail due to the unavailability of your source container registry. This is why we make sure that a copy is always available on the container registry next to the Kubernetes cluster.

                                        Why unique image tags are necessary

                                        When working with containerized applications, it is crucial to employ unique image tags for precise version management. This practice ensures complete confidence in the version running within a container. Failing to use unique image tags can lead to adverse consequences due to the image caching mechanisms employed by both the Qovery mirroring system and Kubernetes:

                                        • Mirroring Registry: Qovery’s mirroring system stores images in a registry. If an image tag remains the same between two versions, the new version will not be mirrored. Consequently, the new version will not be deployed, affecting the overall application.
                                        • Kubernetes: Applications deployed by Qovery on Kubernetes adhere to the “ifNotPresent” image pull policy. This policy means that if the image already exists on the Kubernetes node’s local disk, Kubernetes will not attempt to pull it again. However, if the image tag remains unchanged, the new image version will not be fetched, resulting in your pods running the outdated application code.

                                        In summary, maintaining unique image tags is a critical aspect of effective version control and ensuring that your applications run the intended versions without disruptions caused by caching mechanisms.

                                        +

                                        Image Mirroring

                                        When a cluster is deployed on your cloud account, a dedicated image registry is created to serve as a mirroring system.

                                        This mirroring registry is also available within the Qovery interface

                                        Mirroring Registry

                                        How does it work

                                        Every time an application needs to be deployed on your cluster, the application image is mirrored on the mirroring registry.

                                        Application built via the Qovery pipeline

                                        Images within the mirroring registry are organized by "Qovery service", each service has its own repository (or namespace, naming depends on the cloud provider). This means that each service build and mirroring process is completely isolated from the others.

                                        Before building the application A1, Qovery checks within mirroring registry at the repository of the application A1 if an image has already being built with the same version (commit id and environment variables).

                                        If the image already exists, the built is skipped and Qovery starts the deployment of that image on the Kubernetes cluster.

                                        Otherwise, the image is built by the Qovery pipeline the resulting image is pushed on the mirroring registry at the repository of the application A1, deleting any previous image.

                                        Mirroring built image

                                        Given this isolation mechanism, if the same application is cloned (via the clone or preview environment feature), Qovery will re-build the application since the environment variables have changed (the ones at environment level).

                                        Application deployed from a container registry

                                        The Qovery behaviour in this case will depend on the chosen mirroring mode within the cluster advanced settings.

                                        Two mirroring modes are available when deploying a service from a container registry:

                                        Service (Default)

                                        Images within the mirroring registry are organized by "Qovery service", each service has its own repository (or namespace, naming depends on the cloud provider). This means that each service mirroring process is completely isolated from the others.

                                        At the beginning of the deployment of the application A1, Qovery checks within mirroring registry at the repository of the application A1 if an image with the same image name and tag exists.

                                        If the image already exists, the mirroring process is skipped and Qovery starts the deployment of that image on the Kubernetes cluster.

                                        Otherwise, the image is pulled from the source registry and pushed on the mirroring registry at the repository of the application A1, deleting any previous image.

                                        Mirroring image from registry - Service case

                                        Pro:

                                        • Images are automatically deleted when not needede anymore

                                        Cons:

                                        • If the same image is used across environments or service, Qovery will mirror multiple time the same image, reducing the deployment speed

                                        Cluster

                                        Images within the mirroring registry are organized by "Qovery cluster", meaning that the application deployed on the same cluster are all mirrored on the same repository.

                                        At the beginning of the deployment of the application A1, Qovery checks within mirroring registry at the repository of the cluster C1 if an image with the same image name and tag exists.

                                        If the image already exists, the mirroring process is skipped and Qovery starts the deployment of that image on the Kubernetes cluster.

                                        Otherwise, the image is pulled from the source registry and pushed on the mirroring registry at the repository of the cluster C1.

                                        Mirroring image from registry - Cluster case

                                        Pro:

                                        • If the same image is used across environments or service, this setup will avoid to mirror multiple time the same image, increasing the deployment speed.

                                        Cons:

                                        • Qovery can't automatically delete the images mirrored on the mirroring registry. This will increase the cloud provider cost of your image registry since it will store more data. To reduce the amount data stored you can reduce the image TTL via the cluster advanced settings registry.image_retention_time

                                        Why image mirroring is necessary

                                        Image mirroring is a general best practice: you don't want your system to be strictly coupled on a third party.

                                        Let's say that you run an application on your production environment and Kubernetes needs to pull again the image to spawn a new instance for the application. In this case, you don't want to make this fail due to the unavailability of your source container registry. This is why we make sure that a copy is always available on the container registry next to the Kubernetes cluster.

                                        Why unique image tags are necessary

                                        When working with containerized applications, it is crucial to employ unique image tags for precise version management. This practice ensures complete confidence in the version running within a container. Failing to use unique image tags can lead to adverse consequences due to the image caching mechanisms employed by both the Qovery mirroring system and Kubernetes:

                                        • Mirroring Registry: Qovery’s mirroring system stores images in a registry. If an image tag remains the same between two versions, the new version will not be mirrored. Consequently, the new version will not be deployed, affecting the overall application.
                                        • Kubernetes: Applications deployed by Qovery on Kubernetes adhere to the “ifNotPresent” image pull policy. This policy means that if the image already exists on the Kubernetes node’s local disk, Kubernetes will not attempt to pull it again. However, if the image tag remains unchanged, the new image version will not be fetched, resulting in your pods running the outdated application code.

                                        In summary, maintaining unique image tags is a critical aspect of effective version control and ensuring that your applications run the intended versions without disruptions caused by caching mechanisms.

                                        - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/deployment/index.html b/docs/using-qovery/deployment/index.html index 71d88c584e..4710c460fd 100644 --- a/docs/using-qovery/deployment/index.html +++ b/docs/using-qovery/deployment/index.html @@ -21,62 +21,62 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                        -

                                        Deployment

                                        In the following subsections, you'll find all the information about the deployment management with Qovery.

                                        The deployment has the end goal to create the resources necessary to run your applications on your cloud account, based on the configuration you have done on the Qovery console.

                                        In the image below you can find the complete flow that your application will go through, from your Git repository up to your Kuernetes cluster.

                                        Deployment history access

                                        1. The developer pushes the code within the git repository
                                        2. The deployment trigger can come from different sources depending on your integration type: +

                                          Deployment

                                          In the following subsections, you'll find all the information about the deployment management with Qovery.

                                          The deployment has the end goal to create the resources necessary to run your applications on your cloud account, based on the configuration you have done on the Qovery console.

                                          In the image below you can find the complete flow that your application will go through, from your Git repository up to your Kuernetes cluster.

                                          Deployment history access

                                          1. The developer pushes the code within the git repository
                                          2. The deployment trigger can come from different sources depending on your integration type: 2.a The auto-deploy feature is activated on Qovery. When the new commit is pushed, a webhook call is received by Qovery and can proceed with the application deployment. See this section for more information. 2.b The auto-deploy feature is not activated on Qovery and the deployment is managed via the CI/CD. 2.c The auto-deploy feature is not activated on Qovery and the user decides to trigger the deployment directly from within the Qovery console.
                                          3. The Qovery engine starts processing based on the configured Deployment Pipeline. The pipeline defines the steps that need to be followed in order to deploy your applications. See this section for more information.
                                          4. The Qovery engine pulls the code from your repository.
                                          5. The Qovery engine builds the code and pushes the generated images on a registry present within your cloud account (See the Image Mirroring page for more information).
                                          6. The Qovery engine creates the load balancers and configure the network.
                                          7. The Qovery engine creates a namespace within the Kubernetes cluster and deploys the application.
                                          8. The Qovery engine takes care of creating a custom domain for your application and as well configure the TLS so that you can access the application from the internet.

                                          The developer can monitor at each time the status of the deployment or of the running applications by:

                                          • checking the Deployment Status and Running Status. See this section for more information.
                                          • access the Logs interface to retrieve the deployment logs and as well the application logs in real-time. See this section for more information.
                                          • access the Deployment History section to get all the information about the past deployments. See this section for more information.

                                          Note:

                                          • Qovery also support deployments from container registry but actions 2a is not supported plus 4 and 5 are not done.
                                          • In the example above we have shown how the deployment of an application is done but Qovery provides you with a complete set of Deployment Actions allowing you to manage the deployment lifecycle of your applications and environments (Stop, restart etc..). See this section for more information.
                                          Resources
                                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/deployment/logs/index.html b/docs/using-qovery/deployment/logs/index.html index c6e7c7d082..3699948cd7 100644 --- a/docs/using-qovery/deployment/logs/index.html +++ b/docs/using-qovery/deployment/logs/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                          -

                                          Logs

                                          The Logs interface allows you to access:

                                          • The deployment logs: every time a deployment is triggered, Qovery provides you with the log of its execution and as well with any error that might occur.
                                          • The live logs of your applications: Qovery allows you to retrieve the logs of your application in real-time, streamed directly from your remote application (no data is stored on Qovery side). The logs are accessible as long as the application is running and writing the logs in the stdout.

                                          How to access the logs

                                          The Logs interface can be accessed from the console by clicking on the parchment icon available in the header or within the table

                                          Log access

                                          The interface is composed of two sections:

                                          • A navigation panel (on the left)
                                          • A log section allowing you to switch between the deployment logs and the live logs of a service.

                                          Log View

                                          Navigation Panel

                                          This section provides you with some information on the last Deployment that happened on the environment and a navigation system to access the logs of each service of your environment.

                                          More in detail you will find here:

                                          • Deployment information (top section): this section shows you the status of the deployment execution and when it happened. If a deployment is ongoing, its status will be updated accordingly in this section.
                                          • Pipeline view: this section provides an overall view of the current configuration of the Deployment Pipeline and each service present within the environment. By default, only the services that have been deployed within the last deployment execution are displayed but you can still display all of them by un-ticking the option Last deployed only.

                                          Log section

                                          This section allows you to access the Deployment Logs and the Live logs of each service.

                                          Deployment Logs

                                          This tab shows you the deployment logs for each service of the environment. By default, you get access to the logs of the last deployment execution but you can switch to the previous execution (See Accessing old deployment logs).

                                          If the service is built via the Qovery CI pipeline, you will get access to the build logs.

                                          Build Logs

                                          When the deployment on Kubernetes is executed, the system will provide you with the deployment status updates. In case of deployment issues, these updates will provide you with some information on the root cause.

                                          Deployment Status Update

                                          At the end of the deployment, a final message is emitted confirming if the deployment was successful or not and, in case of an issue, it provides you with some information on how to solve the issue.

                                          Log content

                                          You can use the Troubleshoot section to investigate any issue you might encounter during the deployment of your services.

                                          Accessing old deployment logs

                                          You can access the logs of a past deployment execution in two ways:

                                          • using the Deployment log switch on the logs view

                                          Deployment Log Switch

                                          • from the Deployment tab from the service or environment page and clicking on the parchment icon of a previous deployment

                                          Deployment Tab Switch

                                          Live Logs

                                          The live logs tab gives you a real-time view on the log generated by your application while running remotely on your cloud provider infrastructure.

                                          Within this section you will find:

                                          • Timestamp: the timestamp of the message
                                          • Pod Name: the name of the kubernetes pod where your application is running (to distinguish the instance in case of the multi-instance app). If you want to follow a specific pod, you can filter the logs by clicking on the pod name
                                          • Version: the commit id or the image tag of the application running on this POD
                                          • Message: the log message

                                          Past application logs are also preserved on your cluster via Loki and can be accessed from the same log view within the qovery console. Please keep in mind that:

                                          • Loki is configured to preserve only the latest 1000 lines of log for each application and retain them for 12 weeks (configurable via the cluster advanced settings)
                                          • This feature is not available on EC2 Clusters since we don't install Loki.

                                          If you need to troubleshoot issues on the requests managed by your application, you can also access the Nginx logs in the same view (logs format is available in the helper). Note that this option is available only if the application is exposed publicly (See the Port Section)

                                          Log content

                                          +

                                          Logs

                                          The Logs interface allows you to access:

                                          • The deployment logs: every time a deployment is triggered, Qovery provides you with the log of its execution and as well with any error that might occur.
                                          • The live logs of your applications: Qovery allows you to retrieve the logs of your application in real-time, streamed directly from your remote application (no data is stored on Qovery side). The logs are accessible as long as the application is running and writing the logs in the stdout.

                                          How to access the logs

                                          The Logs interface can be accessed from the console by clicking on the parchment icon available in the header or within the table

                                          Log access

                                          The interface is composed of two sections:

                                          • A navigation panel (on the left)
                                          • A log section allowing you to switch between the deployment logs and the live logs of a service.

                                          Log View

                                          Navigation Panel

                                          This section provides you with some information on the last Deployment that happened on the environment and a navigation system to access the logs of each service of your environment.

                                          More in detail you will find here:

                                          • Deployment information (top section): this section shows you the status of the deployment execution and when it happened. If a deployment is ongoing, its status will be updated accordingly in this section.
                                          • Pipeline view: this section provides an overall view of the current configuration of the Deployment Pipeline and each service present within the environment. By default, only the services that have been deployed within the last deployment execution are displayed but you can still display all of them by un-ticking the option Last deployed only.

                                          Log section

                                          This section allows you to access the Deployment Logs and the Live logs of each service.

                                          Deployment Logs

                                          This tab shows you the deployment logs for each service of the environment. By default, you get access to the logs of the last deployment execution but you can switch to the previous execution (See Accessing old deployment logs).

                                          If the service is built via the Qovery CI pipeline, you will get access to the build logs.

                                          Build Logs

                                          When the deployment on Kubernetes is executed, the system will provide you with the deployment status updates. In case of deployment issues, these updates will provide you with some information on the root cause.

                                          Deployment Status Update

                                          At the end of the deployment, a final message is emitted confirming if the deployment was successful or not and, in case of an issue, it provides you with some information on how to solve the issue.

                                          Log content

                                          You can use the Troubleshoot section to investigate any issue you might encounter during the deployment of your services.

                                          Accessing old deployment logs

                                          You can access the logs of a past deployment execution in two ways:

                                          • using the Deployment log switch on the logs view

                                          Deployment Log Switch

                                          • from the Deployment tab from the service or environment page and clicking on the parchment icon of a previous deployment

                                          Deployment Tab Switch

                                          Live Logs

                                          The live logs tab gives you a real-time view on the log generated by your application while running remotely on your cloud provider infrastructure.

                                          Within this section you will find:

                                          • Timestamp: the timestamp of the message
                                          • Pod Name: the name of the kubernetes pod where your application is running (to distinguish the instance in case of the multi-instance app). If you want to follow a specific pod, you can filter the logs by clicking on the pod name
                                          • Version: the commit id or the image tag of the application running on this POD
                                          • Message: the log message

                                          Past application logs are also preserved on your cluster via Loki and can be accessed from the same log view within the qovery console. Please keep in mind that:

                                          • Loki is configured to preserve only the latest 1000 lines of log for each application and retain them for 12 weeks (configurable via the cluster advanced settings)
                                          • This feature is not available on EC2 Clusters since we don't install Loki.

                                          If you need to troubleshoot issues on the requests managed by your application, you can also access the Nginx logs in the same view (logs format is available in the helper). Note that this option is available only if the application is exposed publicly (See the Port Section)

                                          Log content

                                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/deployment/running-and-deployment-statuses/index.html b/docs/using-qovery/deployment/running-and-deployment-statuses/index.html index 874947766b..4f1d8dc79b 100644 --- a/docs/using-qovery/deployment/running-and-deployment-statuses/index.html +++ b/docs/using-qovery/deployment/running-and-deployment-statuses/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                          -

                                          Running and Deployment Statuses

                                          From any environment window on your Qovery Console, you can monitor the running and deployment status of your environments and services.

                                          Statuses

                                          ItemDescription
                                          1The dot in the service tab shows the environment running status.
                                          For more information, see the Environment Statuses section below.
                                          2The dot in the deployment tab shows the environment deployment status.
                                          For more information, see the Deployment Statuses section below.
                                          3The label in the column "Service status" represents the running status of the service.
                                          For more information, see Service Statuses section below.
                                          4The label in the column "Last deployment" represents the status of the latest deployment of the service.
                                          For more information, see Deployment Statuses section below.

                                          Running Statuses

                                          Thanks to Running statuses, you can find out which services are currently running on your platform, and which are interrupted. There are two types of run services available currently: environment statuses and service statuses.

                                          Environment Statuses

                                          When you access an environment on your Qovery Console, you can check its status in real-time.

                                          The environment status is computed based on the statuses of all the services in that specific environment. Here are all the possible environment statuses:

                                          StatusDescription
                                          STOPPED (Gray dot)All the services are stopped.
                                          STARTING (Loading Icon)At least 1 service is starting.
                                          STOPPING (Loading Icon)At least 1 service is stopping.
                                          RUNNING (Green dot)All services are running correctly.
                                          ERROR (Red dot)All services are in error status.
                                          WARNING (Orange dot)At least 1 service is in error status (but not all of them).
                                          COMPLETED (Green dot)The job execution has completed (only for cronjob and lifecycle jobs).

                                          Service Statuses

                                          When you access an environment on your Qovery Console, you can check the status of each service in that environment in real-time within the column "Service status".

                                          Here are all the possible service statuses:

                                          StatusDescription
                                          STOPPED (Gray dot)All the application instances are stopped.
                                          STARTING (Loading Icon)At least 1 application instance is starting.
                                          STOPPING (Loading Icon)At least 1 application instance is stopping.
                                          RUNNING (Green dot)All application instances are running correctly.
                                          ERROR (Red dot)All application instances are in error status.
                                          WARNING (Orange dot)(Valid for multi-instance applications only) At least 1 application instance is in error status (but not all of them).
                                          Completed (Green dot)(Valid for Lifecycle and Cronjob only) The job was correctly executed.

                                          The service status is computed based on the status of each Kubernetes pod deployed for this application.

                                          Pod status (Application instances)

                                          You can check on the Service overview page the status of each pod running your application in Kubernetes. This page is accessible by clicking on one of the services of your environment.

                                          Within this page you will have a view of:

                                          • the number of running instances of your application
                                          • the status of each instance
                                          • in case of an error, you will get the reason behind the issue by clicking on the Pod in error.

                                          Deployment Statuses

                                          When you access an environment on your Qovery Console, you can check:

                                          • the overall status of your deployments in that specific environment, thanks to the dot present within the "Deployment" tab. This corresponds to the overall deployment status of your environment.

                                          • the deployment status of each service in that specific environment, thanks to the label displayed in the Service status column. This corresponds to the status of the last deployment performed on the service.

                                            Here are all the possible deployment statuses for both environments and services:

                                          • QUEUED (temporary state).

                                          • BUILDING (temporary state).

                                          • BUILDING ERROR (final state).

                                          • DEPLOYING (temporary state).

                                          • DEPLOYMENT ERROR (final state).

                                          • CANCELLING BUILDING (temporary state).

                                          • CANCELLED (temporary state).

                                          • DEPLOYMENT OK (final state).

                                          +

                                          Running and Deployment Statuses

                                          From any environment window on your Qovery Console, you can monitor the running and deployment status of your environments and services.

                                          Statuses

                                          ItemDescription
                                          1The dot in the service tab shows the environment running status.
                                          For more information, see the Environment Statuses section below.
                                          2The dot in the deployment tab shows the environment deployment status.
                                          For more information, see the Deployment Statuses section below.
                                          3The label in the column "Service status" represents the running status of the service.
                                          For more information, see Service Statuses section below.
                                          4The label in the column "Last deployment" represents the status of the latest deployment of the service.
                                          For more information, see Deployment Statuses section below.

                                          Running Statuses

                                          Thanks to Running statuses, you can find out which services are currently running on your platform, and which are interrupted. There are two types of run services available currently: environment statuses and service statuses.

                                          Environment Statuses

                                          When you access an environment on your Qovery Console, you can check its status in real-time.

                                          The environment status is computed based on the statuses of all the services in that specific environment. Here are all the possible environment statuses:

                                          StatusDescription
                                          STOPPED (Gray dot)All the services are stopped.
                                          STARTING (Loading Icon)At least 1 service is starting.
                                          STOPPING (Loading Icon)At least 1 service is stopping.
                                          RUNNING (Green dot)All services are running correctly.
                                          ERROR (Red dot)All services are in error status.
                                          WARNING (Orange dot)At least 1 service is in error status (but not all of them).
                                          COMPLETED (Green dot)The job execution has completed (only for cronjob and lifecycle jobs).

                                          Service Statuses

                                          When you access an environment on your Qovery Console, you can check the status of each service in that environment in real-time within the column "Service status".

                                          Here are all the possible service statuses:

                                          StatusDescription
                                          STOPPED (Gray dot)All the application instances are stopped.
                                          STARTING (Loading Icon)At least 1 application instance is starting.
                                          STOPPING (Loading Icon)At least 1 application instance is stopping.
                                          RUNNING (Green dot)All application instances are running correctly.
                                          ERROR (Red dot)All application instances are in error status.
                                          WARNING (Orange dot)(Valid for multi-instance applications only) At least 1 application instance is in error status (but not all of them).
                                          Completed (Green dot)(Valid for Lifecycle and Cronjob only) The job was correctly executed.

                                          The service status is computed based on the status of each Kubernetes pod deployed for this application.

                                          Pod status (Application instances)

                                          You can check on the Service overview page the status of each pod running your application in Kubernetes. This page is accessible by clicking on one of the services of your environment.

                                          Within this page you will have a view of:

                                          • the number of running instances of your application
                                          • the status of each instance
                                          • in case of an error, you will get the reason behind the issue by clicking on the Pod in error.

                                          Deployment Statuses

                                          When you access an environment on your Qovery Console, you can check:

                                          • the overall status of your deployments in that specific environment, thanks to the dot present within the "Deployment" tab. This corresponds to the overall deployment status of your environment.

                                          • the deployment status of each service in that specific environment, thanks to the label displayed in the Service status column. This corresponds to the status of the last deployment performed on the service.

                                            Here are all the possible deployment statuses for both environments and services:

                                          • QUEUED (temporary state).

                                          • BUILDING (temporary state).

                                          • BUILDING ERROR (final state).

                                          • DEPLOYING (temporary state).

                                          • DEPLOYMENT ERROR (final state).

                                          • CANCELLING BUILDING (temporary state).

                                          • CANCELLED (temporary state).

                                          • DEPLOYMENT OK (final state).

                                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/index.html b/docs/using-qovery/index.html index a9c8723844..4f41edc106 100644 --- a/docs/using-qovery/index.html +++ b/docs/using-qovery/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                          -
                                          Resources
                                            +
                                            Resources
                                              - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/api-integration/index.html b/docs/using-qovery/integration/api-integration/index.html index 8775b3ad85..b175f5cd28 100644 --- a/docs/using-qovery/integration/api-integration/index.html +++ b/docs/using-qovery/integration/api-integration/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                              - +
                                              - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/container-registry/index.html b/docs/using-qovery/integration/container-registry/index.html index b7ac47df86..11f1e1c208 100644 --- a/docs/using-qovery/integration/container-registry/index.html +++ b/docs/using-qovery/integration/container-registry/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                              -

                                              Container Registry

                                              Qovery allows you to integrate with major container registries, enabling you to deploy your own container images or those available on public registries.

                                              You can control the container registry used by your teams directly within the Qovery Console.

                                              To know more about how to configure your container registry connection and the supported container registries, have a look at this section

                                              Resources
                                                +

                                                Container Registry

                                                Qovery allows you to integrate with major container registries, enabling you to deploy your own container images or those available on public registries.

                                                You can control the container registry used by your teams directly within the Qovery Console.

                                                To know more about how to configure your container registry connection and the supported container registries, have a look at this section

                                                Resources
                                                  - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/continuous-integration/circle-ci/index.html b/docs/using-qovery/integration/continuous-integration/circle-ci/index.html index 1f74fab42e..b5436bfd14 100644 --- a/docs/using-qovery/integration/continuous-integration/circle-ci/index.html +++ b/docs/using-qovery/integration/continuous-integration/circle-ci/index.html @@ -21,62 +21,62 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                  -

                                                  Circle CI

                                                  Using Circle CI with Qovery is super powerful and gives you the ability to manage the way that you want to deploy your applications. As the possibility are endless, I will share with you a couple of examples that you can use. Feel free to adapt them to your need.

                                                  Prerequisites

                                                  Before using the examples below, you need to:

                                                  1. Install the Qovery CLI.
                                                  2. Generate an API token via the CLI or the Console .
                                                  3. Set the environment variable Q_CLI_ACCESS_TOKEN or QOVERY_CLI_ACCESS_TOKEN (both are valid) with your API token. E.g. export QOVERY_CLI_ACCESS_TOKEN=your-api-token
                                                  4. You have turned off the Qovery Auto Deployment for every service that you want to deploy manually.

                                                  Jenkins Examples

                                                  Since Circle CI also provides a .yaml file to configure your pipeline. Refers to GitLab CI and GitHub Actions examples to learn how to configure your pipeline with Qovery.

                                                  Qovery CLI command examples

                                                  Deploy your application with a specific commit ID

                                                  qovery application deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --application <your_app_name> \
                                                  --commit-id <your_commit_id> \
                                                  --watch

                                                  Deploy your multiple applications with a different commit ID

                                                  # deploy the application 1 and wait for the deployment to be successful with the --watch argument
                                                  qovery application deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --application <your_app_1_name> \
                                                  --commit-id <your_commit_id> \
                                                  --watch
                                                  +

                                                  Circle CI

                                                  Using Circle CI with Qovery is super powerful and gives you the ability to manage the way that you want to deploy your applications. As the possibility are endless, I will share with you a couple of examples that you can use. Feel free to adapt them to your need.

                                                  Prerequisites

                                                  Before using the examples below, you need to:

                                                  1. Install the Qovery CLI.
                                                  2. Generate an API token via the CLI or the Console .
                                                  3. Set the environment variable Q_CLI_ACCESS_TOKEN or QOVERY_CLI_ACCESS_TOKEN (both are valid) with your API token. E.g. export QOVERY_CLI_ACCESS_TOKEN=your-api-token
                                                  4. You have turned off the Qovery Auto Deployment for every service that you want to deploy manually.

                                                  Jenkins Examples

                                                  Since Circle CI also provides a .yaml file to configure your pipeline. Refers to GitLab CI and GitHub Actions examples to learn how to configure your pipeline with Qovery.

                                                  Qovery CLI command examples

                                                  Deploy your application with a specific commit ID

                                                  qovery application deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --application <your_app_name> \
                                                  --commit-id <your_commit_id> \
                                                  --watch

                                                  Deploy your multiple applications with a different commit ID

                                                  # deploy the application 1 and wait for the deployment to be successful with the --watch argument
                                                  qovery application deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --application <your_app_1_name> \
                                                  --commit-id <your_commit_id> \
                                                  --watch
                                                  # deploy the application 2 and wait for the deployment to be successful with the --watch argument
                                                  qovery application deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --application <your_app_2_name> \
                                                  --commit-id <your_commit_id> \
                                                  --watch

                                                  This is also applicable for the qovery container deploy, qovery lifecycle deploy, and qovery cronjob deploy commands.

                                                  Deploy your multiple applications with a specific commit ID (monorepo)

                                                  # deploy the application 1, 2 and 3 with the same commit ID and wait for the deployment to be successful with the --watch argument
                                                  qovery application deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --applications "<app_1_name>, <app_2_name>, <app_3_name>" \
                                                  --commit-id <your_commit_id> \
                                                  --watch

                                                  This is also applicable for the qovery container deploy, qovery lifecycle deploy, and qovery cronjob deploy commands.

                                                  Create a Preview Environment for your Pull-Request

                                                  Qovery integrates automatically with GitHub, GitLab and Bitbucket to create a Preview Environment for each Pull-Request. But in case you want to control the creation of the Preview Environment manually, you can use the following commands:

                                                  # Clone your base environment
                                                  qovery environment clone \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --new-environment-name <your_new_environment_name>
                                                  # Change your application branch to the Pull-Request branch
                                                  qovery application update \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_new_environment_name> \
                                                  --application <your_app_name> \
                                                  --branch <your_pull_request_branch_name>
                                                  # Deploy your new environment
                                                  qovery environment deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_new_environment_name> \
                                                  --watch

                                                  Delete a Preview Environment

                                                  qovery environment delete \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_preview_environment_name> \
                                                  --watch

                                                  Terraform

                                                  Do you want to include Terraform in your CI? Check out our Terraform documentation.

                                                  Any other examples?

                                                  Feel free to share your examples with us, and we'll be happy to share them with the community. Contact us on our forum.

                                                  - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/continuous-integration/github-actions/index.html b/docs/using-qovery/integration/continuous-integration/github-actions/index.html index 0d0f17d9ec..5f7d678f8d 100644 --- a/docs/using-qovery/integration/continuous-integration/github-actions/index.html +++ b/docs/using-qovery/integration/continuous-integration/github-actions/index.html @@ -21,36 +21,36 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                  -

                                                  GitHub Actions

                                                  Using GitHub Actions with Qovery is super powerful and gives you the ability to manage the way that you want to deploy your applications. As the possibility are endless, I will share with you a couple of examples that you can use. Feel free to adapt them to your need.

                                                  Prerequisites

                                                  Before using the examples below, you need to:

                                                  1. Install the Qovery CLI.
                                                  2. Generate an API token via the CLI or the Console .
                                                  3. Set the environment variable Q_CLI_ACCESS_TOKEN or QOVERY_CLI_ACCESS_TOKEN (both are valid) with your API token. E.g. export QOVERY_CLI_ACCESS_TOKEN=your-api-token
                                                  4. You have turned off the Qovery Auto Deployment for every service that you want to deploy manually.

                                                  GitHub Actions Examples

                                                  Deploy a container application

                                                  This example will deploy a container application with Qovery from your GitHub CI pipeline. Feel free to adapt it to your need.

                                                  .github/workflows/deploy-with-qovery.yml
                                                  # 1. Build and Push image to a remote registry
                                                  # 2. Deploy with Qovery
                                                  +

                                                  GitHub Actions

                                                  Using GitHub Actions with Qovery is super powerful and gives you the ability to manage the way that you want to deploy your applications. As the possibility are endless, I will share with you a couple of examples that you can use. Feel free to adapt them to your need.

                                                  Prerequisites

                                                  Before using the examples below, you need to:

                                                  1. Install the Qovery CLI.
                                                  2. Generate an API token via the CLI or the Console .
                                                  3. Set the environment variable Q_CLI_ACCESS_TOKEN or QOVERY_CLI_ACCESS_TOKEN (both are valid) with your API token. E.g. export QOVERY_CLI_ACCESS_TOKEN=your-api-token
                                                  4. You have turned off the Qovery Auto Deployment for every service that you want to deploy manually.

                                                  GitHub Actions Examples

                                                  Deploy a container application

                                                  This example will deploy a container application with Qovery from your GitHub CI pipeline. Feel free to adapt it to your need.

                                                  .github/workflows/deploy-with-qovery.yml
                                                  # 1. Build and Push image to a remote registry
                                                  # 2. Deploy with Qovery
                                                  name: Publish Docker image and Deploy with Qovery
                                                  on:
                                                  release:
                                                  types: [published]
                                                  jobs:
                                                  deploy_with_qovery:
                                                  name: Push Docker image to Docker Hub and Deploy with Qovery
                                                  runs-on: ubuntu-latest
                                                  steps:
                                                  - name: Check out the repo
                                                  uses: actions/checkout@v3
                                                  @@ -64,27 +64,27 @@
                                                  # Deploy your new environment
                                                  qovery environment deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_new_environment_name> \
                                                  --watch

                                                  Delete a Preview Environment

                                                  qovery environment delete \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_preview_environment_name> \
                                                  --watch

                                                  Terraform

                                                  Do you want to include Terraform in your CI? Check out our Terraform documentation.

                                                  Any other examples?

                                                  Feel free to share your examples with us, and we'll be happy to share them with the community. Contact us on our forum.

                                                  - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/continuous-integration/gitlab-ci/index.html b/docs/using-qovery/integration/continuous-integration/gitlab-ci/index.html index be2cdb7492..abb757f93c 100644 --- a/docs/using-qovery/integration/continuous-integration/gitlab-ci/index.html +++ b/docs/using-qovery/integration/continuous-integration/gitlab-ci/index.html @@ -21,36 +21,36 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                  -

                                                  GitLab CI

                                                  Using Gitlab CI with Qovery is super powerful and gives you the ability to manage the way that you want to deploy your applications. As the possibility are endless, I will share with you a couple of examples that you can use. Feel free to adapt them to your need.

                                                  Prerequisites

                                                  Before using the examples below, you need to:

                                                  1. Install the Qovery CLI.
                                                  2. Generate an API token via the CLI or the Console .
                                                  3. Set the environment variable Q_CLI_ACCESS_TOKEN or QOVERY_CLI_ACCESS_TOKEN (both are valid) with your API token. E.g. export QOVERY_CLI_ACCESS_TOKEN=your-api-token
                                                  4. You have turned off the Qovery Auto Deployment for every service that you want to deploy manually.

                                                  GitLab CI Examples

                                                  Deploy a container application

                                                  This example will deploy a container application with Qovery from your GitLab CI pipeline. Feel free to adapt it to your need.

                                                  .gitlab-ci.yml
                                                  # 1. Build and Push image to a remote registry
                                                  # 2. Deploy with Qovery
                                                  +

                                                  GitLab CI

                                                  Using Gitlab CI with Qovery is super powerful and gives you the ability to manage the way that you want to deploy your applications. As the possibility are endless, I will share with you a couple of examples that you can use. Feel free to adapt them to your need.

                                                  Prerequisites

                                                  Before using the examples below, you need to:

                                                  1. Install the Qovery CLI.
                                                  2. Generate an API token via the CLI or the Console .
                                                  3. Set the environment variable Q_CLI_ACCESS_TOKEN or QOVERY_CLI_ACCESS_TOKEN (both are valid) with your API token. E.g. export QOVERY_CLI_ACCESS_TOKEN=your-api-token
                                                  4. You have turned off the Qovery Auto Deployment for every service that you want to deploy manually.

                                                  GitLab CI Examples

                                                  Deploy a container application

                                                  This example will deploy a container application with Qovery from your GitLab CI pipeline. Feel free to adapt it to your need.

                                                  .gitlab-ci.yml
                                                  # 1. Build and Push image to a remote registry
                                                  # 2. Deploy with Qovery
                                                  stages:
                                                  - build-and-push
                                                  - deploy
                                                  build-and-push-image:
                                                  stage: build-and-push
                                                  script:
                                                  - docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY
                                                  - docker build . --tag my-registry-group/your-app:$CI_COMMIT_SHORT_SHA
                                                  - docker push my-registry-group/your-app:$CI_COMMIT_SHORT_SHA
                                                  deploy-image-with-qovery:
                                                  stage: deploy
                                                  script:
                                                  - curl -s https://get.qovery.com | bash # Download and install Qovery CLI
                                                  - |
                                                  qovery container deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --container <your_qovery_container_name> \
                                                  --tag $CI_COMMIT_SHORT_SHA \
                                                  --watch

                                                  Qovery CLI command examples

                                                  Deploy your application with a specific commit ID

                                                  qovery application deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --application <your_app_name> \
                                                  --commit-id <your_commit_id> \
                                                  --watch

                                                  Deploy your multiple applications with a different commit ID

                                                  # deploy the application 1 and wait for the deployment to be successful with the --watch argument
                                                  qovery application deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --application <your_app_1_name> \
                                                  --commit-id <your_commit_id> \
                                                  --watch
                                                  @@ -59,27 +59,27 @@
                                                  # Deploy your new environment
                                                  qovery environment deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_new_environment_name> \
                                                  --watch

                                                  Delete a Preview Environment

                                                  qovery environment delete \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_preview_environment_name> \
                                                  --watch

                                                  Terraform

                                                  Do you want to include Terraform in your CI? Check out our Terraform documentation.

                                                  Any other examples?

                                                  Feel free to share your examples with us, and we'll be happy to share them with the community. Contact us on our forum.

                                                  - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/continuous-integration/index.html b/docs/using-qovery/integration/continuous-integration/index.html index 76c94fcb20..be73849de9 100644 --- a/docs/using-qovery/integration/continuous-integration/index.html +++ b/docs/using-qovery/integration/continuous-integration/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                  -

                                                  Continuous Integration

                                                  Select the CI/CD system that you use today:

                                                  Gitlab CI
                                                  Circle CI
                                                  Github Actions
                                                  Jenkins

                                                  FAQ

                                                  I don't find my Continuous Integration platform, what should I do?

                                                  Your CI platform is probably going to be officially supported in the near future. In the meantime, you can use our Qovery CLI and make the integration yourself (it is super easy).

                                                  Do you need help?

                                                  Feel free to open a thread on our Community Forum. We will be happy to help you.

                                                  +

                                                  Continuous Integration

                                                  Select the CI/CD system that you use today:

                                                  Gitlab CI
                                                  Circle CI
                                                  Github Actions
                                                  Jenkins

                                                  FAQ

                                                  I don't find my Continuous Integration platform, what should I do?

                                                  Your CI platform is probably going to be officially supported in the near future. In the meantime, you can use our Qovery CLI and make the integration yourself (it is super easy).

                                                  Do you need help?

                                                  Feel free to open a thread on our Community Forum. We will be happy to help you.

                                                  - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/continuous-integration/jenkins/index.html b/docs/using-qovery/integration/continuous-integration/jenkins/index.html index fbab826136..e134b64411 100644 --- a/docs/using-qovery/integration/continuous-integration/jenkins/index.html +++ b/docs/using-qovery/integration/continuous-integration/jenkins/index.html @@ -21,62 +21,62 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                  -

                                                  Jenkins

                                                  Using Jenkins with Qovery is super powerful and gives you the ability to manage the way that you want to deploy your applications. As the possibility are endless, I will share with you a couple of examples that you can use. Feel free to adapt them to your need.

                                                  Prerequisites

                                                  Before using the examples below, you need to:

                                                  1. Install the Qovery CLI.
                                                  2. Generate an API token via the CLI or the Console .
                                                  3. Set the environment variable Q_CLI_ACCESS_TOKEN or QOVERY_CLI_ACCESS_TOKEN (both are valid) with your API token. E.g. export QOVERY_CLI_ACCESS_TOKEN=your-api-token
                                                  4. You have turned off the Qovery Auto Deployment for every service that you want to deploy manually.

                                                  Jenkins Examples

                                                  Since Jenkins also provides a .yaml file to configure your pipeline. Refers to GitLab CI and GitHub Actions examples to learn how to configure your pipeline with Qovery.

                                                  Qovery CLI command examples

                                                  Deploy your application with a specific commit ID

                                                  qovery application deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --application <your_app_name> \
                                                  --commit-id <your_commit_id> \
                                                  --watch

                                                  Deploy your multiple applications with a different commit ID

                                                  # deploy the application 1 and wait for the deployment to be successful with the --watch argument
                                                  qovery application deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --application <your_app_1_name> \
                                                  --commit-id <your_commit_id> \
                                                  --watch
                                                  +

                                                  Jenkins

                                                  Using Jenkins with Qovery is super powerful and gives you the ability to manage the way that you want to deploy your applications. As the possibility are endless, I will share with you a couple of examples that you can use. Feel free to adapt them to your need.

                                                  Prerequisites

                                                  Before using the examples below, you need to:

                                                  1. Install the Qovery CLI.
                                                  2. Generate an API token via the CLI or the Console .
                                                  3. Set the environment variable Q_CLI_ACCESS_TOKEN or QOVERY_CLI_ACCESS_TOKEN (both are valid) with your API token. E.g. export QOVERY_CLI_ACCESS_TOKEN=your-api-token
                                                  4. You have turned off the Qovery Auto Deployment for every service that you want to deploy manually.

                                                  Jenkins Examples

                                                  Since Jenkins also provides a .yaml file to configure your pipeline. Refers to GitLab CI and GitHub Actions examples to learn how to configure your pipeline with Qovery.

                                                  Qovery CLI command examples

                                                  Deploy your application with a specific commit ID

                                                  qovery application deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --application <your_app_name> \
                                                  --commit-id <your_commit_id> \
                                                  --watch

                                                  Deploy your multiple applications with a different commit ID

                                                  # deploy the application 1 and wait for the deployment to be successful with the --watch argument
                                                  qovery application deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --application <your_app_1_name> \
                                                  --commit-id <your_commit_id> \
                                                  --watch
                                                  # deploy the application 2 and wait for the deployment to be successful with the --watch argument
                                                  qovery application deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --application <your_app_2_name> \
                                                  --commit-id <your_commit_id> \
                                                  --watch

                                                  This is also applicable for the qovery container deploy, qovery lifecycle deploy, and qovery cronjob deploy commands.

                                                  Deploy your multiple applications with a specific commit ID (monorepo)

                                                  # deploy the application 1, 2 and 3 with the same commit ID and wait for the deployment to be successful with the --watch argument
                                                  qovery application deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --applications "<app_1_name>, <app_2_name>, <app_3_name>" \
                                                  --commit-id <your_commit_id> \
                                                  --watch

                                                  This is also applicable for the qovery container deploy, qovery lifecycle deploy, and qovery cronjob deploy commands.

                                                  Create a Preview Environment for your Pull-Request

                                                  Qovery integrates automatically with GitHub, GitLab and Bitbucket to create a Preview Environment for each Pull-Request. But in case you want to control the creation of the Preview Environment manually, you can use the following commands:

                                                  # Clone your base environment
                                                  qovery environment clone \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_environment_name> \
                                                  --new-environment-name <your_new_environment_name>
                                                  # Change your application branch to the Pull-Request branch
                                                  qovery application update \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_new_environment_name> \
                                                  --application <your_app_name> \
                                                  --branch <your_pull_request_branch_name>
                                                  # Deploy your new environment
                                                  qovery environment deploy \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_new_environment_name> \
                                                  --watch

                                                  Delete a Preview Environment

                                                  qovery environment delete \
                                                  --organization <your_org_name> \
                                                  --project <your_project_name> \
                                                  --environment <your_preview_environment_name> \
                                                  --watch

                                                  Terraform

                                                  Do you want to include Terraform in your CI? Check out our Terraform documentation.

                                                  Any other examples?

                                                  Feel free to share your examples with us, and we'll be happy to share them with the community. Contact us on our forum.

                                                  - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/git-repository/index.html b/docs/using-qovery/integration/git-repository/index.html index 6f3ebd09d2..241e67c4c1 100644 --- a/docs/using-qovery/integration/git-repository/index.html +++ b/docs/using-qovery/integration/git-repository/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                  -

                                                  Git Repository

                                                  Qovery allows you to integrate with the major git based software version control systems in order to build and deploy the applications available on your own repositories.

                                                  Today Qovery supports the following software version control systems:

                                                  • GitHub and GitHub Enterprise
                                                  • GitLab
                                                  • Bitbucket

                                                  Once connected to the Qovery Console via one of these three systems, Qovery will be able to access all the repositories connected to your account.

                                                  If you have special access needs, you can use the git provider tokens instead of your own git provider account. Have a look at the Managing git permission section to know more.

                                                  Resources
                                                    +

                                                    Git Repository

                                                    Qovery allows you to integrate with the major git based software version control systems in order to build and deploy the applications available on your own repositories.

                                                    Today Qovery supports the following software version control systems:

                                                    • GitHub and GitHub Enterprise
                                                    • GitLab
                                                    • Bitbucket

                                                    Once connected to the Qovery Console via one of these three systems, Qovery will be able to access all the repositories connected to your account.

                                                    If you have special access needs, you can use the git provider tokens instead of your own git provider account. Have a look at the Managing git permission section to know more.

                                                    Resources
                                                      - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/helm-repository/index.html b/docs/using-qovery/integration/helm-repository/index.html new file mode 100644 index 0000000000..fc9f38b3e3 --- /dev/null +++ b/docs/using-qovery/integration/helm-repository/index.html @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + +Helm Repository | Docs | Qovery + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                      +

                                                      Helm Repository

                                                      Qovery allows you to integrate with major helm registries, enabling you to deploy your own helm charts or those available on public registries.

                                                      You can control the helm registry used by your teams directly within the Qovery Console.

                                                      To know more about how to configure your helm registry connection and the supported container registries, have a look at this section

                                                      Resources
                                                        +
                                                        + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/using-qovery/integration/index.html b/docs/using-qovery/integration/index.html index 6b92dfda25..1f8b69d1b4 100644 --- a/docs/using-qovery/integration/index.html +++ b/docs/using-qovery/integration/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                        -
                                                        Resources
                                                          +
                                                          Resources
                                                            - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/monitoring/datadog/index.html b/docs/using-qovery/integration/monitoring/datadog/index.html index 2e89cf0feb..4a361999c5 100644 --- a/docs/using-qovery/integration/monitoring/datadog/index.html +++ b/docs/using-qovery/integration/monitoring/datadog/index.html @@ -21,60 +21,60 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                            -

                                                            Datadog

                                                            Datadog is a recommended product to monitor and track down your application performance issue (APM). Qovery supports and recommends using Datadog (or another monitoring/observability platform). +

                                                            Datadog

                                                            Datadog is a recommended product to monitor and track down your application performance issue (APM). Qovery supports and recommends using Datadog (or another monitoring/observability platform). Check out our tutorial to know how to integrate Datadog with Qovery.

                                                            Resources
                                                              - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/monitoring/index.html b/docs/using-qovery/integration/monitoring/index.html index 23fec0b89e..35b2e37e59 100644 --- a/docs/using-qovery/integration/monitoring/index.html +++ b/docs/using-qovery/integration/monitoring/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                              -

                                                              Monitoring

                                                              Datadog
                                                              New Relic

                                                              FAQ

                                                              I don't find my Monitoring provider, what should I do?

                                                              Basically, Qovery relies on Kubernetes to run your apps. Meaning, Qovery will support your monitoring solution if their maintainers provide a Helm Chart.

                                                              If your monitoring platform provides a Helm Chart, then you can install it:

                                                              By using the Qovery Lifecycle Jobs

                                                              1. Follow this guide to deploy your Helm Chart with the Qovery Lifecycle Jobs.

                                                              By using kubectl

                                                              1. Connect to your Qovery Kubernetes cluster.
                                                              2. Install the helm chart.

                                                              Do you need help?

                                                              Feel free to open a thread on our Community Forum. We will be happy to help you.

                                                              +

                                                              Monitoring

                                                              Datadog
                                                              New Relic

                                                              FAQ

                                                              I don't find my Monitoring provider, what should I do?

                                                              Basically, Qovery relies on Kubernetes to run your apps. Meaning, Qovery will support your monitoring solution if their maintainers provide a Helm Chart.

                                                              If your monitoring platform provides a Helm Chart, then you can install it:

                                                              By using the Qovery Lifecycle Jobs

                                                              1. Follow this guide to deploy your Helm Chart with the Qovery Lifecycle Jobs.

                                                              By using kubectl

                                                              1. Connect to your Qovery Kubernetes cluster.
                                                              2. Install the helm chart.

                                                              Do you need help?

                                                              Feel free to open a thread on our Community Forum. We will be happy to help you.

                                                              - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/monitoring/new-relic/index.html b/docs/using-qovery/integration/monitoring/new-relic/index.html index 11da03c268..46ede9bbb3 100644 --- a/docs/using-qovery/integration/monitoring/new-relic/index.html +++ b/docs/using-qovery/integration/monitoring/new-relic/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                              -

                                                              New Relic

                                                              NewRelic is a recommended product to monitor and track down your application performance issue (APM). Qovery supports and recommends using NewRelic (or another monitoring/observability platform).

                                                              Install NewRelic

                                                              To install NewRelic on Qovery, you have 2 choices:

                                                              By using the Qovery Lifecycle Jobs

                                                              1. Follow this guide to deploy your NewRelic Helm Chart with the Qovery Lifecycle Jobs.

                                                              By using kubectl

                                                              1. Connect to your Qovery Kubernetes cluster.
                                                              2. Use helm to install NewRelic.
                                                              +

                                                              New Relic

                                                              NewRelic is a recommended product to monitor and track down your application performance issue (APM). Qovery supports and recommends using NewRelic (or another monitoring/observability platform).

                                                              Install NewRelic

                                                              To install NewRelic on Qovery, you have 2 choices:

                                                              By using the Qovery Lifecycle Jobs

                                                              1. Follow this guide to deploy your NewRelic Helm Chart with the Qovery Lifecycle Jobs.

                                                              By using kubectl

                                                              1. Connect to your Qovery Kubernetes cluster.
                                                              2. Use helm to install NewRelic.
                                                              - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/secret-manager/aws-secrets-manager/index.html b/docs/using-qovery/integration/secret-manager/aws-secrets-manager/index.html index 7cab6b04ea..4e2e20bb18 100644 --- a/docs/using-qovery/integration/secret-manager/aws-secrets-manager/index.html +++ b/docs/using-qovery/integration/secret-manager/aws-secrets-manager/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                              -

                                                              AWS Secrets Manager

                                                              AWS Secrets Manager is a service that helps you protect secrets needed to access your applications, services, and IT resources. The service enables you to easily rotate, manage, and retrieve database credentials, API keys, and other secrets throughout their lifecycle.

                                                              Setup

                                                              API Keys

                                                              If your applications need to use AWS Secrets Manager with API Keys, you need to add your API Key in Qovery Secrets Manager.

                                                              Then you can use it in your application as a regular environment variable.

                                                              Assume Roles

                                                              Follow this guide to get assume roles on your Kubernetes cluster. Once it is set up, your application will be able to connect to AWS Secrets Manager using the AWS SDK.

                                                              Resources
                                                                +

                                                                AWS Secrets Manager

                                                                AWS Secrets Manager is a service that helps you protect secrets needed to access your applications, services, and IT resources. The service enables you to easily rotate, manage, and retrieve database credentials, API keys, and other secrets throughout their lifecycle.

                                                                Setup

                                                                API Keys

                                                                If your applications need to use AWS Secrets Manager with API Keys, you need to add your API Key in Qovery Secrets Manager.

                                                                Then you can use it in your application as a regular environment variable.

                                                                Assume Roles

                                                                Follow this guide to get assume roles on your Kubernetes cluster. Once it is set up, your application will be able to connect to AWS Secrets Manager using the AWS SDK.

                                                                Resources
                                                                  - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/secret-manager/doppler/index.html b/docs/using-qovery/integration/secret-manager/doppler/index.html index 1c1583ac91..1abcc45aa0 100644 --- a/docs/using-qovery/integration/secret-manager/doppler/index.html +++ b/docs/using-qovery/integration/secret-manager/doppler/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                                  -

                                                                  Doppler

                                                                  Doppler is a universal secrets manager that integrates with Qovery. Doppler allows you to store and manage your application secrets in a single place and access them from anywhere.

                                                                  Check out this Doppler documentation to integrate Qovery with your Doppler account.

                                                                  Resources
                                                                    +

                                                                    Doppler

                                                                    Doppler is a universal secrets manager that integrates with Qovery. Doppler allows you to store and manage your application secrets in a single place and access them from anywhere.

                                                                    Check out this Doppler documentation to integrate Qovery with your Doppler account.

                                                                    Resources
                                                                      - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/secret-manager/index.html b/docs/using-qovery/integration/secret-manager/index.html index 17f2b99306..bffe1b7794 100644 --- a/docs/using-qovery/integration/secret-manager/index.html +++ b/docs/using-qovery/integration/secret-manager/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                                      -

                                                                      Secret Manager

                                                                      Doppler
                                                                      AWS Secrets Manager

                                                                      FAQ

                                                                      I don't find my Secret Manager provider, what should I do?

                                                                      Basically, Qovery relies on Kubernetes to run your apps. Meaning, Qovery will support your secret manager if their maintainers provide a Helm Chart.

                                                                      If your secret manager provides a Helm Chart, then you can install it:

                                                                      By using the Qovery Lifecycle Jobs

                                                                      1. Follow this guide to deploy your Helm Chart with the Qovery Lifecycle Jobs.

                                                                      By using kubectl

                                                                      1. Connect to your Qovery Kubernetes cluster.
                                                                      2. Install the helm chart.

                                                                      Do you need help?

                                                                      Feel free to open a thread on our Community Forum. We will be happy to help you.

                                                                      +

                                                                      Secret Manager

                                                                      Doppler
                                                                      AWS Secrets Manager

                                                                      FAQ

                                                                      I don't find my Secret Manager provider, what should I do?

                                                                      Basically, Qovery relies on Kubernetes to run your apps. Meaning, Qovery will support your secret manager if their maintainers provide a Helm Chart.

                                                                      If your secret manager provides a Helm Chart, then you can install it:

                                                                      By using the Qovery Lifecycle Jobs

                                                                      1. Follow this guide to deploy your Helm Chart with the Qovery Lifecycle Jobs.

                                                                      By using kubectl

                                                                      1. Connect to your Qovery Kubernetes cluster.
                                                                      2. Install the helm chart.

                                                                      Do you need help?

                                                                      Feel free to open a thread on our Community Forum. We will be happy to help you.

                                                                      - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/slack/index.html b/docs/using-qovery/integration/slack/index.html index bd6b1a3937..91a317e850 100644 --- a/docs/using-qovery/integration/slack/index.html +++ b/docs/using-qovery/integration/slack/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                                      -

                                                                      Slack

                                                                      If you'd like to automatically notify your team on a Slack workspace whenever a change has occurred on your apps, this integration will help you out. You can choose which actions should trigger messages on your Slack workspace.

                                                                      Here are the steps that we are going through:

                                                                      1. Create a Slack App
                                                                      2. Create a Webhook
                                                                      3. Setup a Webhook in Qovery
                                                                      4. Try it!

                                                                      1. Create a Slack App

                                                                      1. Go to the Slack page to create apps and create a new app:

                                                                        Create a slack app - step 1

                                                                      2. Create a Slack app from scratch:

                                                                        Create a slack app - step 2

                                                                      3. Call it Qovery and connect it to the workspace of your choice:

                                                                        Create a slack app - step 3

                                                                      4. Feel free to use an image from here as the app's logo:

                                                                        Create a slack app - step 4

                                                                      2. Create a Webhook

                                                                      1. Go to the Incoming Webhooks page for your newly-created app and toggle Activate Incoming Webhooks to turn it on:

                                                                        Create a webhook integration on Slack - step 1

                                                                      2. Click on Add New Webhook to Workspace:

                                                                        Create a webhook integration on Slack - step 2

                                                                      3. Select the channel that the notifications will be posted to:

                                                                        Create a webhook integration on Slack - step 3

                                                                      4. Copy the webhook URL:

                                                                        Create a webhook integration on Slack - step 4

                                                                      3. Create a Webhook in Qovery

                                                                      To create a webhook in Qovery, have a look at this section. For the URL, use the Slack Webhook URL that you got from the previous step.

                                                                      Considerations

                                                                      • You can have multiple webhooks targeting different Slack channels.
                                                                      • You can specify the events that you want to receive. E.g. if you just want to be notified when a deployment failed, then use "events": ["DEPLOYMENT_FAILURE"]. All the events and the description are available on our Webhook section.
                                                                      • You can turn off or delete your webhooks at any time from the webhook section.

                                                                      Check out this page for further details on how to use and configure the WebHook.

                                                                      4. Try it!

                                                                      Launch a deployment with Qovery, and you will see a message like the one below appearing in your Slack channel 🎉

                                                                      Open a thread on our forum if you have any questions.

                                                                      +

                                                                      Slack

                                                                      If you'd like to automatically notify your team on a Slack workspace whenever a change has occurred on your apps, this integration will help you out. You can choose which actions should trigger messages on your Slack workspace.

                                                                      Here are the steps that we are going through:

                                                                      1. Create a Slack App
                                                                      2. Create a Webhook
                                                                      3. Setup a Webhook in Qovery
                                                                      4. Try it!

                                                                      1. Create a Slack App

                                                                      1. Go to the Slack page to create apps and create a new app:

                                                                        Create a slack app - step 1

                                                                      2. Create a Slack app from scratch:

                                                                        Create a slack app - step 2

                                                                      3. Call it Qovery and connect it to the workspace of your choice:

                                                                        Create a slack app - step 3

                                                                      4. Feel free to use an image from here as the app's logo:

                                                                        Create a slack app - step 4

                                                                      2. Create a Webhook

                                                                      1. Go to the Incoming Webhooks page for your newly-created app and toggle Activate Incoming Webhooks to turn it on:

                                                                        Create a webhook integration on Slack - step 1

                                                                      2. Click on Add New Webhook to Workspace:

                                                                        Create a webhook integration on Slack - step 2

                                                                      3. Select the channel that the notifications will be posted to:

                                                                        Create a webhook integration on Slack - step 3

                                                                      4. Copy the webhook URL:

                                                                        Create a webhook integration on Slack - step 4

                                                                      3. Create a Webhook in Qovery

                                                                      To create a webhook in Qovery, have a look at this section. For the URL, use the Slack Webhook URL that you got from the previous step.

                                                                      Considerations

                                                                      • You can have multiple webhooks targeting different Slack channels.
                                                                      • You can specify the events that you want to receive. E.g. if you just want to be notified when a deployment failed, then use "events": ["DEPLOYMENT_FAILURE"]. All the events and the description are available on our Webhook section.
                                                                      • You can turn off or delete your webhooks at any time from the webhook section.

                                                                      Check out this page for further details on how to use and configure the WebHook.

                                                                      4. Try it!

                                                                      Launch a deployment with Qovery, and you will see a message like the one below appearing in your Slack channel 🎉

                                                                      Open a thread on our forum if you have any questions.

                                                                      - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/terraform/index.html b/docs/using-qovery/integration/terraform/index.html index 1c7c9b6216..ea8fc3fc7f 100644 --- a/docs/using-qovery/integration/terraform/index.html +++ b/docs/using-qovery/integration/terraform/index.html @@ -21,60 +21,60 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                                      -

                                                                      Terraform

                                                                      Terraform is an open-source infrastructure as code software (IaC) tool that provides a consistent CLI workflow to manage hundreds of cloud services. Terraform codifies cloud APIs into declarative configuration files.

                                                                      Terraform can be used in 2 context:

                                                                      1. Qovery can be controlled via Terraform. This allows you to automate the creation of your organization, project, clusters, applications and environments (and more).
                                                                      2. Qovery can be used to deploy your Terraform code. This allows you to automate the deployment of your infrastructure.

                                                                      Deploy Qovery with Terraform

                                                                      Qovery integrates with Terraform to create a complete workflow with a strong developer and operations experience for the different teams from development to critical production applications. By integrating Terraform with Qovery, your team can quickly implement governance at scale while drastically improving the developer experience when deploying and managing applications.

                                                                      Examples

                                                                      Check out our Terraform examples here.

                                                                      Terraform Exporter

                                                                      Qovery allows you to export your environment as a Terraform Manifest. Check the Terraform Exporter documentation to know more.

                                                                      Resources

                                                                      Deploy your Terraform code with Qovery

                                                                      Qovery can deploy your Terraform code. It's very useful when you want to deploy your own cloud resources. For example, you can deploy your own databases, lambdas, brokers etc... -To do so, you need to use the Lifecycle Jobs feature.

                                                                      Examples

                                                                      Check out our Terraform examples here.

                                                                      Resources

                                                                      Do you need help?

                                                                      Feel free to open a thread on our Community Forum. We will be happy to help you.

                                                                      +

                                                                      Terraform

                                                                      Terraform is an open-source infrastructure as code software (IaC) tool that provides a consistent CLI workflow to manage hundreds of cloud services. Terraform codifies cloud APIs into declarative configuration files.

                                                                      Terraform can be used in 2 context:

                                                                      1. Qovery can be controlled via Terraform. This allows you to automate the creation of your organization, project, clusters, applications and environments (and more).
                                                                      2. Qovery can be used to deploy your Terraform code. This allows you to automate the deployment of your infrastructure.

                                                                      Deploy Qovery with Terraform

                                                                      Qovery integrates with Terraform to create a complete workflow with a strong developer and operations experience for the different teams from development to critical production applications. By integrating Terraform with Qovery, your team can quickly implement governance at scale while drastically improving the developer experience when deploying and managing applications.

                                                                      Examples

                                                                      Check out our Terraform examples here.

                                                                      Terraform Exporter

                                                                      Qovery allows you to export your environment as a Terraform Manifest. Check the Terraform Exporter documentation to know more.

                                                                      Resources

                                                                      Deploy your Terraform code with Qovery

                                                                      Qovery can deploy your Terraform code. It's very useful when you want to deploy your own cloud resources. For example, you can deploy your own databases, lambdas, brokers etc... +To do so, you need to use the Lifecycle Jobs feature.

                                                                      Examples

                                                                      Check out our Terraform examples here.

                                                                      Resources

                                                                      Do you need help?

                                                                      Feel free to open a thread on our Community Forum. We will be happy to help you.

                                                                      - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/webhook/index.html b/docs/using-qovery/integration/webhook/index.html index eafc48b8c1..ffc220e0f3 100644 --- a/docs/using-qovery/integration/webhook/index.html +++ b/docs/using-qovery/integration/webhook/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                                      -

                                                                      Webhooks

                                                                      Qovery allows you to create webhooks at organization-level so that, when an event happens on an environment within your organization, you can get notified on external applications.

                                                                      This is useful for the following use cases:

                                                                      • integrate Qovery with an exeternal tool that needs to be informed when the deployment status changes.
                                                                      • share within a slack channel any deployment status change for your environments.

                                                                      You can trigger webhooks when:

                                                                      • A deployment has started in the environment.
                                                                      • A deployment has been successful in the environment.
                                                                      • A deployment has been cancelled in the environment.
                                                                      • A deployment has failed in the environment.

                                                                      Two types of webhooks can be created within Qovery:

                                                                      • Standard: this type of webhook will send a payload to the defined url with a Qovery proprietary format (check out our Webhook payload documentation for more information on the payload format)
                                                                      • Slack: this type of webhook will send pre-formatted messages using the Slack messaging syntax. Have a look at our Slack integration for more information on the integration.

                                                                      Creating a Webhook

                                                                      To create a webhook via the Qovery Console:

                                                                      1. Open the Organization settings and the Webhook section

                                                                        Access webhook section

                                                                      2. Press the Add New button.

                                                                      3. Enter the following parameters:

                                                                        ParameterUsage
                                                                        URLThe webhook URL provided by the external application you want to receive notifications on.
                                                                        "kind"Specify which kind of webhook you want to create. At the moment, you can specify : "kind": "STANDARD" to create a generic webhook, or "kind": "SLACK" to create a Slack webhook.
                                                                        "description"(Optional) Enter a self-explanatory description of what your webhook does. In the example, "description": "slack notifications" clearly states that the webhook triggers notifications on Slack.
                                                                        "secret"(Optional) Specify the secret to be used when calling the specified webhook URL
                                                                        "events"List all the events you want to be notified about.
                                                                        "environment_types_filter"(Optional) If you only want to get notified about events happening on one or several specific type(s) or environment(s), you can provide a list using the following possible values: "PRODUCTION", "DEVELOPMENT", "STAGING" and "PREVIEW".

                                                                        Please note that "environment_types_filter" can be used together with "project_names_filter".
                                                                        "project_names_filter"(Optional) If you only want to get notified about events happening in one or several specific projects, you can provide a list of project names that will act as a filter. Notifications will then only be triggered for projects whose names match or, if you're using a wildcard, start with one of the values from your list.

                                                                        Please note that "project_names_filter" is not case-sensitive, accepts wildcards, and can be used together with "environment_types_filter".

                                                                        And press the Create button.

                                                                      Editing a Webhook

                                                                      From the webhook page, press the Wheel button to edit the webhook.

                                                                      If you want to temporally disable the webhook, you can disable it by clicking on the Enable switch.

                                                                      Delete a Webhook

                                                                      From the webhook page, press the Bin button to delete the webhook. A confirmation modal will ask you to confirm the operation.

                                                                      Webhook payload

                                                                      Here is an example of a Qovery Webhook standard payload. The payload is sent as a POST request to the specified URL.

                                                                      Deployment payload

                                                                      This payload is sent when a deployment starts, is cancelled, is successful or fails.

                                                                      {
                                                                      "created_at": "2020-10-04T14:00:00.000Z",
                                                                      "event_type": "DEPLOYMENT_STARTED|DEPLOYMENT_CANCELLED|DEPLOYMENT_SUCCESSFUL|DEPLOYMENT_FAILURE",
                                                                      "payload_type": "DEPLOYMENT", // no other option at the moment
                                                                      "payload_id": "5f7a5b0c-7b7d-4b0a-8b0a-5f7a5b0c7b7d",
                                                                      "payload": {
                                                                      "id": "5f7a5b0c-7b7d-4b0a-8b0a-5f7a5b0c7b7d",
                                                                      "current_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "desired_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "organization": {...}, // doc: https://api-doc.qovery.com/#tag/Organization-Main-Calls/operation/getOrganization
                                                                      "project": {...}, // doc: https://api-doc.qovery.com/#tag/Project-Main-Calls/operation/getProject
                                                                      "environment": {...}, // doc: https://api-doc.qovery.com/#tag/Environment-Main-Calls/operation/getEnvironment
                                                                      "applications": [
                                                                      {
                                                                      "current_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "desired_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "application": {...} // doc: https://api-doc.qovery.com/#tag/Application-Main-Calls/operation/getApplication
                                                                      }
                                                                      ],
                                                                      "databases": [
                                                                      {
                                                                      "current_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "desired_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "database": {...} // doc: https://api-doc.qovery.com/#tag/Database-Main-Calls/operation/getDatabase
                                                                      }
                                                                      ],
                                                                      "containers": [
                                                                      {
                                                                      "current_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "desired_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "container": {...} // doc: https://api-doc.qovery.com/#tag/Container-Main-Calls/operation/getContainer
                                                                      }
                                                                      ],
                                                                      "jobs": [
                                                                      {
                                                                      "current_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "desired_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "job": {...} // doc: https://api-doc.qovery.com/#tag/Job-Main-Calls/operation/getJob
                                                                      }
                                                                      ],
                                                                      "logs": [...] // doc: https://api-doc.qovery.com/#tag/Environment-Logs/operation/listEnvironmentLog
                                                                      }
                                                                      }
                                                                      +

                                                                      Webhooks

                                                                      Qovery allows you to create webhooks at organization-level so that, when an event happens on an environment within your organization, you can get notified on external applications.

                                                                      This is useful for the following use cases:

                                                                      • integrate Qovery with an exeternal tool that needs to be informed when the deployment status changes.
                                                                      • share within a slack channel any deployment status change for your environments.

                                                                      You can trigger webhooks when:

                                                                      • A deployment has started in the environment.
                                                                      • A deployment has been successful in the environment.
                                                                      • A deployment has been cancelled in the environment.
                                                                      • A deployment has failed in the environment.

                                                                      Two types of webhooks can be created within Qovery:

                                                                      • Standard: this type of webhook will send a payload to the defined url with a Qovery proprietary format (check out our Webhook payload documentation for more information on the payload format)
                                                                      • Slack: this type of webhook will send pre-formatted messages using the Slack messaging syntax. Have a look at our Slack integration for more information on the integration.

                                                                      Creating a Webhook

                                                                      To create a webhook via the Qovery Console:

                                                                      1. Open the Organization settings and the Webhook section

                                                                        Access webhook section

                                                                      2. Press the Add New button.

                                                                      3. Enter the following parameters:

                                                                        ParameterUsage
                                                                        URLThe webhook URL provided by the external application you want to receive notifications on.
                                                                        "kind"Specify which kind of webhook you want to create. At the moment, you can specify : "kind": "STANDARD" to create a generic webhook, or "kind": "SLACK" to create a Slack webhook.
                                                                        "description"(Optional) Enter a self-explanatory description of what your webhook does. In the example, "description": "slack notifications" clearly states that the webhook triggers notifications on Slack.
                                                                        "secret"(Optional) Specify the secret to be used when calling the specified webhook URL
                                                                        "events"List all the events you want to be notified about.
                                                                        "environment_types_filter"(Optional) If you only want to get notified about events happening on one or several specific type(s) or environment(s), you can provide a list using the following possible values: "PRODUCTION", "DEVELOPMENT", "STAGING" and "PREVIEW".

                                                                        Please note that "environment_types_filter" can be used together with "project_names_filter".
                                                                        "project_names_filter"(Optional) If you only want to get notified about events happening in one or several specific projects, you can provide a list of project names that will act as a filter. Notifications will then only be triggered for projects whose names match or, if you're using a wildcard, start with one of the values from your list.

                                                                        Please note that "project_names_filter" is not case-sensitive, accepts wildcards, and can be used together with "environment_types_filter".

                                                                        And press the Create button.

                                                                      Editing a Webhook

                                                                      From the webhook page, press the Wheel button to edit the webhook.

                                                                      If you want to temporally disable the webhook, you can disable it by clicking on the Enable switch.

                                                                      Delete a Webhook

                                                                      From the webhook page, press the Bin button to delete the webhook. A confirmation modal will ask you to confirm the operation.

                                                                      Webhook payload

                                                                      Here is an example of a Qovery Webhook standard payload. The payload is sent as a POST request to the specified URL.

                                                                      Deployment payload

                                                                      This payload is sent when a deployment starts, is cancelled, is successful or fails.

                                                                      {
                                                                      "created_at": "2020-10-04T14:00:00.000Z",
                                                                      "event_type": "DEPLOYMENT_STARTED|DEPLOYMENT_CANCELLED|DEPLOYMENT_SUCCESSFUL|DEPLOYMENT_FAILURE",
                                                                      "payload_type": "DEPLOYMENT", // no other option at the moment
                                                                      "payload_id": "5f7a5b0c-7b7d-4b0a-8b0a-5f7a5b0c7b7d",
                                                                      "payload": {
                                                                      "id": "5f7a5b0c-7b7d-4b0a-8b0a-5f7a5b0c7b7d",
                                                                      "current_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "desired_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "organization": {...}, // doc: https://api-doc.qovery.com/#tag/Organization-Main-Calls/operation/getOrganization
                                                                      "project": {...}, // doc: https://api-doc.qovery.com/#tag/Project-Main-Calls/operation/getProject
                                                                      "environment": {...}, // doc: https://api-doc.qovery.com/#tag/Environment-Main-Calls/operation/getEnvironment
                                                                      "applications": [
                                                                      {
                                                                      "current_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "desired_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "application": {...} // doc: https://api-doc.qovery.com/#tag/Application-Main-Calls/operation/getApplication
                                                                      }
                                                                      ],
                                                                      "databases": [
                                                                      {
                                                                      "current_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "desired_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "database": {...} // doc: https://api-doc.qovery.com/#tag/Database-Main-Calls/operation/getDatabase
                                                                      }
                                                                      ],
                                                                      "containers": [
                                                                      {
                                                                      "current_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "desired_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "container": {...} // doc: https://api-doc.qovery.com/#tag/Container-Main-Calls/operation/getContainer
                                                                      }
                                                                      ],
                                                                      "jobs": [
                                                                      {
                                                                      "current_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "desired_status": "ENUM_TYPE", // doc: https://github.com/Qovery/qovery-openapi-spec/blob/main/src/schemas/enums/State.yaml
                                                                      "job": {...} // doc: https://api-doc.qovery.com/#tag/Job-Main-Calls/operation/getJob
                                                                      }
                                                                      ],
                                                                      "logs": [...] // doc: https://api-doc.qovery.com/#tag/Environment-Logs/operation/listEnvironmentLog
                                                                      }
                                                                      }
                                                                      - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/interface/cli/index.html b/docs/using-qovery/interface/cli/index.html index c151e91278..1b73bcd23f 100644 --- a/docs/using-qovery/interface/cli/index.html +++ b/docs/using-qovery/interface/cli/index.html @@ -21,38 +21,38 @@ - + - + - + - + - + - + - + - + - + - + - + - + - +
                                                                      -

                                                                      CLI

                                                                      Qovery provides a very easy to use CLI (Command Line Interface) designed to fit the developer workflow perfectly.


                                                                      The purpose of the CLI is to integrate seamlessly with your development workflow:

                                                                      1. Write code
                                                                      2. Commit
                                                                      3. Qovery - deploy a new version of your application
                                                                      4. Qovery CLI - check the status of your application
                                                                      5. Qovery CLI - debug your application
                                                                      6. Repeat

                                                                      First usage

                                                                      Install

                                                                      To download and install Qovery CLI on any Linux distribution:

                                                                      $ curl -s https://get.qovery.com | bash

                                                                      Sign up

                                                                      # Sign up and sign in command
                                                                      $ qovery auth

                                                                      Your browser window with sign-in options will open.

                                                                      Qovery Sign-up page

                                                                      Click here to authorize Qovery to clone and build your applications.

                                                                      Connect Github

                                                                      Congratulations, you are logged-in.

                                                                      Help

                                                                      You can see all the commands available by executing:

                                                                      $ qovery help
                                                                      Help output
                                                                      $ qovery help
                                                                      A Command-line Interface of the Qovery platform
                                                                      +

                                                                      CLI

                                                                      Qovery provides a very easy to use CLI (Command Line Interface) designed to fit the developer workflow perfectly.


                                                                      The purpose of the CLI is to integrate seamlessly with your development workflow:

                                                                      1. Write code
                                                                      2. Commit
                                                                      3. Qovery - deploy a new version of your application
                                                                      4. Qovery CLI - check the status of your application
                                                                      5. Qovery CLI - debug your application
                                                                      6. Repeat

                                                                      First usage

                                                                      Install

                                                                      To download and install Qovery CLI on any Linux distribution:

                                                                      $ curl -s https://get.qovery.com | bash

                                                                      Sign up

                                                                      # Sign up and sign in command
                                                                      $ qovery auth

                                                                      Your browser window with sign-in options will open.

                                                                      Qovery Sign-up page

                                                                      Click here to authorize Qovery to clone and build your applications.

                                                                      Connect Github

                                                                      Congratulations, you are logged-in.

                                                                      Help

                                                                      You can see all the commands available by executing:

                                                                      $ qovery help
                                                                      Help output
                                                                      $ qovery help
                                                                      A Command-line Interface of the Qovery platform
                                                                      Usage:
                                                                      qovery [command]
                                                                      Available Commands:
                                                                      application Manage applications
                                                                      auth Log in to Qovery
                                                                      completion Generate the autocompletion script for the specified shell
                                                                      console Opens the application in Qovery Console in your browser
                                                                      container Manage containers
                                                                      context Manage CLI context
                                                                      cronjob Manage cronjobs
                                                                      database Manage databases
                                                                      env Manage Environment Variables and Secrets
                                                                      environment Manage environments
                                                                      help Help about any command
                                                                      lifecycle Manage lifecycle jobs
                                                                      log Print your application logs
                                                                      service Manage services
                                                                      shell Connect to an application container
                                                                      status Print the status of your application
                                                                      token Generate an API token
                                                                      upgrade Upgrade Qovery CLI to latest version
                                                                      version Print installed version of the Qovery CLI
                                                                      Flags:
                                                                      -h, --help help for qovery
                                                                      @@ -80,29 +80,29 @@
                                                                      ~ $ qovery environment deploy
                                                                      Environment is deploying!

                                                                      Managing the Deployment Pipeline

                                                                      In the following sections we will describe how to modify the Deployment Pipeline.

                                                                      List stages

                                                                      You can list all the stages of your environment by using the following command:

                                                                      qovery environment stage list

                                                                      Add a stage

                                                                      You can add a new stage by using the following command:

                                                                      qovery environment stage create -n <name> -d <description>

                                                                      Note that the stage will be added at the end of the pipeline (the highest number)

                                                                      Modify a stage

                                                                      You can modify a stage by using the following command:

                                                                      qovery environment stage edit -n <original name> --new-name <new name> --new-description <new description>

                                                                      Delete a stage

                                                                      You can modify a stage by using the following command:

                                                                      qovery environment stage delete -n <name>

                                                                      Change stage for a service

                                                                      You can modify the stage associated to a service by using the following command:

                                                                      qovery environment stage move -n <service name> --stage <stage name>

                                                                      Support

                                                                      Do you have any issues with Qovery CLI? Open an issue.

                                                                      - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/interface/index.html b/docs/using-qovery/interface/index.html index 443add6c96..6ff0e39b1f 100644 --- a/docs/using-qovery/interface/index.html +++ b/docs/using-qovery/interface/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                                      -

                                                                      Interface

                                                                      In the following subsections, you'll learn how to use the web interface, the CLI (Command Line Interface) and other interfaces to deploy your application with Qovery.

                                                                      Cli
                                                                      Rest api
                                                                      Terraform interface
                                                                      Web interface
                                                                      Resources
                                                                        +

                                                                        Interface

                                                                        In the following subsections, you'll learn how to use the web interface, the CLI (Command Line Interface) and other interfaces to deploy your application with Qovery.

                                                                        Cli
                                                                        Rest api
                                                                        Terraform interface
                                                                        Web interface
                                                                        Resources
                                                                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/interface/rest-api/index.html b/docs/using-qovery/interface/rest-api/index.html index ae6ca5bac3..2b3b7c4e22 100644 --- a/docs/using-qovery/interface/rest-api/index.html +++ b/docs/using-qovery/interface/rest-api/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                                          -

                                                                          REST API

                                                                          Use the Qovery REST API to programmatically create infrastructure and deploy your applications. The only limit is your imagination. Find the Qovery API documentation and the OpenAPI spec to generate your own Qovery client with your favorite programming language.

                                                                          API clients

                                                                          Here is the list of clients available to use the Qovery Web API.

                                                                          LanguageLink
                                                                          Golangsource
                                                                          Pythonsource
                                                                          Typescriptsource
                                                                          Javascriptsource

                                                                          Generate an API token

                                                                          You can generate an API token from the Qovery CLI or via the Qovery Web Console.

                                                                          API Documentation

                                                                          The API documentation is available here

                                                                          +

                                                                          REST API

                                                                          Use the Qovery REST API to programmatically create infrastructure and deploy your applications. The only limit is your imagination. Find the Qovery API documentation and the OpenAPI spec to generate your own Qovery client with your favorite programming language.

                                                                          API clients

                                                                          Here is the list of clients available to use the Qovery Web API.

                                                                          LanguageLink
                                                                          Golangsource
                                                                          Pythonsource
                                                                          Typescriptsource
                                                                          Javascriptsource

                                                                          Generate an API token

                                                                          You can generate an API token from the Qovery CLI or via the Qovery Web Console.

                                                                          API Documentation

                                                                          The API documentation is available here

                                                                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/interface/terraform-interface/index.html b/docs/using-qovery/interface/terraform-interface/index.html index 30ba38d3a8..c79c652b4b 100644 --- a/docs/using-qovery/interface/terraform-interface/index.html +++ b/docs/using-qovery/interface/terraform-interface/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                                          - +
                                                                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/interface/web-interface/index.html b/docs/using-qovery/interface/web-interface/index.html index 3a7e12302b..9fd676db5f 100644 --- a/docs/using-qovery/interface/web-interface/index.html +++ b/docs/using-qovery/interface/web-interface/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                                          -

                                                                          Web interface

                                                                          Qovery provides a management console which allows you to interact with your projects and manage your environments.

                                                                          First sign-up

                                                                          Sign in to the Qovery web interface.

                                                                          Qovery Sign-up page

                                                                          Deploy your first application

                                                                          Now that you have signed up on the web interface, check out how to deploy your first application

                                                                          +

                                                                          Web interface

                                                                          Qovery provides a management console which allows you to interact with your projects and manage your environments.

                                                                          First sign-up

                                                                          Sign in to the Qovery web interface.

                                                                          Qovery Sign-up page

                                                                          Deploy your first application

                                                                          Now that you have signed up on the web interface, check out how to deploy your first application

                                                                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/maintenance/index.html b/docs/using-qovery/maintenance/index.html index bc1f80f22e..1bb88a62a4 100644 --- a/docs/using-qovery/maintenance/index.html +++ b/docs/using-qovery/maintenance/index.html @@ -21,36 +21,36 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                                          -

                                                                          Maintenance

                                                                          This guide will provide inputs about maintenance with Qovery. Qovery provides automatic and silent updates as much as possible. With and without cloud providers.

                                                                          Kubernetes and components, patches, and upgrades

                                                                          Qovery manages Kubernetes updates through the Cloud provider update mechanism and ensures full compatibility with all deployed infrastructure components (Nginx ingress, cert-manager, CNI, CSI, etc.) inside the Kubernetes cluster.

                                                                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/troubleshoot/application-troubleshoot/index.html b/docs/using-qovery/troubleshoot/application-troubleshoot/index.html index ab2aeff346..5c6f865c1a 100644 --- a/docs/using-qovery/troubleshoot/application-troubleshoot/index.html +++ b/docs/using-qovery/troubleshoot/application-troubleshoot/index.html @@ -21,60 +21,60 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                                          -

                                                                          Application Troubleshoot

                                                                          Within this section you will find the common errors you might encounter when deploying or running your applications with Qovery

                                                                          Liveness/Readiness failed, connect: connection refused

                                                                          If you encounter this kind of error on the Liveness and/or Readiness probe during an application deployment phase:

                                                                          Readiness probe failed: dial tcp 100.64.2.230:80: connect: connection refused
                                                                          Liveness probe failed: dial tcp 100.64.2.230:80: connect: connection refused

                                                                          That means your application may not able to start, or has started but takes too many time to start.

                                                                          Here are the possible reasons for starting issues you should check:

                                                                          1. The declared port on Qovery (here 80), does not match your application's opening port. Check your application port, and set the correct port to your application configuration.

                                                                          2. Ensure your application is not listening onto localhost (127.0.0.1) or a specific IP. But set it to all interfaces (0.0.0.0).

                                                                          3. Your application takes too long to start and the liveness probe is flagging your application as unhealthy. Try to increase the Liveness Initial Delay parameter, to inform Kubernetes to delay the time before checking your application availability. Set it for example to 120.

                                                                          My app is crashing, how do I connect to investigate?

                                                                          Goal: You want to connect to your container's application to debug your application

                                                                          First, try to use qovery shell command from the Qovery CLI. It's a safe method to connect to your container and debug your application.

                                                                          If your app is crashing in the first seconds, you'll lose the connection to your container, making the debug almost impossible, then continue reading.

                                                                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/troubleshoot/cluster-troubleshoot/index.html b/docs/using-qovery/troubleshoot/cluster-troubleshoot/index.html index aab596abb9..e6acbef6a3 100644 --- a/docs/using-qovery/troubleshoot/cluster-troubleshoot/index.html +++ b/docs/using-qovery/troubleshoot/cluster-troubleshoot/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                                          -

                                                                          Cluster Troubleshoot

                                                                          Within this section you will find the common errors you might encounter when deploying or running your clusters with Qovery

                                                                          I don't have Qovery access anymore, how could I delete Qovery deployed resources on my AWS account?

                                                                          Unfortunately, there is no automatic way to do it with Qovery once we don't have access. However, AWS provides an easy way to retrieve those resources, so you can manually perform the delete. To do so, go on the AWS web console, and search for "Resource Groups & Tag Editor" service, then:

                                                                          Resource groups search by tag

                                                                          1. Click on "Create Resource Group".
                                                                          2. In Tags, enter: "ClusterLongId".
                                                                          3. In the "Optional Tag value", enter the Qovery cluster ID. If you don't have it, let AWS suggest it for you. If you have Qovery deployed elements remainings, it will propose the Cluster long ID automatically.
                                                                          4. Click on "Add".
                                                                          5. You should see the filter with the information you just entered.
                                                                          6. Click on "Preview groups resources".
                                                                          7. You'll have all elements deployed by Qovery and you can delete what you want.

                                                                          My cloud account has been blocked, what should I do?

                                                                          If you encounter this kind of error during an infrastructure deployment (including managed DBs):

                                                                          This account is currently blocked by your cloud provider, please contact them directly.

                                                                          Or

                                                                          This AWS account is currently blocked and not recognized as a valid account.
                                                                          Please contact aws-verification@amazon.com directly to get more details.
                                                                          Maybe you are not allowed to use your free tier in this region?
                                                                          Maybe you need to provide billing info?

                                                                          This error is likely due to a billing issue or blocked free-tier usage in the given region.

                                                                          Unfortunately, there is nothing Qovery can do. You need to reach out directly to your cloud provider to get more details and get your account unblocked.

                                                                          More

                                                                          You are looking to troubleshoot your application with Qovery? Read this very short guide

                                                                          +

                                                                          Cluster Troubleshoot

                                                                          Within this section you will find the common errors you might encounter when deploying or running your clusters with Qovery

                                                                          I don't have Qovery access anymore, how could I delete Qovery deployed resources on my AWS account?

                                                                          Unfortunately, there is no automatic way to do it with Qovery once we don't have access. However, AWS provides an easy way to retrieve those resources, so you can manually perform the delete. To do so, go on the AWS web console, and search for "Resource Groups & Tag Editor" service, then:

                                                                          Resource groups search by tag

                                                                          1. Click on "Create Resource Group".
                                                                          2. In Tags, enter: "ClusterLongId".
                                                                          3. In the "Optional Tag value", enter the Qovery cluster ID. If you don't have it, let AWS suggest it for you. If you have Qovery deployed elements remainings, it will propose the Cluster long ID automatically.
                                                                          4. Click on "Add".
                                                                          5. You should see the filter with the information you just entered.
                                                                          6. Click on "Preview groups resources".
                                                                          7. You'll have all elements deployed by Qovery and you can delete what you want.

                                                                          My cloud account has been blocked, what should I do?

                                                                          If you encounter this kind of error during an infrastructure deployment (including managed DBs):

                                                                          This account is currently blocked by your cloud provider, please contact them directly.

                                                                          Or

                                                                          This AWS account is currently blocked and not recognized as a valid account.
                                                                          Please contact aws-verification@amazon.com directly to get more details.
                                                                          Maybe you are not allowed to use your free tier in this region?
                                                                          Maybe you need to provide billing info?

                                                                          This error is likely due to a billing issue or blocked free-tier usage in the given region.

                                                                          Unfortunately, there is nothing Qovery can do. You need to reach out directly to your cloud provider to get more details and get your account unblocked.

                                                                          More

                                                                          You are looking to troubleshoot your application with Qovery? Read this very short guide

                                                                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/troubleshoot/database-troubleshoot/index.html b/docs/using-qovery/troubleshoot/database-troubleshoot/index.html index 7aabc8ad8a..79f177c5cc 100644 --- a/docs/using-qovery/troubleshoot/database-troubleshoot/index.html +++ b/docs/using-qovery/troubleshoot/database-troubleshoot/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                                          -

                                                                          Database Troubleshoot

                                                                          Within this section you will find the common errors you might encounter when deploying or running your databases with Qovery

                                                                          During a managed database delete, I've this error: SnapshotQuotaExceeded

                                                                          This errors occurs because Qovery creates a snapshot before the delete of the database. This to avoid a user mistake who delete a database accidentally.

                                                                          To fix this issue, you have 2 solutions:

                                                                          1. You certainly have useless snapshots, from old databases or old ones you don't want to keep anymore. Delete them directly from your Cloud Provider web interface. Here is an example on AWS:

                                                                            • Search for the database service (here RDS)
                                                                            • Select the Snapshots menu
                                                                            • Select the snapshots to delete

                                                                            Database snapshots

                                                                          2. Open a ticket to the Cloud Provider support, and as to raise this limit.

                                                                          +

                                                                          Database Troubleshoot

                                                                          Within this section you will find the common errors you might encounter when deploying or running your databases with Qovery

                                                                          During a managed database delete, I've this error: SnapshotQuotaExceeded

                                                                          This errors occurs because Qovery creates a snapshot before the delete of the database. This to avoid a user mistake who delete a database accidentally.

                                                                          To fix this issue, you have 2 solutions:

                                                                          1. You certainly have useless snapshots, from old databases or old ones you don't want to keep anymore. Delete them directly from your Cloud Provider web interface. Here is an example on AWS:

                                                                            • Search for the database service (here RDS)
                                                                            • Select the Snapshots menu
                                                                            • Select the snapshots to delete

                                                                            Database snapshots

                                                                          2. Open a ticket to the Cloud Provider support, and as to raise this limit.

                                                                          - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/troubleshoot/index.html b/docs/using-qovery/troubleshoot/index.html index 152e2c1ade..3b0f141e8a 100644 --- a/docs/using-qovery/troubleshoot/index.html +++ b/docs/using-qovery/troubleshoot/index.html @@ -21,59 +21,59 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                                          -

                                                                          Troubleshoot

                                                                          This guide is divided into three sections that will guide you through your troubleshooting depending on the issue you face

                                                                          • Deployment issues: guide through to fix the deployment
                                                                          • Run issues : App in error -> provide Pod errors, performance issues (?), dropped request(nginx investigations)
                                                                          • Cluster issues:
                                                                          Application troubleshoot
                                                                          Cluster troubleshoot
                                                                          Database troubleshoot
                                                                          Lifecycle troubleshoot
                                                                          Resources
                                                                            +

                                                                            Troubleshoot

                                                                            This guide is divided into three sections that will guide you through your troubleshooting depending on the issue you face

                                                                            • Deployment issues: guide through to fix the deployment
                                                                            • Run issues : App in error -> provide Pod errors, performance issues (?), dropped request(nginx investigations)
                                                                            • Cluster issues:
                                                                            Application troubleshoot
                                                                            Cluster troubleshoot
                                                                            Database troubleshoot
                                                                            Lifecycle troubleshoot
                                                                            Resources
                                                                              - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/troubleshoot/lifecycle-troubleshoot/index.html b/docs/using-qovery/troubleshoot/lifecycle-troubleshoot/index.html index e6b6b64116..d18ef97f6c 100644 --- a/docs/using-qovery/troubleshoot/lifecycle-troubleshoot/index.html +++ b/docs/using-qovery/troubleshoot/lifecycle-troubleshoot/index.html @@ -21,61 +21,61 @@ - + - + - + - + - + - + - + - + - + - + - + - +
                                                                              -

                                                                              Lifecycle Job Troubleshoot

                                                                              Within this section you will find the common errors you might encounter when deploying or running your Lifecycle Job with Qovery

                                                                              Joib failed: either it couldn't be executed correctly after X retries or its execution didn't finish after Y minutes

                                                                              This errors occurs in the following two cases:

                                                                              Job code execution failures +

                                                                              Lifecycle Job Troubleshoot

                                                                              Within this section you will find the common errors you might encounter when deploying or running your Lifecycle Job with Qovery

                                                                              Joib failed: either it couldn't be executed correctly after X retries or its execution didn't finish after Y minutes

                                                                              This errors occurs in the following two cases:

                                                                              Job code execution failures The pod running your lifecycle job is crashing due to an exception in your code or OOM issue. Have a look at the Live Logs of your Lifecycle job to understand from where the issue is coming from your code.

                                                                              Job execution timeout The code run in your job is taking more time than expected and thus it's execution is stopped. If your code needs more time to be excecuted, increase the Max Duration value within the Lifecycle Job configuration page

                                                                              - + - + - + - + - + - + - + - + - + - + - + diff --git a/e06f2af5.44c7ca39.js b/e06f2af5.44c7ca39.js new file mode 100644 index 0000000000..f8c3de376d --- /dev/null +++ b/e06f2af5.44c7ca39.js @@ -0,0 +1,2 @@ +/*! For license information please see e06f2af5.44c7ca39.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[239],{391:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),i=(n(0),n(425)),a=n(434),c={last_modified_on:"2021-09-06",$schema:"/.meta/.schemas/guides.json",title:"How to use Github Organizations with Qovery",description:"How to configure Github and Qovery to use your Github Organization repositories with Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},u={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to use Github Organizations with Qovery",description:"How to configure Github and Qovery to use your Github Organization repositories with Qovery",permalink:"/guides/tutorial/github-organization-repository-access",readingTime:"1 min read",source:"@site/guides/tutorial/github-organization-repository-access.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to use Github Organizations with Qovery",truncated:!1,prevItem:{title:"How to use CloudFront with a React frontend application on Qovery",permalink:"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery"},nextItem:{title:"How To Use Lifecycle Job To Deploy Any Kind Of Resources",permalink:"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources"}},s=[],l={rightToc:s};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"When you create a new application, you need to connect it to a Git repository.\nIf your code is stored in a Github Organization, Qovery needs privileges to access your Organization's repositories\nin order to run deployments."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/github-org-access-1.png",alt:"Github Organization"})),Object(i.b)("p",null,"If Organization repositories are missing in the repository selector, you will need to grant Qovery access to your organization."),Object(i.b)(a.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/settings/connections/applications/f54d3da8bad40800b3bf"}),"Qovery Github Application"))),Object(i.b)("li",null,Object(i.b)("p",null,"Make sure Qovery has access to the organization you want to use (grant permissions if necessary)"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/github-org-access-2.png",alt:"Github Organization"}))))),Object(i.b)("p",null,"After following the steps from above, you should be able to select your organization repositories in Qovery Console while creating an application."))}p.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),l=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,a=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(n),b=r,y=p["".concat(a,".").concat(b)]||p[b]||f[b]||i;return n?o.a.createElement(y,c({ref:t},s,{components:n})):o.a.createElement(y,c({ref:t},s))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=b;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,a[1]=c;for(var s=2;s"\n logGroupName: "/aws/eks/fluentbit-/logs"\n logRetentionDays: 7\n\nenv:\n - name: "AWS_ACCESS_KEY_ID"\n value: ""\n - name: "AWS_SECRET_ACCESS_KEY"\n value: ""\n\nfirehose:\n enabled: false\n\nkinesis:\n enabled: false\n\nelasticsearch:\n enabled: false\n')),Object(r.b)("p",null,"You can take a look at additional configuration options on the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://artifacthub.io/packages/helm/aws/aws-for-fluent-bit"}),"AWS provided chart")," "),Object(r.b)("p",null,"Then deploy fluent-bit with the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install aws-for-fluent-bit -f values.yaml --namespace fluent-bit --create-namespace eks/aws-for-fluent-bit --version 0.1.21\n")),Object(r.b)("p",null,"You should start seeing fluent-bit pods. Take a look at the logs to ensure there is no configuration issue."),Object(r.b)("h2",{id:"cloudwatch-usage"},"Cloudwatch usage"),Object(r.b)("p",null,"You can now use Cloudwatch to look at your logs. Connect to Cloudwatch, go into the ",Object(r.b)("inlineCode",{parentName:"p"},"Logs insight")," section, then you can perform queries:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-cloudwatch/cloudwatch-search.png",alt:"cloudwatch search"})),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Select the fluent-bit group of logs"),Object(r.b)("li",{parentName:"ol"},"Create a query (",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html"}),"syntax examples"),")"),Object(r.b)("li",{parentName:"ol"},"Run your query"),Object(r.b)("li",{parentName:"ol"},"See the result and expand to filter on other elements")))}p.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),u=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=a,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||r;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:o(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var a=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&a(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),o=n.n(a),r=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),o=n(0),r=n.n(o),i=n(39),c=n(430),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,p=Object(c.a)(u),b=Object(o.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?r.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,a;d&&e&&p&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):r.a.createElement("a",Object(a.a)({},e,{href:u}))}},429:function(e,t,n){"use strict";var a=n(0),o=n.n(a),r=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+s,n),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},a?o.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?o.a.createElement("a",{href:p,target:u,className:b},d):o.a.createElement(r.a,{to:p,className:b},d)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see e1becc8e.623d578a.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[240],{392:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var a=n(1),o=n(9),r=(n(0),n(425)),i=(n(431),n(424)),c=(n(429),{last_modified_on:"2022-11-16",$schema:"/.meta/.schemas/guides.json",title:"Integrate your application logs to Cloudwatch",description:"Add Kubernetes pod logs into Cloudwatch to perform full text search",author_github:"https://github.com/deimosfr",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Integrate your application logs to Cloudwatch",description:"Add Kubernetes pod logs into Cloudwatch to perform full text search",permalink:"/guides/tutorial/cloudwatch-integration",readingTime:"4 min read",source:"@site/guides/tutorial/cloudwatch-integration.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Integrate your application logs to Cloudwatch",truncated:!1,prevItem:{title:"Install Qovery your Google Cloud Platform account",permalink:"/guides/cloud-provider/guide-google-cloud-platform"},nextItem:{title:"Kubernetes observability and monitoring with Datadog",permalink:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog"}},s=[{value:"AWS permissions for Cloudwatch",id:"aws-permissions-for-cloudwatch",children:[]},{value:"Helm",id:"helm",children:[]},{value:"Cloudwatch usage",id:"cloudwatch-usage",children:[]}],u={rightToc:s};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Qovery provides by default an easy way to get access to your logs through the Console or the CLI. For statistics, debugging or security reasons, you may want to access all logs and perform a full-text search inside them."),Object(r.b)("p",null,"Qovery implementation is based on ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://grafana.com/oss/loki/"}),"Loki")," for performance and cost-effective reasons. However, Loki is not a full-text search engine. It is a log aggregation system. It is not designed to be queried directly."),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Why Qovery does not provides current Loki access?"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"As mentioned Loki is not a full-text search and results may not reflect what you are looking for."),Object(r.b)("li",{parentName:"ol"},"Loki is configured to answer usage from Qovery Console and CLI. Using it directly may impact Qovery Console and CLI performances or worst, lose logs and make it irresponsive."))),Object(r.b)("p",null,"Serveral solutions exists, with and without 3rd parties. We will cover here a solution without a third party. But if you're interrested, you can take a look at ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/"}),"Datadog integration"),"."),Object(r.b)("p",null,"Note: in this tutorial, we are using Fluent-bit with proposed solutions above. However, if none of those solutions suits your needs, feel free to look at supported solution on the official website."),Object(r.b)("h2",{id:"aws-permissions-for-cloudwatch"},"AWS permissions for Cloudwatch"),Object(r.b)("p",null,"We will create a dedicated service account (note: STS account can be used, but for simplicity reasons, we will use a dedicated service account)."),Object(r.b)("p",null,"On IAM create a policy with the following permissions, and name this policy ",Object(r.b)("inlineCode",{parentName:"p"},"fluent-bit-write-policy"),":"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-policy-content.png",alt:"policy content"})),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Sid": "CloudWatchLogs",\n "Effect": "Allow",\n "Action": [\n "logs:CreateLogGroup",\n "logs:CreateLogStream",\n "logs:PutRetentionPolicy",\n "logs:PutLogEvents"\n ],\n "Resource": "arn:aws:logs:*:*:*"\n }\n ]\n}\n')),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-policy-create.png",alt:"policy create"})),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You can enforce this policy by cluster if you need, by updating the ",Object(r.b)("inlineCode",{parentName:"p"},"Resource")," content. But we want to keep it simple in this tutorial, so we will apply it to all clusters (so you can reuse the same service account if you want for other clusters).")),Object(r.b)("p",null,"Once done, let's create a user and attach the policy to it:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-user-create.png",alt:"User create"})),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-cloudwatch-permissions.png",alt:"User permissions"})),Object(r.b)("p",null,"Finish the user creation and keep credentials for the coming section."),Object(r.b)("h2",{id:"helm"},"Helm"),Object(r.b)("p",null,"Ensure you have the following elements before going ahead:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Helm should be installed on your machine. If you don't have it, you can follow the ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://helm.sh/docs/intro/install/"}),"official documentation"),"."),Object(r.b)("li",{parentName:"ol"},"You need Kubeconfig configuration file and permissions to access the cluster. You can use the same documentation as kubectl to ",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"get the kubeconfig file"),".")),Object(r.b)("p",null,"We will use ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://artifacthub.io/packages/helm/aws/aws-for-fluent-bit"}),"AWS fluent-bit Helm Chart")," to setup logs streaming:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add eks https://aws.github.io/eks-charts\n")),Object(r.b)("p",null,"Create on your workstation a ",Object(r.b)("inlineCode",{parentName:"p"},"values.yaml")," file to setup your custom configuration and adapt required fields:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'cloudWatch:\n enabled: true\n region: ""\n logGroupName: "/aws/eks/fluentbit-/logs"\n logRetentionDays: 7\n\nenv:\n - name: "AWS_ACCESS_KEY_ID"\n value: ""\n - name: "AWS_SECRET_ACCESS_KEY"\n value: ""\n\nfirehose:\n enabled: false\n\nkinesis:\n enabled: false\n\nelasticsearch:\n enabled: false\n')),Object(r.b)("p",null,"You can take a look at additional configuration options on the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://artifacthub.io/packages/helm/aws/aws-for-fluent-bit"}),"AWS provided chart")," "),Object(r.b)("p",null,"Then deploy fluent-bit with the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install aws-for-fluent-bit -f values.yaml --namespace fluent-bit --create-namespace eks/aws-for-fluent-bit --version 0.1.21\n")),Object(r.b)("p",null,"You should start seeing fluent-bit pods. Take a look at the logs to ensure there is no configuration issue."),Object(r.b)("h2",{id:"cloudwatch-usage"},"Cloudwatch usage"),Object(r.b)("p",null,"You can now use Cloudwatch to look at your logs. Connect to Cloudwatch, go into the ",Object(r.b)("inlineCode",{parentName:"p"},"Logs insight")," section, then you can perform queries:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-cloudwatch/cloudwatch-search.png",alt:"cloudwatch search"})),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Select the fluent-bit group of logs"),Object(r.b)("li",{parentName:"ol"},"Create a query (",Object(r.b)("a",Object(a.a)({parentName:"li"},{href:"https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html"}),"syntax examples"),")"),Object(r.b)("li",{parentName:"ol"},"Run your query"),Object(r.b)("li",{parentName:"ol"},"See the result and expand to filter on other elements")))}p.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),u=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=a,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||r;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:o(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var a=n(28).f,o=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in o||n(10)&&a(o,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),o=n.n(a),r=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(r.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),o=n(0),r=n.n(o),i=n(39),c=n(432),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,u=n||l,p=Object(c.a)(u),b=Object(o.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,p]),u&&p?r.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var n,a;d&&e&&p&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):r.a.createElement("a",Object(a.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var a=n(0),o=n.n(a),r=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,b=c()("jump-to","jump-to--"+s,n),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},a?o.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return u?o.a.createElement("a",{href:p,target:u,className:b},d):o.a.createElement(r.a,{to:p,className:b},d)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/e3c664e0.7a71f042.js.LICENSE.txt b/e1becc8e.623d578a.js.LICENSE.txt similarity index 100% rename from e3c664e0.7a71f042.js.LICENSE.txt rename to e1becc8e.623d578a.js.LICENSE.txt diff --git a/e1e0a511.cf8b515f.js b/e1e0a511.f122b493.js similarity index 90% rename from e1e0a511.cf8b515f.js rename to e1e0a511.f122b493.js index 954015748b..2fe854f998 100644 --- a/e1e0a511.cf8b515f.js +++ b/e1e0a511.f122b493.js @@ -1,2 +1,2 @@ -/*! For license information please see e1e0a511.cf8b515f.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[238],{390:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return c})),r.d(t,"metadata",(function(){return l})),r.d(t,"rightToc",(function(){return u})),r.d(t,"default",(function(){return p}));var n=r(1),o=r(9),i=(r(0),r(422)),a=r(421),c={last_modified_on:"2023-05-20",title:"New Relic",description:"Learn how to configure and plug your New Relic account"},l={id:"using-qovery/integration/monitoring/new-relic",title:"New Relic",description:"Learn how to configure and plug your New Relic account",source:"@site/docs/using-qovery/integration/monitoring/new-relic.md",permalink:"/docs/using-qovery/integration/monitoring/new-relic",sidebar:"docs",previous:{title:"Datadog",permalink:"/docs/using-qovery/integration/monitoring/datadog"},next:{title:"Secret Manager",permalink:"/docs/using-qovery/integration/secret-manager"}},u=[{value:"Install NewRelic",id:"install-newrelic",children:[{value:"By using the Qovery Lifecycle Jobs",id:"by-using-the-qovery-lifecycle-jobs",children:[]},{value:"By using kubectl",id:"by-using-kubectl",children:[]}]}],s={rightToc:u};function p(e){var t=e.components,r=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"NewRelic is a recommended product to monitor and track down your application performance issue (APM). Qovery supports and recommends using NewRelic (or another monitoring/observability platform)."),Object(i.b)("h2",{id:"install-newrelic"},"Install NewRelic"),Object(i.b)("p",null,"To install NewRelic on Qovery, you have 2 choices:"),Object(i.b)("h3",{id:"by-using-the-qovery-lifecycle-jobs"},"By using the Qovery Lifecycle Jobs"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"Follow ",Object(i.b)("a",Object(n.a)({parentName:"li"},{href:"/guides/tutorial/how-to-deploy-helm-charts/"}),"this guide")," to deploy your NewRelic Helm Chart with the Qovery Lifecycle Jobs.")),Object(i.b)("h3",{id:"by-using-kubectl"},"By using kubectl"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(n.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"Connect to your Qovery Kubernetes cluster"),"."),Object(i.b)("li",{parentName:"ol"},"Use ",Object(i.b)("inlineCode",{parentName:"li"},"helm")," to ",Object(i.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/newrelic/helm-charts"}),"install NewRelic"),".")),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Helm is a Kubernetes package manager. NewRelic provides an official helm chart that you can use to install NewRelic on your Kubernetes infrastructure.")))}p.isMDXComponent=!0},420:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,a=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),f=n,y=p["".concat(a,".").concat(f)]||p[f]||b[f]||i;return r?o.a.createElement(y,c({ref:t},u,{components:r})):o.a.createElement(y,c({ref:t},u))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,a=new Array(i);a[0]=f;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,a[1]=c;for(var u=2;u1?arguments[1]:void 0,r),l=a>2?arguments[2]:void 0,u=void 0===l?r:o(l,r);u>c;)t[c++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see e1e0a511.f122b493.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[241],{393:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return c})),r.d(t,"metadata",(function(){return l})),r.d(t,"rightToc",(function(){return u})),r.d(t,"default",(function(){return p}));var n=r(1),o=r(9),i=(r(0),r(425)),a=r(424),c={last_modified_on:"2023-05-20",title:"New Relic",description:"Learn how to configure and plug your New Relic account"},l={id:"using-qovery/integration/monitoring/new-relic",title:"New Relic",description:"Learn how to configure and plug your New Relic account",source:"@site/docs/using-qovery/integration/monitoring/new-relic.md",permalink:"/docs/using-qovery/integration/monitoring/new-relic",sidebar:"docs",previous:{title:"Datadog",permalink:"/docs/using-qovery/integration/monitoring/datadog"},next:{title:"Secret Manager",permalink:"/docs/using-qovery/integration/secret-manager"}},u=[{value:"Install NewRelic",id:"install-newrelic",children:[{value:"By using the Qovery Lifecycle Jobs",id:"by-using-the-qovery-lifecycle-jobs",children:[]},{value:"By using kubectl",id:"by-using-kubectl",children:[]}]}],s={rightToc:u};function p(e){var t=e.components,r=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"NewRelic is a recommended product to monitor and track down your application performance issue (APM). Qovery supports and recommends using NewRelic (or another monitoring/observability platform)."),Object(i.b)("h2",{id:"install-newrelic"},"Install NewRelic"),Object(i.b)("p",null,"To install NewRelic on Qovery, you have 2 choices:"),Object(i.b)("h3",{id:"by-using-the-qovery-lifecycle-jobs"},"By using the Qovery Lifecycle Jobs"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"Follow ",Object(i.b)("a",Object(n.a)({parentName:"li"},{href:"/guides/tutorial/how-to-deploy-helm-charts/"}),"this guide")," to deploy your NewRelic Helm Chart with the Qovery Lifecycle Jobs.")),Object(i.b)("h3",{id:"by-using-kubectl"},"By using kubectl"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},Object(i.b)("a",Object(n.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"Connect to your Qovery Kubernetes cluster"),"."),Object(i.b)("li",{parentName:"ol"},"Use ",Object(i.b)("inlineCode",{parentName:"li"},"helm")," to ",Object(i.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/newrelic/helm-charts"}),"install NewRelic"),".")),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Helm is a Kubernetes package manager. NewRelic provides an official helm chart that you can use to install NewRelic on your Kubernetes infrastructure.")))}p.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,a=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),f=n,y=p["".concat(a,".").concat(f)]||p[f]||b[f]||i;return r?o.a.createElement(y,c({ref:t},u,{components:r})):o.a.createElement(y,c({ref:t},u))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,a=new Array(i);a[0]=f;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,a[1]=c;for(var u=2;u1?arguments[1]:void 0,r),l=a>2?arguments[2]:void 0,u=void 0===l?r:o(l,r);u>c;)t[c++]=e;return t}}}]); \ No newline at end of file diff --git a/e4310ee0.27f4cee2.js.LICENSE.txt b/e1e0a511.f122b493.js.LICENSE.txt similarity index 100% rename from e4310ee0.27f4cee2.js.LICENSE.txt rename to e1e0a511.f122b493.js.LICENSE.txt diff --git a/e3c664e0.7a71f042.js b/e3c664e0.c51149d9.js similarity index 93% rename from e3c664e0.7a71f042.js rename to e3c664e0.c51149d9.js index a2210f20a1..8979f9211f 100644 --- a/e3c664e0.7a71f042.js +++ b/e3c664e0.c51149d9.js @@ -1,2 +1,2 @@ -/*! For license information please see e3c664e0.7a71f042.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[239],{391:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),c=(n(0),n(422)),o=(n(429),n(421)),i=(n(426),{last_modified_on:"2023-12-11",title:"Running and Deployment Statuses",description:"Learn how to monitor your services"}),l={id:"using-qovery/deployment/running-and-deployment-statuses",title:"Running and Deployment Statuses",description:"Learn how to monitor your services",source:"@site/docs/using-qovery/deployment/running-and-deployment-statuses.md",permalink:"/docs/using-qovery/deployment/running-and-deployment-statuses",sidebar:"docs",previous:{title:"Deployment History",permalink:"/docs/using-qovery/deployment/deployment-history"},next:{title:"Logs",permalink:"/docs/using-qovery/deployment/logs"}},s=[{value:"Running Statuses",id:"running-statuses",children:[]},{value:"Environment Statuses",id:"environment-statuses",children:[]},{value:"Service Statuses",id:"service-statuses",children:[{value:"Pod status (Application instances)",id:"pod-status-application-instances",children:[]}]},{value:"Deployment Statuses",id:"deployment-statuses",children:[]}],b={rightToc:s};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(c.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(c.b)("p",null,"From any environment window on your ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),", you can monitor the running and deployment status of your environments and services."),Object(c.b)("p",{align:"center"},Object(c.b)("img",{src:"/img/deployment/run_deployment_statuses.png",alt:"Statuses"})),Object(c.b)("table",null,Object(c.b)("thead",{parentName:"table"},Object(c.b)("tr",{parentName:"thead"},Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Item"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"The dot in the service tab shows the environment running status. ",Object(c.b)("br",null)," For more information, see the Environment Statuses section below.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"2"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"The dot in the deployment tab shows the environment deployment status. ",Object(c.b)("br",null)," For more information, see the Deployment Statuses section below.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"3"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),'The label in the column "Service status" represents the running status of the service. ',Object(c.b)("br",null)," For more information, see Service Statuses section below.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"4"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),'The label in the column "Last deployment" represents the status of the latest deployment of the service. ',Object(c.b)("br",null)," For more information, see Deployment Statuses section below.")))),Object(c.b)("h2",{id:"running-statuses"},"Running Statuses"),Object(c.b)("p",null,"Thanks to Running statuses, you can find out which services are currently running on your platform, and which are interrupted. There are two types of run services available currently: environment statuses and service statuses."),Object(c.b)("h2",{id:"environment-statuses"},"Environment Statuses"),Object(c.b)("p",null,"When you access an environment on your ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),", you can check its status in real-time."),Object(c.b)("p",null,"The environment status is computed based on the statuses of all the services in that specific environment. Here are all the possible environment statuses:"),Object(c.b)("table",null,Object(c.b)("thead",{parentName:"table"},Object(c.b)("tr",{parentName:"thead"},Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Status"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STOPPED ",Object(c.b)("em",{parentName:"td"},"(Gray dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All the services are stopped.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STARTING ",Object(c.b)("em",{parentName:"td"},"(Loading Icon)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 service is starting.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STOPPING ",Object(c.b)("em",{parentName:"td"},"(Loading Icon)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 service is stopping.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"RUNNING ",Object(c.b)("em",{parentName:"td"},"(Green dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All services are running correctly.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ERROR ",Object(c.b)("em",{parentName:"td"},"(Red dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All services are in error status.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"WARNING ",Object(c.b)("em",{parentName:"td"},"(Orange dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 service is in error status (but not all of them).")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"COMPLETED ",Object(c.b)("em",{parentName:"td"},"(Green dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"The job execution has completed (only for cronjob and lifecycle jobs).")))),Object(c.b)("h2",{id:"service-statuses"},"Service Statuses"),Object(c.b)("p",null,"When you access an environment on your ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),', you can check the status of each service in that environment in real-time within the column "Service status".'),Object(c.b)("p",null,"Here are all the possible service statuses:"),Object(c.b)("table",null,Object(c.b)("thead",{parentName:"table"},Object(c.b)("tr",{parentName:"thead"},Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Status"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STOPPED ",Object(c.b)("em",{parentName:"td"},"(Gray dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All the application instances are stopped.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STARTING ",Object(c.b)("em",{parentName:"td"},"(Loading Icon)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 application instance is starting.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STOPPING ",Object(c.b)("em",{parentName:"td"},"(Loading Icon)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 application instance is stopping.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"RUNNING ",Object(c.b)("em",{parentName:"td"},"(Green dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All application instances are running correctly.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ERROR ",Object(c.b)("em",{parentName:"td"},"(Red dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All application instances are in error status.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"WARNING ",Object(c.b)("em",{parentName:"td"},"(Orange dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(c.b)("em",{parentName:"td"},"(Valid for multi-instance applications only)")," At least 1 application instance is in error status (but not all of them).")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Completed ",Object(c.b)("em",{parentName:"td"},"(Green dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(c.b)("em",{parentName:"td"},"(Valid for Lifecycle and Cronjob only)")," The job was correctly executed.")))),Object(c.b)("p",null,"The service status is computed based on the status of each ",Object(c.b)("inlineCode",{parentName:"p"},"Kubernetes pod")," deployed for this application."),Object(c.b)("h3",{id:"pod-status-application-instances"},"Pod status (Application instances)"),Object(c.b)("p",null,"You can check on the ",Object(c.b)("inlineCode",{parentName:"p"},"Service overview")," page the status of each pod running your application in Kubernetes. This page is accessible by clicking on one of the services of your environment."),Object(c.b)("p",null,"Within this page you will have a view of:"),Object(c.b)("ul",null,Object(c.b)("li",{parentName:"ul"},"the number of running instances of your application"),Object(c.b)("li",{parentName:"ul"},"the status of each instance"),Object(c.b)("li",{parentName:"ul"},"in case of an error, you will get the reason behind the issue by clicking on the Pod in error.")),Object(c.b)("h2",{id:"deployment-statuses"},"Deployment Statuses"),Object(c.b)("p",null,"When you access an environment on your ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),", you can check:"),Object(c.b)("ul",null,Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"the overall status of your deployments in that specific environment"),', thanks to the dot present within the "Deployment" tab. This corresponds to the overall deployment status of your environment.')),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"the deployment status of each service in that specific environment"),", thanks to the label displayed in the ",Object(c.b)("inlineCode",{parentName:"p"},"Service status")," column. This corresponds to the status of the last deployment performed on the service."),Object(c.b)("p",{parentName:"li"},"Here are all the possible deployment statuses for both environments and services:")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"QUEUED")," (temporary state).")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"BUILDING")," (temporary state).")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"BUILDING ERROR")," (final state).")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"DEPLOYING")," (temporary state).")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"DEPLOYMENT ERROR")," (final state).")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"CANCELLING BUILDING")," (temporary state).")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"CANCELLED")," (temporary state).")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"DEPLOYMENT OK")," (final state)."))),Object(c.b)(o.a,{type:"info",mdxType:"Alert"},Object(c.b)("p",null,"Just because an error arised during deployment does not mean your application is not running. Monitoring both your deployment and service statuses allows you to know exactly which applications are currently running on your platform.")))}p.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),b=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},p=function(e){var t=b(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,c=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=b(n),m=a,d=p["".concat(o,".").concat(m)]||p[m]||u[m]||c;return n?r.a.createElement(d,i({ref:t},s,{components:n})):r.a.createElement(d,i({ref:t},s))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var c=n.length,o=new Array(c);o[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:a,o[1]=i;for(var s=2;s1?arguments[1]:void 0,n),l=o>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>i;)t[i++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,c=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(c)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),c=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(c.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),c=n.n(r),o=n(39),i=n(430),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,p=Object(i.a)(b),u=Object(r.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&p&&window.docusaurus.prefetch(b),function(){m&&t&&t.disconnect()}}),[b,m,p]),b&&p?c.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){u.current||(window.docusaurus.preload(b),u.current=!0)},innerRef:function(e){var n,a;m&&e&&p&&(n=e,a=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:b})):c.a.createElement("a",Object(a.a)({},e,{href:b}))}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),c=n(427),o=n(420),i=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,o=e.leftIcon,l=e.rightIcon,s=e.size,b=e.target,p=e.to,u=i()("jump-to","jump-to--"+s,n),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},o&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+o})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return b?r.a.createElement("a",{href:p,target:b,className:u},m):r.a.createElement(c.a,{to:p,className:u},m)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see e3c664e0.c51149d9.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[242],{394:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),c=(n(0),n(425)),o=(n(431),n(424)),i=(n(429),{last_modified_on:"2023-12-11",title:"Running and Deployment Statuses",description:"Learn how to monitor your services"}),l={id:"using-qovery/deployment/running-and-deployment-statuses",title:"Running and Deployment Statuses",description:"Learn how to monitor your services",source:"@site/docs/using-qovery/deployment/running-and-deployment-statuses.md",permalink:"/docs/using-qovery/deployment/running-and-deployment-statuses",sidebar:"docs",previous:{title:"Deployment History",permalink:"/docs/using-qovery/deployment/deployment-history"},next:{title:"Logs",permalink:"/docs/using-qovery/deployment/logs"}},s=[{value:"Running Statuses",id:"running-statuses",children:[]},{value:"Environment Statuses",id:"environment-statuses",children:[]},{value:"Service Statuses",id:"service-statuses",children:[{value:"Pod status (Application instances)",id:"pod-status-application-instances",children:[]}]},{value:"Deployment Statuses",id:"deployment-statuses",children:[]}],b={rightToc:s};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(c.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(c.b)("p",null,"From any environment window on your ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),", you can monitor the running and deployment status of your environments and services."),Object(c.b)("p",{align:"center"},Object(c.b)("img",{src:"/img/deployment/run_deployment_statuses.png",alt:"Statuses"})),Object(c.b)("table",null,Object(c.b)("thead",{parentName:"table"},Object(c.b)("tr",{parentName:"thead"},Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Item"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"1"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"The dot in the service tab shows the environment running status. ",Object(c.b)("br",null)," For more information, see the Environment Statuses section below.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"2"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"The dot in the deployment tab shows the environment deployment status. ",Object(c.b)("br",null)," For more information, see the Deployment Statuses section below.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"3"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),'The label in the column "Service status" represents the running status of the service. ',Object(c.b)("br",null)," For more information, see Service Statuses section below.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"4"),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),'The label in the column "Last deployment" represents the status of the latest deployment of the service. ',Object(c.b)("br",null)," For more information, see Deployment Statuses section below.")))),Object(c.b)("h2",{id:"running-statuses"},"Running Statuses"),Object(c.b)("p",null,"Thanks to Running statuses, you can find out which services are currently running on your platform, and which are interrupted. There are two types of run services available currently: environment statuses and service statuses."),Object(c.b)("h2",{id:"environment-statuses"},"Environment Statuses"),Object(c.b)("p",null,"When you access an environment on your ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),", you can check its status in real-time."),Object(c.b)("p",null,"The environment status is computed based on the statuses of all the services in that specific environment. Here are all the possible environment statuses:"),Object(c.b)("table",null,Object(c.b)("thead",{parentName:"table"},Object(c.b)("tr",{parentName:"thead"},Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Status"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STOPPED ",Object(c.b)("em",{parentName:"td"},"(Gray dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All the services are stopped.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STARTING ",Object(c.b)("em",{parentName:"td"},"(Loading Icon)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 service is starting.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STOPPING ",Object(c.b)("em",{parentName:"td"},"(Loading Icon)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 service is stopping.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"RUNNING ",Object(c.b)("em",{parentName:"td"},"(Green dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All services are running correctly.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ERROR ",Object(c.b)("em",{parentName:"td"},"(Red dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All services are in error status.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"WARNING ",Object(c.b)("em",{parentName:"td"},"(Orange dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 service is in error status (but not all of them).")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"COMPLETED ",Object(c.b)("em",{parentName:"td"},"(Green dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"The job execution has completed (only for cronjob and lifecycle jobs).")))),Object(c.b)("h2",{id:"service-statuses"},"Service Statuses"),Object(c.b)("p",null,"When you access an environment on your ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),', you can check the status of each service in that environment in real-time within the column "Service status".'),Object(c.b)("p",null,"Here are all the possible service statuses:"),Object(c.b)("table",null,Object(c.b)("thead",{parentName:"table"},Object(c.b)("tr",{parentName:"thead"},Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Status"),Object(c.b)("th",Object(a.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STOPPED ",Object(c.b)("em",{parentName:"td"},"(Gray dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All the application instances are stopped.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STARTING ",Object(c.b)("em",{parentName:"td"},"(Loading Icon)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 application instance is starting.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STOPPING ",Object(c.b)("em",{parentName:"td"},"(Loading Icon)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 application instance is stopping.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"RUNNING ",Object(c.b)("em",{parentName:"td"},"(Green dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All application instances are running correctly.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ERROR ",Object(c.b)("em",{parentName:"td"},"(Red dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All application instances are in error status.")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"WARNING ",Object(c.b)("em",{parentName:"td"},"(Orange dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(c.b)("em",{parentName:"td"},"(Valid for multi-instance applications only)")," At least 1 application instance is in error status (but not all of them).")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Completed ",Object(c.b)("em",{parentName:"td"},"(Green dot)")),Object(c.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(c.b)("em",{parentName:"td"},"(Valid for Lifecycle and Cronjob only)")," The job was correctly executed.")))),Object(c.b)("p",null,"The service status is computed based on the status of each ",Object(c.b)("inlineCode",{parentName:"p"},"Kubernetes pod")," deployed for this application."),Object(c.b)("h3",{id:"pod-status-application-instances"},"Pod status (Application instances)"),Object(c.b)("p",null,"You can check on the ",Object(c.b)("inlineCode",{parentName:"p"},"Service overview")," page the status of each pod running your application in Kubernetes. This page is accessible by clicking on one of the services of your environment."),Object(c.b)("p",null,"Within this page you will have a view of:"),Object(c.b)("ul",null,Object(c.b)("li",{parentName:"ul"},"the number of running instances of your application"),Object(c.b)("li",{parentName:"ul"},"the status of each instance"),Object(c.b)("li",{parentName:"ul"},"in case of an error, you will get the reason behind the issue by clicking on the Pod in error.")),Object(c.b)("h2",{id:"deployment-statuses"},"Deployment Statuses"),Object(c.b)("p",null,"When you access an environment on your ",Object(c.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),", you can check:"),Object(c.b)("ul",null,Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"the overall status of your deployments in that specific environment"),', thanks to the dot present within the "Deployment" tab. This corresponds to the overall deployment status of your environment.')),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"the deployment status of each service in that specific environment"),", thanks to the label displayed in the ",Object(c.b)("inlineCode",{parentName:"p"},"Service status")," column. This corresponds to the status of the last deployment performed on the service."),Object(c.b)("p",{parentName:"li"},"Here are all the possible deployment statuses for both environments and services:")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"QUEUED")," (temporary state).")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"BUILDING")," (temporary state).")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"BUILDING ERROR")," (final state).")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"DEPLOYING")," (temporary state).")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"DEPLOYMENT ERROR")," (final state).")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"CANCELLING BUILDING")," (temporary state).")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"CANCELLED")," (temporary state).")),Object(c.b)("li",{parentName:"ul"},Object(c.b)("p",{parentName:"li"},Object(c.b)("strong",{parentName:"p"},"DEPLOYMENT OK")," (final state)."))),Object(c.b)(o.a,{type:"info",mdxType:"Alert"},Object(c.b)("p",null,"Just because an error arised during deployment does not mean your application is not running. Monitoring both your deployment and service statuses allows you to know exactly which applications are currently running on your platform.")))}p.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),b=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},p=function(e){var t=b(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,c=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=b(n),m=a,d=p["".concat(o,".").concat(m)]||p[m]||u[m]||c;return n?r.a.createElement(d,i({ref:t},s,{components:n})):r.a.createElement(d,i({ref:t},s))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var c=n.length,o=new Array(c);o[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:a,o[1]=i;for(var s=2;s1?arguments[1]:void 0,n),l=o>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>i;)t[i++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,c=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(c)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),c=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(c.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),c=n.n(r),o=n(39),i=n(432),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,p=Object(i.a)(b),u=Object(r.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!m&&p&&window.docusaurus.prefetch(b),function(){m&&t&&t.disconnect()}}),[b,m,p]),b&&p?c.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){u.current||(window.docusaurus.preload(b),u.current=!0)},innerRef:function(e){var n,a;m&&e&&p&&(n=e,a=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:b})):c.a.createElement("a",Object(a.a)({},e,{href:b}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),c=n(430),o=n(423),i=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,o=e.leftIcon,l=e.rightIcon,s=e.size,b=e.target,p=e.to,u=i()("jump-to","jump-to--"+s,n),m=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},o&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+o})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return b?r.a.createElement("a",{href:p,target:b,className:u},m):r.a.createElement(c.a,{to:p,className:u},m)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/e4768112.e546d594.js.LICENSE.txt b/e3c664e0.c51149d9.js.LICENSE.txt similarity index 100% rename from e4768112.e546d594.js.LICENSE.txt rename to e3c664e0.c51149d9.js.LICENSE.txt diff --git a/c0594016.772afbdc.js b/e4310ee0.abc843fc.js similarity index 90% rename from c0594016.772afbdc.js rename to e4310ee0.abc843fc.js index 41f92c4d77..ba51337cf9 100644 --- a/c0594016.772afbdc.js +++ b/e4310ee0.abc843fc.js @@ -1,2 +1,2 @@ -/*! For license information please see c0594016.772afbdc.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[197],{348:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),a=(n(0),n(422)),i=n(431),c=n(426),u=(n(421),{last_modified_on:"2023-07-07",$schema:"/.meta/.schemas/guides.json",title:"Custom domain",description:"How to set and use your own domain",series_position:3,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),l={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Custom domain",description:"How to set and use your own domain",permalink:"/guides/getting-started/setting-custom-domain",readingTime:"2 min read",seriesPosition:3,source:"@site/guides/getting-started/setting-custom-domain.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Custom domain",truncated:!1,prevItem:{title:"Create a database",permalink:"/guides/getting-started/create-a-database"},nextItem:{title:"Environment variables",permalink:"/guides/getting-started/managing-environment-variables"}},s=[{value:"Tutorial",id:"tutorial",children:[{value:"Add the domain to your app",id:"add-the-domain-to-your-app",children:[]},{value:"Configure your DNS",id:"configure-your-dns",children:[]},{value:"Your domain is ready",id:"your-domain-is-ready",children:[]}]}],d={rightToc:s};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"On Qovery, every application exposed publicly automatically gets a temporary ",Object(a.b)("inlineCode",{parentName:"p"},"qovery.io")," domain. You can also bring your domains to Qovery\nquickly. We handle TLS/SSL certificate creation and renewal, as well as automatic HTTP to HTTPS redirects for all your custom domains. Let\u2019s\nlearn how to set up your domains on Qovery!"),Object(a.b)(c.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have a domain"),Object(a.b)("li",{parentName:"ul"},"You have the permission to add a ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://en.wikipedia.org/wiki/CNAME_record"}),"CNAME")," record to your domain"))),Object(a.b)("h2",{id:"tutorial"},"Tutorial"),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h3",{id:"add-the-domain-to-your-app"},"Add the domain to your app"),Object(a.b)("div",{class:"video-container"},Object(a.b)("p",{align:"center"},Object(a.b)("iframe",{src:"https://www.loom.com/embed/cd9c56a133164005bfeb7db23d2b6ed1",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0})))),Object(a.b)("li",null,Object(a.b)("h3",{id:"configure-your-dns"},"Configure your DNS"),Object(a.b)("p",null,"Configure your DNS by adding a CNAME record pointing to the domain provided by Qovery in the previous step"),Object(a.b)("p",null,"If you have multiple public ports (or you want to have them in the future), make sure you add a CNAME for both yourdomain.com and *.yourdomain.com. "),Object(a.b)("p",null,"In this way:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"your application default port will be accessible via the domain ",Object(a.b)("inlineCode",{parentName:"li"},"yourdomain.com")," or by a subdomain equal to the port name (portNameA.yourdomain.com). "),Object(a.b)("li",{parentName:"ul"},"the other application public port will be accessible via a subdomain equal to the portName (portNameB.yourdomain.com). ")),Object(a.b)("p",null,"See the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#ports"}),"port setup of your application")," for more information on the port name setup.")),Object(a.b)("li",null,Object(a.b)("h3",{id:"your-domain-is-ready"},"Your domain is ready"),Object(a.b)("p",null,"You need to ",Object(a.b)("strong",{parentName:"p"},"restart")," your app to use your custom domain on your application.")))),Object(a.b)("p",null,"If you run into any trouble, ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discord.qovery.com"}),"find us on Discord"),". Our team and the community will be glad to help out."))}p.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=o.a.createContext({}),s=function(e){var t=o.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},d=function(e){var t=s(e.components);return o.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),d=s(n),m=r,b=d["".concat(i,".").concat(m)]||d[m]||p[m]||a;return n?o.a.createElement(b,c({ref:t},l,{components:n})):o.a.createElement(b,c({ref:t},l))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,l=void 0===u?n:o(u,n);l>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),s=Object(r.useState)(null),d=s[0],p=s[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!d&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==d&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see e4310ee0.abc843fc.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[243],{395:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),a=(n(0),n(425)),i=n(434),c=n(429),u=(n(424),{last_modified_on:"2023-07-07",$schema:"/.meta/.schemas/guides.json",title:"Custom domain",description:"How to set and use your own domain",series_position:3,author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),l={categories:[{name:"getting-started",title:"Getting Started",description:"Take Qovery from zero to production in under 10 minutes.",permalink:"/guides/getting-started"}],coverLabel:"Custom domain",description:"How to set and use your own domain",permalink:"/guides/getting-started/setting-custom-domain",readingTime:"2 min read",seriesPosition:3,source:"@site/guides/getting-started/setting-custom-domain.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Custom domain",truncated:!1,prevItem:{title:"Create a database",permalink:"/guides/getting-started/create-a-database"},nextItem:{title:"Environment variables",permalink:"/guides/getting-started/managing-environment-variables"}},s=[{value:"Tutorial",id:"tutorial",children:[{value:"Add the domain to your app",id:"add-the-domain-to-your-app",children:[]},{value:"Configure your DNS",id:"configure-your-dns",children:[]},{value:"Your domain is ready",id:"your-domain-is-ready",children:[]}]}],d={rightToc:s};function p(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"On Qovery, every application exposed publicly automatically gets a temporary ",Object(a.b)("inlineCode",{parentName:"p"},"qovery.io")," domain. You can also bring your domains to Qovery\nquickly. We handle TLS/SSL certificate creation and renewal, as well as automatic HTTP to HTTPS redirects for all your custom domains. Let\u2019s\nlearn how to set up your domains on Qovery!"),Object(a.b)(c.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have a domain"),Object(a.b)("li",{parentName:"ul"},"You have the permission to add a ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://en.wikipedia.org/wiki/CNAME_record"}),"CNAME")," record to your domain"))),Object(a.b)("h2",{id:"tutorial"},"Tutorial"),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h3",{id:"add-the-domain-to-your-app"},"Add the domain to your app"),Object(a.b)("div",{class:"video-container"},Object(a.b)("p",{align:"center"},Object(a.b)("iframe",{src:"https://www.loom.com/embed/cd9c56a133164005bfeb7db23d2b6ed1",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0})))),Object(a.b)("li",null,Object(a.b)("h3",{id:"configure-your-dns"},"Configure your DNS"),Object(a.b)("p",null,"Configure your DNS by adding a CNAME record pointing to the domain provided by Qovery in the previous step"),Object(a.b)("p",null,"If you have multiple public ports (or you want to have them in the future), make sure you add a CNAME for both yourdomain.com and *.yourdomain.com. "),Object(a.b)("p",null,"In this way:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"your application default port will be accessible via the domain ",Object(a.b)("inlineCode",{parentName:"li"},"yourdomain.com")," or by a subdomain equal to the port name (portNameA.yourdomain.com). "),Object(a.b)("li",{parentName:"ul"},"the other application public port will be accessible via a subdomain equal to the portName (portNameB.yourdomain.com). ")),Object(a.b)("p",null,"See the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#ports"}),"port setup of your application")," for more information on the port name setup.")),Object(a.b)("li",null,Object(a.b)("h3",{id:"your-domain-is-ready"},"Your domain is ready"),Object(a.b)("p",null,"You need to ",Object(a.b)("strong",{parentName:"p"},"restart")," your app to use your custom domain on your application.")))),Object(a.b)("p",null,"If you run into any trouble, ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discord.qovery.com"}),"find us on Discord"),". Our team and the community will be glad to help out."))}p.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=o.a.createContext({}),s=function(e){var t=o.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},d=function(e){var t=s(e.components);return o.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),d=s(n),m=r,b=d["".concat(i,".").concat(m)]||d[m]||p[m]||a;return n?o.a.createElement(b,c({ref:t},l,{components:n})):o.a.createElement(b,c({ref:t},l))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var l=2;l1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,l=void 0===u?n:o(u,n);l>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),s=Object(r.useState)(null),d=s[0],p=s[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!d&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==d&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/e5653b8d.e8572ecf.js.LICENSE.txt b/e4310ee0.abc843fc.js.LICENSE.txt similarity index 100% rename from e5653b8d.e8572ecf.js.LICENSE.txt rename to e4310ee0.abc843fc.js.LICENSE.txt diff --git a/bdd6d8c6.bce2bc95.js b/e4768112.08a4bc30.js similarity index 77% rename from bdd6d8c6.bce2bc95.js rename to e4768112.08a4bc30.js index dad350fa10..54fce501ef 100644 --- a/bdd6d8c6.bce2bc95.js +++ b/e4768112.08a4bc30.js @@ -1,2 +1,2 @@ -/*! For license information please see bdd6d8c6.bce2bc95.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[195],{346:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),o=(n(0),n(422)),c=n(431),i=(n(421),n(426)),s=(n(429),{last_modified_on:"2022-01-27",$schema:"/.meta/.schemas/guides.json",title:"How to create an RDS instance through the AWS console",description:"How to create an RDS instance through the AWS console.",author_github:"https://github.com/l0ck3",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to create an RDS instance through the AWS console",description:"How to create an RDS instance through the AWS console.",permalink:"/guides/tutorial/how-to-create-an-rds-instance-through-aws-console",readingTime:"4 min read",source:"@site/guides/tutorial/how-to-create-an-rds-instance-through-aws-console.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to create an RDS instance through the AWS console",truncated:!1,prevItem:{title:"How to connect to your EKS cluster with kubectl",permalink:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl"},nextItem:{title:"How to deploy a Rust REST API application on AWS with ease",permalink:"/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease"}},u=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],b={rightToc:u};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery make it easy to create an RDS database on AWS with a few clicks. You might however want to create your own RDS instance in a separate VPC. For example in case you want to use the same instance with several Qovery clusters."),Object(o.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have an AWS account."))),Object(o.b)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"This tutorial will show you how to create an production-ready RDS PostgreSQL instance on AWS. "),Object(o.b)("p",null,"To connect your Qovery cluster(s) to the created RDS database, refer to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"this tutorial")),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"create-rds-database"},"Create RDS database"),Object(o.b)("p",null,"Go to the AWS RDS console and click ",Object(o.b)("inlineCode",{parentName:"p"},"Create database")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/1.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"select-your-database-type"},"Select your database type"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"We will need to create a dedicated VPC, so select ",Object(o.b)("inlineCode",{parentName:"li"},"Standard create"),"."),Object(o.b)("li",{parentName:"ul"},"Then chose your database type (we'll use PostgreSQL for our example) and the version."),Object(o.b)("li",{parentName:"ul"},"Since we're creating a production database, we'll select the ",Object(o.b)("inlineCode",{parentName:"li"},"Production")," template. You can pick ",Object(o.b)("inlineCode",{parentName:"li"},"Dev/Test")," template for non-production environments.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/2.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"settings"},"Settings"),Object(o.b)("p",null,"Select a name for your RDS instance, here ",Object(o.b)("inlineCode",{parentName:"p"},"my-production-database"),", master username and password."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/3.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"instance-class"},"Instance class"),Object(o.b)("p",null,"Pick an instance class that works for your needs.\nYou can refer to this document for more information about the different options: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html"}),"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/4.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"storage"},"Storage"),Object(o.b)("p",null,Object(o.b)("inlineCode",{parentName:"p"},"General Purpose SSD")," should be the right option for most cases.\nChose the allocated storage that fits the needs of your application. We also advise you to ",Object(o.b)("inlineCode",{parentName:"p"},"Enable storage autoscaling")," in case you need more storage over time. "),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/5.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"availability--durability"},"Availability & durability"),Object(o.b)("p",null,"For a production setup you should ",Object(o.b)("inlineCode",{parentName:"p"},"Create a standby instance"),". For non-production usecase you can avoid it to reduce costs."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/6.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"connectivity"},"Connectivity"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Since we want the database to live in it's own VPC, make sure to select the ",Object(o.b)("inlineCode",{parentName:"li"},"Create new VPC")," option."),Object(o.b)("li",{parentName:"ul"},"Also select ",Object(o.b)("inlineCode",{parentName:"li"},"Create new DB Subnet Group"),"."),Object(o.b)("li",{parentName:"ul"},"We advise you to disable ",Object(o.b)("inlineCode",{parentName:"li"},"Public access")," for security reason. We'll setup VPC peering in the next guide to allow access from your Qovery clusters through private networking."),Object(o.b)("li",{parentName:"ul"},"Finally chose ",Object(o.b)("inlineCode",{parentName:"li"},"Create new")," security group and give it a name.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/7.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"database-authentication-and-estimated-costs"},"Database authentication and estimated costs"),Object(o.b)("p",null,"Chose ",Object(o.b)("inlineCode",{parentName:"p"},"Password authentication"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/8.png",alt:"AWS RDS console"})),Object(o.b)("p",null,"You can then click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create database"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"database-creation"},"Database creation"),Object(o.b)("p",null,"You should see your new RDS instance in the list of databases, with the ",Object(o.b)("inlineCode",{parentName:"p"},"Creating")," status."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/9.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"name-your-rds-vpc"},"Name your RDS VPC"),Object(o.b)("p",null,"The VPC created for the new RDS database will be named ",Object(o.b)("inlineCode",{parentName:"p"},"-"),". For convenience you should rename it."),Object(o.b)("p",null,"Click on your database in the list, then on the VPC id. "),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/10.png",alt:"AWS RDS console"})),Object(o.b)("p",null,"You will be redirected to the VPCs list, filtered on the VPC id. Click on the edit icon in the ",Object(o.b)("inlineCode",{parentName:"p"},"Name")," column, and give it a meaningful name."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/11.png",alt:"AWS RDS console"})),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/12.png",alt:"AWS RDS console"}))))),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"Your RDS database is ready. Now in order to access it from your Qovery cluster, we will need to setup VPC peering. You can find the procedure in ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"this tutorial")))}p.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),u=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=u(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),b=u(n),d=a,m=b["".concat(c,".").concat(d)]||b[d]||p[d]||o;return n?r.a.createElement(m,i({ref:t},l,{components:n})):r.a.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,c=new Array(o);c[0]=d;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:a,c[1]=i;for(var l=2;l1?arguments[1]:void 0,n),s=c>2?arguments[2]:void 0,l=void 0===s?n:r(s,n);l>i;)t[i++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),c=n(39),i=n(430),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,b=Object(i.a)(u),p=Object(r.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,b]),u&&b?o.a.createElement(c.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,a;d&&e&&b&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},428:function(e,t,n){"use strict";var a=n(432),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var c=[];return r.slice().forEach((function(e){void 0!==e&&c.push(n(a,e,c.length))})),c.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),c=n(420),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,c=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,b=e.to,p=i()("jump-to","jump-to--"+l,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:b,target:u,className:p},d):r.a.createElement(o.a,{to:b,className:p},d)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(420),n(428)),c=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(s),u=Object(a.useState)(null),b=u[0],p=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see e4768112.08a4bc30.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[244],{396:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return s})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var a=n(1),r=n(9),o=(n(0),n(425)),c=n(434),i=(n(424),n(429)),s=(n(431),{last_modified_on:"2022-01-27",$schema:"/.meta/.schemas/guides.json",title:"How to create an RDS instance through the AWS console",description:"How to create an RDS instance through the AWS console.",author_github:"https://github.com/l0ck3",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to create an RDS instance through the AWS console",description:"How to create an RDS instance through the AWS console.",permalink:"/guides/tutorial/how-to-create-an-rds-instance-through-aws-console",readingTime:"4 min read",source:"@site/guides/tutorial/how-to-create-an-rds-instance-through-aws-console.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to create an RDS instance through the AWS console",truncated:!1,prevItem:{title:"How to connect to your EKS cluster with kubectl",permalink:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl"},nextItem:{title:"How to deploy a Rust REST API application on AWS with ease",permalink:"/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease"}},u=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],b={rightToc:u};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Qovery make it easy to create an RDS database on AWS with a few clicks. You might however want to create your own RDS instance in a separate VPC. For example in case you want to use the same instance with several Qovery clusters."),Object(o.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have an AWS account."))),Object(o.b)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"This tutorial will show you how to create an production-ready RDS PostgreSQL instance on AWS. "),Object(o.b)("p",null,"To connect your Qovery cluster(s) to the created RDS database, refer to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"this tutorial")),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"create-rds-database"},"Create RDS database"),Object(o.b)("p",null,"Go to the AWS RDS console and click ",Object(o.b)("inlineCode",{parentName:"p"},"Create database")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/1.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"select-your-database-type"},"Select your database type"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"We will need to create a dedicated VPC, so select ",Object(o.b)("inlineCode",{parentName:"li"},"Standard create"),"."),Object(o.b)("li",{parentName:"ul"},"Then chose your database type (we'll use PostgreSQL for our example) and the version."),Object(o.b)("li",{parentName:"ul"},"Since we're creating a production database, we'll select the ",Object(o.b)("inlineCode",{parentName:"li"},"Production")," template. You can pick ",Object(o.b)("inlineCode",{parentName:"li"},"Dev/Test")," template for non-production environments.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/2.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"settings"},"Settings"),Object(o.b)("p",null,"Select a name for your RDS instance, here ",Object(o.b)("inlineCode",{parentName:"p"},"my-production-database"),", master username and password."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/3.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"instance-class"},"Instance class"),Object(o.b)("p",null,"Pick an instance class that works for your needs.\nYou can refer to this document for more information about the different options: ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html"}),"https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/4.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"storage"},"Storage"),Object(o.b)("p",null,Object(o.b)("inlineCode",{parentName:"p"},"General Purpose SSD")," should be the right option for most cases.\nChose the allocated storage that fits the needs of your application. We also advise you to ",Object(o.b)("inlineCode",{parentName:"p"},"Enable storage autoscaling")," in case you need more storage over time. "),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/5.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"availability--durability"},"Availability & durability"),Object(o.b)("p",null,"For a production setup you should ",Object(o.b)("inlineCode",{parentName:"p"},"Create a standby instance"),". For non-production usecase you can avoid it to reduce costs."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/6.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"connectivity"},"Connectivity"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Since we want the database to live in it's own VPC, make sure to select the ",Object(o.b)("inlineCode",{parentName:"li"},"Create new VPC")," option."),Object(o.b)("li",{parentName:"ul"},"Also select ",Object(o.b)("inlineCode",{parentName:"li"},"Create new DB Subnet Group"),"."),Object(o.b)("li",{parentName:"ul"},"We advise you to disable ",Object(o.b)("inlineCode",{parentName:"li"},"Public access")," for security reason. We'll setup VPC peering in the next guide to allow access from your Qovery clusters through private networking."),Object(o.b)("li",{parentName:"ul"},"Finally chose ",Object(o.b)("inlineCode",{parentName:"li"},"Create new")," security group and give it a name.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/7.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"database-authentication-and-estimated-costs"},"Database authentication and estimated costs"),Object(o.b)("p",null,"Chose ",Object(o.b)("inlineCode",{parentName:"p"},"Password authentication"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/8.png",alt:"AWS RDS console"})),Object(o.b)("p",null,"You can then click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create database"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"database-creation"},"Database creation"),Object(o.b)("p",null,"You should see your new RDS instance in the list of databases, with the ",Object(o.b)("inlineCode",{parentName:"p"},"Creating")," status."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/9.png",alt:"AWS RDS console"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"name-your-rds-vpc"},"Name your RDS VPC"),Object(o.b)("p",null,"The VPC created for the new RDS database will be named ",Object(o.b)("inlineCode",{parentName:"p"},"-"),". For convenience you should rename it."),Object(o.b)("p",null,"Click on your database in the list, then on the VPC id. "),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/10.png",alt:"AWS RDS console"})),Object(o.b)("p",null,"You will be redirected to the VPCs list, filtered on the VPC id. Click on the edit icon in the ",Object(o.b)("inlineCode",{parentName:"p"},"Name")," column, and give it a meaningful name."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/11.png",alt:"AWS RDS console"})),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/how-to-create-an-rds-instance-through-aws-console/12.png",alt:"AWS RDS console"}))))),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"Your RDS database is ready. Now in order to access it from your Qovery cluster, we will need to setup VPC peering. You can find the procedure in ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/aws-vpc-peering-with-qovery/"}),"this tutorial")))}p.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),u=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},b=function(e){var t=u(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),b=u(n),d=a,m=b["".concat(c,".").concat(d)]||b[d]||p[d]||o;return n?r.a.createElement(m,i({ref:t},l,{components:n})):r.a.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,c=new Array(o);c[0]=d;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:a,c[1]=i;for(var l=2;l1?arguments[1]:void 0,n),s=c>2?arguments[2]:void 0,l=void 0===s?n:r(s,n);l>i;)t[i++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),c=n(39),i=n(432),s=n(20),l=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,u=n||s,b=Object(i.a)(u),p=Object(r.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,b]),u&&b?o.a.createElement(c.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(u),p.current=!0)},innerRef:function(e){var n,a;d&&e&&b&&(n=e,a=function(){window.docusaurus.prefetch(u)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:u})):o.a.createElement("a",Object(a.a)({},e,{href:u}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),c=n(423),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,c=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,b=e.to,p=i()("jump-to","jump-to--"+l,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:b,target:u,className:p},d):r.a.createElement(o.a,{to:b,className:p},d)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},433:function(e,t,n){"use strict";var a=n(435),r=n(51);function o(e,t){return t.encode?t.strict?a(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,a){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===a[e]&&(a[e]={}),a[e][t[1]]=n):a[e]=n};case"bracket":return function(e,n,a){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==a[e]?a[e]=[].concat(a[e],n):a[e]=[n]:a[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),a=Object.create(null);return"string"!=typeof e?a:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(r),o,a)})),Object.keys(a).sort().reduce((function(e,t){var n=a[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):a},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,a){return null===n?[o(t,e),"[",a,"]"].join(""):[o(t,e),"[",o(a,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var r=e[a];if(void 0===r)return"";if(null===r)return o(a,t);if(Array.isArray(r)){var c=[];return r.slice().forEach((function(e){void 0!==e&&c.push(n(a,e,c.length))})),c.join("&")}return o(a,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(423),n(433)),c=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},l="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(s),u=Object(a.useState)(null),b=u[0],p=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!b&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:l,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/e5b9b0aa.95998124.js.LICENSE.txt b/e4768112.08a4bc30.js.LICENSE.txt similarity index 100% rename from e5b9b0aa.95998124.js.LICENSE.txt rename to e4768112.08a4bc30.js.LICENSE.txt diff --git a/e5653b8d.e8572ecf.js b/e5653b8d.ca58aa43.js similarity index 91% rename from e5653b8d.e8572ecf.js rename to e5653b8d.ca58aa43.js index 0749cbccfe..314bdbe787 100644 --- a/e5653b8d.e8572ecf.js +++ b/e5653b8d.ca58aa43.js @@ -1,2 +1,2 @@ -/*! For license information please see e5653b8d.e8572ecf.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[242],{394:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var a=n(1),r=n(9),o=(n(0),n(422)),i=n(421),l=(n(426),n(429),{last_modified_on:"2023-12-12",$schema:"/.meta/.schemas/guides.json",title:"Setting up Cloudflare and Custom Domain on Qovery",description:"Using Cloudflare for applications deployed on Qovery",author_github:"https://github.com/jul-dan",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Setting up Cloudflare and Custom Domain on Qovery",description:"Using Cloudflare for applications deployed on Qovery",permalink:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery",readingTime:"4 min read",source:"@site/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Setting up Cloudflare and Custom Domain on Qovery",truncated:!1,prevItem:{title:"Seed Database",permalink:"/guides/advanced/seed-database"},nextItem:{title:"Setup VPC peering on AWS with Qovery",permalink:"/guides/tutorial/aws-vpc-peering-with-qovery"}},u=[{value:"Adding a Custom Domain",id:"adding-a-custom-domain",children:[]},{value:"Cloudflare Configuration",id:"cloudflare-configuration",children:[{value:"CNAME",id:"cname",children:[]},{value:"SSL/TLS",id:"ssltls",children:[]},{value:"Restrict application access",id:"restrict-application-access",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],s={rightToc:u};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"The guide assumes that you have an application up and running on Qovery. We'll go through the process of adding a new Custom Domain to the application and use Cloudflare as the domain provider. We also assume that you own a custom domain on Cloudflare (or any other domain registrar):"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/1.png",alt:"Cloudflare"})),Object(o.b)("h2",{id:"adding-a-custom-domain"},"Adding a Custom Domain"),Object(o.b)("p",null,"First, let's open application settings:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/2.png",alt:"Cloudflare"})),Object(o.b)("p",null,"Add your Cloudflare managed domain in ",Object(o.b)("inlineCode",{parentName:"p"},"Domain")," section:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/3.png",alt:"Cloudflare"})),Object(o.b)("h2",{id:"cloudflare-configuration"},"Cloudflare Configuration"),Object(o.b)("h3",{id:"cname"},"CNAME"),Object(o.b)("p",null,"To finish the configuration on Cloudfalre, open the DNS Settings:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/4.png",alt:"Cloudflare"})),Object(o.b)("p",null,"And add a CNAME entry with the value taken from the Qovery Console just like this:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/5.png",alt:"Cloudflare"})),Object(o.b)("p",null,"You can safely use the ",Object(o.b)("inlineCode",{parentName:"p"},"Proxy")," mode."),Object(o.b)("h3",{id:"ssltls"},"SSL/TLS"),Object(o.b)("p",null,"The last step to configure the domain Cloudflare side properly, is to use the ",Object(o.b)("inlineCode",{parentName:"p"},"Full")," TLS encryption:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/6.png",alt:"Cloudflare"})),Object(o.b)("p",null,"This is the requirement to make Custom Domain work properly using Cloudflare as the domain provider on Qovery."),Object(o.b)("h3",{id:"restrict-application-access"},"Restrict application access"),Object(o.b)("p",null,"If you want to limit the application access via Cloudflare only, you have two ways to perform it:"),Object(o.b)("h4",{id:"ip-whitelisting"},"IP whitelisting"),Object(o.b)("p",null,"In Qovery it is possible to whitelist a range of IPs that can reach your application:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"In the advanced settings section of your application:",Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/8.png",alt:"Cloudflare"}))),Object(o.b)("li",{parentName:"ul"},"Get the ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.cloudflare.com/ips-v4/"}),"Cloudflare ips")),Object(o.b)("li",{parentName:"ul"},"Edit the ",Object(o.b)("inlineCode",{parentName:"li"},"network.ingress.whitelist_source_range")," setting and add the Cloudflare IPs separated with a comma:",Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/9.png",alt:"Cloudflare"}))),Object(o.b)("li",{parentName:"ul"},"Save and redeploy your application")),Object(o.b)("h4",{id:"cloudflared"},"Cloudflared"),Object(o.b)("p",null,"Cloudflared establishes outbound connections (tunnels) between your resources and Cloudflare\u2019s global network."),Object(o.b)("p",null,"You have different ways to install Cloudflared on your cluster, you can find the installation instructions within this ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel/"}),"documentation"),"\nSince Cloudflared establishes a tunnel for you and the domain and TLS management is done by Cloudflare, you don't need to expose publicly the application during the setup (See ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#ports"}),"port setup")),Object(o.b)("p",null,"You can decide to install Cloudflared by yourself or via Qovery. Within the section below, you will find documentation on how to install Cloudflared as a container in one of the Qovery environments.\nBy creating and deploying the following service, using the Cloudflared image:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/10.png",alt:"Cloudflare"})),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Create a ",Object(o.b)("inlineCode",{parentName:"p"},"TUNNEL_TOKEN")," secret environment variable (Scope: Environment) to pass the Cloudflare token."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/13.png",alt:"Cloudflare"}))),Object(o.b)("p",null,"Once your tunnel is created and connected, you have to set the public hostname and the related service settings."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/11.png",alt:"Cloudflare"})),Object(o.b)("p",null,"To get the service name of your application deployed by Qovery, you can get it in your application variables:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/12.png",alt:"Cloudflare"})),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This setup works for static environments but not for dynamic ones since the service name is dynamic. We should probably suggest to use the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/cloudflare/helm-charts"}),"cloudflared helm chart")," once we release helm deployment")),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"After following the steps from above, our application should be accessible using the custom domain we selected:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/7.png",alt:"Cloudflare"})),Object(o.b)("p",null,"In the guide we went through all the necessary steps to configure Cloudflare and Qovery to make use of your custom domain."))}d.isMDXComponent=!0},420:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var u=r.a.createContext({}),s=function(e){var t=r.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},d=function(e){var t=s(e.components);return r.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},b=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),d=s(n),b=a,f=d["".concat(i,".").concat(b)]||d[b]||p[b]||o;return n?r.a.createElement(f,l({ref:t},u,{components:n})):r.a.createElement(f,l({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=b;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,i[1]=l;for(var u=2;u1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,u=void 0===c?n:r(c,n);u>l;)t[l++]=e;return t}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(430),c=n(20),u=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,s=n||c,d=Object(l.a)(s),p=Object(r.useRef)(!1),b=u.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!b&&d&&window.docusaurus.prefetch(s),function(){b&&t&&t.disconnect()}}),[s,b,d]),s&&d?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,a;b&&e&&d&&(n=e,a=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:s})):o.a.createElement("a",Object(a.a)({},e,{href:s}))}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),i=n(420),l=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,u=e.size,s=e.target,d=e.to,p=l()("jump-to","jump-to--"+u,n),b=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return s?r.a.createElement("a",{href:d,target:s,className:p},b):r.a.createElement(o.a,{to:d,className:p},b)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see e5653b8d.ca58aa43.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[245],{397:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var a=n(1),r=n(9),o=(n(0),n(425)),i=n(424),l=(n(429),n(431),{last_modified_on:"2023-12-12",$schema:"/.meta/.schemas/guides.json",title:"Setting up Cloudflare and Custom Domain on Qovery",description:"Using Cloudflare for applications deployed on Qovery",author_github:"https://github.com/jul-dan",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Setting up Cloudflare and Custom Domain on Qovery",description:"Using Cloudflare for applications deployed on Qovery",permalink:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery",readingTime:"4 min read",source:"@site/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Setting up Cloudflare and Custom Domain on Qovery",truncated:!1,prevItem:{title:"Seed Database",permalink:"/guides/advanced/seed-database"},nextItem:{title:"Setup VPC peering on AWS with Qovery",permalink:"/guides/tutorial/aws-vpc-peering-with-qovery"}},u=[{value:"Adding a Custom Domain",id:"adding-a-custom-domain",children:[]},{value:"Cloudflare Configuration",id:"cloudflare-configuration",children:[{value:"CNAME",id:"cname",children:[]},{value:"SSL/TLS",id:"ssltls",children:[]},{value:"Restrict application access",id:"restrict-application-access",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],s={rightToc:u};function d(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"The guide assumes that you have an application up and running on Qovery. We'll go through the process of adding a new Custom Domain to the application and use Cloudflare as the domain provider. We also assume that you own a custom domain on Cloudflare (or any other domain registrar):"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/1.png",alt:"Cloudflare"})),Object(o.b)("h2",{id:"adding-a-custom-domain"},"Adding a Custom Domain"),Object(o.b)("p",null,"First, let's open application settings:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/2.png",alt:"Cloudflare"})),Object(o.b)("p",null,"Add your Cloudflare managed domain in ",Object(o.b)("inlineCode",{parentName:"p"},"Domain")," section:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/3.png",alt:"Cloudflare"})),Object(o.b)("h2",{id:"cloudflare-configuration"},"Cloudflare Configuration"),Object(o.b)("h3",{id:"cname"},"CNAME"),Object(o.b)("p",null,"To finish the configuration on Cloudfalre, open the DNS Settings:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/4.png",alt:"Cloudflare"})),Object(o.b)("p",null,"And add a CNAME entry with the value taken from the Qovery Console just like this:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/5.png",alt:"Cloudflare"})),Object(o.b)("p",null,"You can safely use the ",Object(o.b)("inlineCode",{parentName:"p"},"Proxy")," mode."),Object(o.b)("h3",{id:"ssltls"},"SSL/TLS"),Object(o.b)("p",null,"The last step to configure the domain Cloudflare side properly, is to use the ",Object(o.b)("inlineCode",{parentName:"p"},"Full")," TLS encryption:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/6.png",alt:"Cloudflare"})),Object(o.b)("p",null,"This is the requirement to make Custom Domain work properly using Cloudflare as the domain provider on Qovery."),Object(o.b)("h3",{id:"restrict-application-access"},"Restrict application access"),Object(o.b)("p",null,"If you want to limit the application access via Cloudflare only, you have two ways to perform it:"),Object(o.b)("h4",{id:"ip-whitelisting"},"IP whitelisting"),Object(o.b)("p",null,"In Qovery it is possible to whitelist a range of IPs that can reach your application:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"In the advanced settings section of your application:",Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/8.png",alt:"Cloudflare"}))),Object(o.b)("li",{parentName:"ul"},"Get the ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.cloudflare.com/ips-v4/"}),"Cloudflare ips")),Object(o.b)("li",{parentName:"ul"},"Edit the ",Object(o.b)("inlineCode",{parentName:"li"},"network.ingress.whitelist_source_range")," setting and add the Cloudflare IPs separated with a comma:",Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/9.png",alt:"Cloudflare"}))),Object(o.b)("li",{parentName:"ul"},"Save and redeploy your application")),Object(o.b)("h4",{id:"cloudflared"},"Cloudflared"),Object(o.b)("p",null,"Cloudflared establishes outbound connections (tunnels) between your resources and Cloudflare\u2019s global network."),Object(o.b)("p",null,"You have different ways to install Cloudflared on your cluster, you can find the installation instructions within this ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel/"}),"documentation"),"\nSince Cloudflared establishes a tunnel for you and the domain and TLS management is done by Cloudflare, you don't need to expose publicly the application during the setup (See ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#ports"}),"port setup")),Object(o.b)("p",null,"You can decide to install Cloudflared by yourself or via Qovery. Within the section below, you will find documentation on how to install Cloudflared as a container in one of the Qovery environments.\nBy creating and deploying the following service, using the Cloudflared image:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/10.png",alt:"Cloudflare"})),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Create a ",Object(o.b)("inlineCode",{parentName:"p"},"TUNNEL_TOKEN")," secret environment variable (Scope: Environment) to pass the Cloudflare token."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/13.png",alt:"Cloudflare"}))),Object(o.b)("p",null,"Once your tunnel is created and connected, you have to set the public hostname and the related service settings."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/11.png",alt:"Cloudflare"})),Object(o.b)("p",null,"To get the service name of your application deployed by Qovery, you can get it in your application variables:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/12.png",alt:"Cloudflare"})),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"This setup works for static environments but not for dynamic ones since the service name is dynamic. We should probably suggest to use the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/cloudflare/helm-charts"}),"cloudflared helm chart")," once we release helm deployment")),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"After following the steps from above, our application should be accessible using the custom domain we selected:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/cloudflare/7.png",alt:"Cloudflare"})),Object(o.b)("p",null,"In the guide we went through all the necessary steps to configure Cloudflare and Qovery to make use of your custom domain."))}d.isMDXComponent=!0},423:function(e,t,n){var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var u=r.a.createContext({}),s=function(e){var t=r.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},d=function(e){var t=s(e.components);return r.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},b=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),d=s(n),b=a,f=d["".concat(i,".").concat(b)]||d[b]||p[b]||o;return n?r.a.createElement(f,l({ref:t},u,{components:n})):r.a.createElement(f,l({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=b;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,i[1]=l;for(var u=2;u1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,u=void 0===c?n:r(c,n);u>l;)t[l++]=e;return t}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(432),c=n(20),u=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,s=n||c,d=Object(l.a)(s),p=Object(r.useRef)(!1),b=u.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!b&&d&&window.docusaurus.prefetch(s),function(){b&&t&&t.disconnect()}}),[s,b,d]),s&&d?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,a;b&&e&&d&&(n=e,a=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:s})):o.a.createElement("a",Object(a.a)({},e,{href:s}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),i=n(423),l=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,u=e.size,s=e.target,d=e.to,p=l()("jump-to","jump-to--"+u,n),b=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(c||"chevron-right")+" arrow"}))));return s?r.a.createElement("a",{href:d,target:s,className:p},b):r.a.createElement(o.a,{to:d,className:p},b)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/e61780f0.47d7cd59.js.LICENSE.txt b/e5653b8d.ca58aa43.js.LICENSE.txt similarity index 100% rename from e61780f0.47d7cd59.js.LICENSE.txt rename to e5653b8d.ca58aa43.js.LICENSE.txt diff --git a/e5b9b0aa.95998124.js b/e5b9b0aa.10b14e43.js similarity index 91% rename from e5b9b0aa.95998124.js rename to e5b9b0aa.10b14e43.js index 230ba4d6bb..d6ee3fdb0e 100644 --- a/e5b9b0aa.95998124.js +++ b/e5b9b0aa.10b14e43.js @@ -1,2 +1,2 @@ -/*! For license information please see e5b9b0aa.95998124.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[243],{395:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return c})),r.d(t,"metadata",(function(){return u})),r.d(t,"rightToc",(function(){return s})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),o=(r(0),r(422)),i=(r(431),r(426),r(421)),c={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Migration",description:"Learn how to migrate your applications with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Migration",description:"Learn how to migrate your applications with Qovery",permalink:"/guides/advanced/migration",readingTime:"2 min read",source:"@site/guides/advanced/migration.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Migration",truncated:!1,prevItem:{title:"Migrate your application from Heroku to AWS",permalink:"/guides/tutorial/migrate-your-application-from-heroku-to-aws"},nextItem:{title:"Monitoring",permalink:"/guides/advanced/monitoring"}},s=[{value:"Resources",id:"resources",children:[]},{value:"Migration assistance",id:"migration-assistance",children:[]},{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},l,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"You plan to migrate to AWS (Amazon Web Services), GCP (Google Cloud Platform) or Microsoft Azure with Qovery? This guide is for you."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to migrate your applications to your favorite cloud provider with Qovery."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Are you migrating from Digital Ocean, OVH, Netlify or any other cloud provider? You can use the same resources to migrate your applications. Qovery provides the same features for all cloud providers.")),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/migrate-your-application-from-heroku-to-aws/"}),"Migrate from Heroku to AWS")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/migrate-your-application-from-heroku-to-aws/"}),"Complete guide to migrate from Heroku to AWS with Qovery")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Migration checklist"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Comprehensive migration checklist to read before migrating your applications with Qovery (coming soon)"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=migration"}),"Forum")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=migration"}),'List "Migration" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"migration-assistance"},"Migration assistance"),Object(o.b)("p",null,"Qovery provides a migration assistance to help you migrate your applications with Qovery. Contact us via the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://en.wikipedia.org/wiki/System_console"}),"Qovery Console")," and ask for migration assistance via the chat."),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},420:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(r),b=n,d=p["".concat(i,".").concat(b)]||p[b]||m[b]||o;return r?a.a.createElement(d,c({ref:t},s,{components:r})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=b;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s1?arguments[1]:void 0,r),u=i>2?arguments[2]:void 0,s=void 0===u?r:a(u,r);s>c;)t[c++]=e;return t}},425:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,r){"use strict";r(425);var n=r(0),a=r.n(n),o=r(421);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},428:function(e,t,r){"use strict";var n=r(432),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(r(n,e,i.length))})),i.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(420),r(428)),i=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(n.useState)(null),p=l[0],m=l[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return m("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see e5b9b0aa.10b14e43.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[246],{398:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return c})),r.d(t,"metadata",(function(){return u})),r.d(t,"rightToc",(function(){return s})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),o=(r(0),r(425)),i=(r(434),r(429),r(424)),c={last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Migration",description:"Learn how to migrate your applications with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Migration",description:"Learn how to migrate your applications with Qovery",permalink:"/guides/advanced/migration",readingTime:"2 min read",source:"@site/guides/advanced/migration.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Migration",truncated:!1,prevItem:{title:"Migrate your application from Heroku to AWS",permalink:"/guides/tutorial/migrate-your-application-from-heroku-to-aws"},nextItem:{title:"Monitoring",permalink:"/guides/advanced/monitoring"}},s=[{value:"Resources",id:"resources",children:[]},{value:"Migration assistance",id:"migration-assistance",children:[]},{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},l,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"You plan to migrate to AWS (Amazon Web Services), GCP (Google Cloud Platform) or Microsoft Azure with Qovery? This guide is for you."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to migrate your applications to your favorite cloud provider with Qovery."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Are you migrating from Digital Ocean, OVH, Netlify or any other cloud provider? You can use the same resources to migrate your applications. Qovery provides the same features for all cloud providers.")),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/migrate-your-application-from-heroku-to-aws/"}),"Migrate from Heroku to AWS")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"/guides/tutorial/migrate-your-application-from-heroku-to-aws/"}),"Complete guide to migrate from Heroku to AWS with Qovery")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Migration checklist"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Comprehensive migration checklist to read before migrating your applications with Qovery (coming soon)"),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=migration"}),"Forum")),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(n.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=migration"}),'List "Migration" threads from Qovery community forum')),Object(o.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"migration-assistance"},"Migration assistance"),Object(o.b)("p",null,"Qovery provides a migration assistance to help you migrate your applications with Qovery. Contact us via the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://en.wikipedia.org/wiki/System_console"}),"Qovery Console")," and ask for migration assistance via the chat."),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},423:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(r),b=n,d=p["".concat(i,".").concat(b)]||p[b]||m[b]||o;return r?a.a.createElement(d,c({ref:t},s,{components:r})):a.a.createElement(d,c({ref:t},s))}));function d(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=b;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var s=2;s1?arguments[1]:void 0,r),u=i>2?arguments[2]:void 0,s=void 0===u?r:a(u,r);s>c;)t[c++]=e;return t}},428:function(e,t,r){var n=r(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||r(10)&&n(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,r){"use strict";r(428);var n=r(0),a=r.n(n),o=r(424);t.a=function(e){var t=e.children,r=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},433:function(e,t,r){"use strict";var n=r(435),a=r(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var r=function(e){var t;switch(e.arrayFormat){case"index":return function(e,r,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return function(e,r,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};default:return function(e,t,r){void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=a({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),r(decodeURIComponent(a),o,n)})),Object.keys(n).sort().reduce((function(e,t){var r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(r):e[t]=r,e}),Object.create(null))):n},t.stringify=function(e,t){var r=function(e){switch(e.arrayFormat){case"index":return function(t,r,n){return null===r?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(r,e)].join("")};case"bracket":return function(t,r){return null===r?o(t,e):[o(t,e),"[]=",o(r,e)].join("")};default:return function(t,r){return null===r?o(t,e):[o(t,e),"=",o(r,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var a=e[n];if(void 0===a)return"";if(null===a)return o(n,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(r(n,e,i.length))})),i.join("&")}return o(n,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(423),r(433)),i=r.n(o);r(134);t.a=function(e){var t=e.children,r=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(n.useState)(null),p=l[0],m=l[1];return a.a.createElement("div",{className:"steps steps--h"+r},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return m("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/e7d0ec68.b0767d31.js.LICENSE.txt b/e5b9b0aa.10b14e43.js.LICENSE.txt similarity index 100% rename from e7d0ec68.b0767d31.js.LICENSE.txt rename to e5b9b0aa.10b14e43.js.LICENSE.txt diff --git a/e61780f0.47d7cd59.js b/e61780f0.ea7afb53.js similarity index 88% rename from e61780f0.47d7cd59.js rename to e61780f0.ea7afb53.js index 9ebbd3d27f..ef3ad97568 100644 --- a/e61780f0.47d7cd59.js +++ b/e61780f0.ea7afb53.js @@ -1,2 +1,2 @@ -/*! For license information please see e61780f0.47d7cd59.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[244],{396:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return u})),t.d(r,"metadata",(function(){return s})),t.d(r,"rightToc",(function(){return l})),t.d(r,"default",(function(){return f}));var n=t(1),o=t(9),a=(t(0),t(422)),c=t(421),i=t(429),u={last_modified_on:"2023-11-25",title:"Microsoft Azure",description:"Learn how to configure and plug your Microsoft Azure account"},s={id:"using-qovery/configuration/cloud-service-provider/microsoft-azure",title:"Microsoft Azure",description:"Learn how to configure and plug your Microsoft Azure account",source:"@site/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure.md",permalink:"/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure",sidebar:"docs",previous:{title:"Google Cloud Platform (GCP)",permalink:"/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform"},next:{title:"Scaleway (SCW)",permalink:"/docs/using-qovery/configuration/cloud-service-provider/scaleway"}},l=[{value:"Available Cloud Service Providers",id:"available-cloud-service-providers",children:[]}],p={rightToc:l};function f(e){var r=e.components,t=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},p,t,{components:r,mdxType:"MDXLayout"}),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Please refer to ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/provider/kubernetes/"}),"this page")," if you want to install Qovery on your own Kubernetes cluster (BYOK).")),Object(a.b)("p",null,"Azure is coming soon (",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"https://roadmap.qovery.com/roadmap/support-azure"}),"see when"),"). Vote ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"https://roadmap.qovery.com/roadmap/support-azure"}),"here")," to make it happen faster."),Object(a.b)("h2",{id:"available-cloud-service-providers"},"Available Cloud Service Providers"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services",mdxType:"Jump"},"Amazon Web Services (AWS)"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform",mdxType:"Jump"},"Google Cloud Platform (GCP)"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure",mdxType:"Jump"},"Azure"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/scaleway",mdxType:"Jump"},"Scaleway"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/other-csps",mdxType:"Jump"},"Others"))}f.isMDXComponent=!0},420:function(e,r,t){var n;!function(){"use strict";var t={}.hasOwnProperty;function o(){for(var e=[],r=0;r=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=o.a.createContext({}),l=function(e){var r=o.a.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):i({},r,{},e)),t},p=function(e){var r=l(e.components);return o.a.createElement(s.Provider,{value:r},e.children)},f={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},d=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,a=e.originalType,c=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(t),d=n,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||a;return t?o.a.createElement(m,i({ref:r},s,{components:t})):o.a.createElement(m,i({ref:r},s))}));function m(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var a=t.length,c=new Array(a);c[0]=d;var i={};for(var u in r)hasOwnProperty.call(r,u)&&(i[u]=r[u]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var s=2;s1?arguments[1]:void 0,t),u=c>2?arguments[2]:void 0,s=void 0===u?t:o(u,t);s>i;)r[i++]=e;return r}},427:function(e,r,t){"use strict";var n=t(1),o=t(0),a=t.n(o),c=t(39),i=t(430),u=t(20),s=t.n(u);r.a=function(e){var r,t=e.to,u=e.href,l=t||u,p=Object(i.a)(l),f=Object(o.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(l),function(){d&&r&&r.disconnect()}}),[l,d,p]),l&&p?a.a.createElement(c.b,Object(n.a)({},e,{onMouseEnter:function(){f.current||(window.docusaurus.preload(l),f.current=!0)},innerRef:function(e){var t,n;d&&e&&p&&(t=e,n=function(){window.docusaurus.prefetch(l)},(r=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(r.unobserve(t),r.disconnect(),n())}))}))).observe(t))},to:l})):a.a.createElement("a",Object(n.a)({},e,{href:l}))}},429:function(e,r,t){"use strict";var n=t(0),o=t.n(n),a=t(427),c=t(420),i=t.n(c);t(133);r.a=function(e){var r=e.children,t=e.className,n=e.badge,c=e.leftIcon,u=e.rightIcon,s=e.size,l=e.target,p=e.to,f=i()("jump-to","jump-to--"+s,t),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},c&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+c})),o.a.createElement("div",{className:"jump-to--main"},n?o.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",r),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return l?o.a.createElement("a",{href:p,target:l,className:f},d):o.a.createElement(a.a,{to:p,className:f},d)}},430:function(e,r,t){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(r,"a",(function(){return n}))}}]); \ No newline at end of file +/*! For license information please see e61780f0.ea7afb53.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[247],{399:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return u})),t.d(r,"metadata",(function(){return s})),t.d(r,"rightToc",(function(){return l})),t.d(r,"default",(function(){return f}));var n=t(1),o=t(9),a=(t(0),t(425)),c=t(424),i=t(431),u={last_modified_on:"2023-11-25",title:"Microsoft Azure",description:"Learn how to configure and plug your Microsoft Azure account"},s={id:"using-qovery/configuration/cloud-service-provider/microsoft-azure",title:"Microsoft Azure",description:"Learn how to configure and plug your Microsoft Azure account",source:"@site/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure.md",permalink:"/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure",sidebar:"docs",previous:{title:"Google Cloud Platform (GCP)",permalink:"/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform"},next:{title:"Scaleway (SCW)",permalink:"/docs/using-qovery/configuration/cloud-service-provider/scaleway"}},l=[{value:"Available Cloud Service Providers",id:"available-cloud-service-providers",children:[]}],p={rightToc:l};function f(e){var r=e.components,t=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},p,t,{components:r,mdxType:"MDXLayout"}),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Please refer to ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/provider/kubernetes/"}),"this page")," if you want to install Qovery on your own Kubernetes cluster (BYOK).")),Object(a.b)("p",null,"Azure is coming soon (",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"https://roadmap.qovery.com/roadmap/support-azure"}),"see when"),"). Vote ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"https://roadmap.qovery.com/roadmap/support-azure"}),"here")," to make it happen faster."),Object(a.b)("h2",{id:"available-cloud-service-providers"},"Available Cloud Service Providers"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services",mdxType:"Jump"},"Amazon Web Services (AWS)"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform",mdxType:"Jump"},"Google Cloud Platform (GCP)"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure",mdxType:"Jump"},"Azure"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/scaleway",mdxType:"Jump"},"Scaleway"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/other-csps",mdxType:"Jump"},"Others"))}f.isMDXComponent=!0},423:function(e,r,t){var n;!function(){"use strict";var t={}.hasOwnProperty;function o(){for(var e=[],r=0;r=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=o.a.createContext({}),l=function(e){var r=o.a.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):i({},r,{},e)),t},p=function(e){var r=l(e.components);return o.a.createElement(s.Provider,{value:r},e.children)},f={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},d=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,a=e.originalType,c=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(t),d=n,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||a;return t?o.a.createElement(m,i({ref:r},s,{components:t})):o.a.createElement(m,i({ref:r},s))}));function m(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var a=t.length,c=new Array(a);c[0]=d;var i={};for(var u in r)hasOwnProperty.call(r,u)&&(i[u]=r[u]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var s=2;s1?arguments[1]:void 0,t),u=c>2?arguments[2]:void 0,s=void 0===u?t:o(u,t);s>i;)r[i++]=e;return r}},430:function(e,r,t){"use strict";var n=t(1),o=t(0),a=t.n(o),c=t(39),i=t(432),u=t(20),s=t.n(u);r.a=function(e){var r,t=e.to,u=e.href,l=t||u,p=Object(i.a)(l),f=Object(o.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&p&&window.docusaurus.prefetch(l),function(){d&&r&&r.disconnect()}}),[l,d,p]),l&&p?a.a.createElement(c.b,Object(n.a)({},e,{onMouseEnter:function(){f.current||(window.docusaurus.preload(l),f.current=!0)},innerRef:function(e){var t,n;d&&e&&p&&(t=e,n=function(){window.docusaurus.prefetch(l)},(r=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(r.unobserve(t),r.disconnect(),n())}))}))).observe(t))},to:l})):a.a.createElement("a",Object(n.a)({},e,{href:l}))}},431:function(e,r,t){"use strict";var n=t(0),o=t.n(n),a=t(430),c=t(423),i=t.n(c);t(133);r.a=function(e){var r=e.children,t=e.className,n=e.badge,c=e.leftIcon,u=e.rightIcon,s=e.size,l=e.target,p=e.to,f=i()("jump-to","jump-to--"+s,t),d=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},c&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+c})),o.a.createElement("div",{className:"jump-to--main"},n?o.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",r),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return l?o.a.createElement("a",{href:p,target:l,className:f},d):o.a.createElement(a.a,{to:p,className:f},d)}},432:function(e,r,t){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(r,"a",(function(){return n}))}}]); \ No newline at end of file diff --git a/e8b0321f.beff7991.js.LICENSE.txt b/e61780f0.ea7afb53.js.LICENSE.txt similarity index 100% rename from e8b0321f.beff7991.js.LICENSE.txt rename to e61780f0.ea7afb53.js.LICENSE.txt diff --git a/e7d0ec68.b0767d31.js b/e7d0ec68.76cc2e0e.js similarity index 87% rename from e7d0ec68.b0767d31.js rename to e7d0ec68.76cc2e0e.js index 5c5e3d4d56..09500b31a2 100644 --- a/e7d0ec68.b0767d31.js +++ b/e7d0ec68.76cc2e0e.js @@ -1,2 +1,2 @@ -/*! For license information please see e7d0ec68.b0767d31.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[245],{397:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),a=n(9),o=(n(0),n(422)),i=(n(431),n(426),n(421)),c={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Deploy External Services",description:"Learn how to deploy any external services with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Deploy External Services",description:"Learn how to deploy any external services with Qovery",permalink:"/guides/advanced/deploy-external-services",readingTime:"1 min read",source:"@site/guides/advanced/deploy-external-services.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Deploy External Services",truncated:!1,prevItem:{title:"Deploy AWS Services",permalink:"/guides/advanced/deploy-aws-services"},nextItem:{title:"Deploy Frontend App",permalink:"/guides/advanced/deploy-frontend"}},s=[{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function p(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},"WIP"),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||f[d]||o;return n?a.a.createElement(m,c({ref:t},s,{components:n})):a.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:a(u,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),p=l[0],f=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return f("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see e7d0ec68.76cc2e0e.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[248],{400:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return p}));var r=n(1),a=n(9),o=(n(0),n(425)),i=(n(434),n(429),n(424)),c={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Deploy External Services",description:"Learn how to deploy any external services with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]},u={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Deploy External Services",description:"Learn how to deploy any external services with Qovery",permalink:"/guides/advanced/deploy-external-services",readingTime:"1 min read",source:"@site/guides/advanced/deploy-external-services.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Deploy External Services",truncated:!1,prevItem:{title:"Deploy AWS Services",permalink:"/guides/advanced/deploy-aws-services"},nextItem:{title:"Deploy Frontend App",permalink:"/guides/advanced/deploy-frontend"}},s=[{value:"Q&A",id:"qa",children:[]}],l={rightToc:s};function p(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},"WIP"),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}p.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),l=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,m=p["".concat(i,".").concat(d)]||p[d]||f[d]||o;return n?a.a.createElement(m,c({ref:t},s,{components:n})):a.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,s=void 0===u?n:a(u,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,u={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(u),l=Object(r.useState)(null),p=l[0],f=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return f("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/e9c994cf.b6e0768e.js.LICENSE.txt b/e7d0ec68.76cc2e0e.js.LICENSE.txt similarity index 100% rename from e9c994cf.b6e0768e.js.LICENSE.txt rename to e7d0ec68.76cc2e0e.js.LICENSE.txt diff --git a/e8b0321f.beff7991.js b/e8b0321f.9c64b53f.js similarity index 91% rename from e8b0321f.beff7991.js rename to e8b0321f.9c64b53f.js index 1738c23999..3d3cbdfaba 100644 --- a/e8b0321f.beff7991.js +++ b/e8b0321f.9c64b53f.js @@ -1,2 +1,2 @@ -/*! For license information please see e8b0321f.beff7991.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[246],{398:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return c})),a.d(t,"rightToc",(function(){return s})),a.d(t,"default",(function(){return l}));var r=a(1),n=a(9),o=(a(0),a(422)),i=(a(431),a(426),a(421),{last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Seed Database",description:"Learn how to seed your database with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),c={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Seed Database",description:"Learn how to seed your database with Qovery",permalink:"/guides/advanced/seed-database",readingTime:"2 min read",source:"@site/guides/advanced/seed-database.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Seed Database",truncated:!1,prevItem:{title:"Production",permalink:"/guides/advanced/production"},nextItem:{title:"Setting up Cloudflare and Custom Domain on Qovery",permalink:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery"}},s=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],u={rightToc:s};function l(e){var t=e.components,a=Object(n.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Seeding a database is a common task when developing an application. It allows you to populate your database with some data to test your application.\nQovery provides multiple ways to seed your database."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to seed your database with Qovery."),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/data-seeding-in-postgres/"}),"Seed your database with a SQL script (simple)")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/data-seeding-in-postgres/"}),"Seed your database with a SQL script and a Docker ENTRYPOINT instruction")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-postgres-database-with-sql-script"}),"Seed your database with a SQL script (advanced)")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-postgres-database-with-sql-script"}),"Seed your database with a SQL script and a Lifecycle Job")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-database-with-replibyte"}),"Seed your database with Replibyte (advanced)")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-database-with-replibyte"}),"Seed your database with Replibyte and a Lifecycle Job")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"Migrate your database schema")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"Migrate your database schema with a Docker ENTRYPOINT instruction")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=seed%20database"}),"Forum")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=seed%20database"}),'List "Seed Database" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}l.isMDXComponent=!0},420:function(e,t,a){var r;!function(){"use strict";var a={}.hasOwnProperty;function n(){for(var e=[],t=0;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var u=n.a.createContext({}),l=function(e){var t=n.a.useContext(u),a=t;return e&&(a="function"==typeof e?e(t):c({},t,{},e)),a},b=function(e){var t=l(e.components);return n.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},p=Object(r.forwardRef)((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),b=l(a),p=r,m=b["".concat(i,".").concat(p)]||b[p]||d[p]||o;return a?n.a.createElement(m,c({ref:t},u,{components:a})):n.a.createElement(m,c({ref:t},u))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=p;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,a),s=i>2?arguments[2]:void 0,u=void 0===s?a:n(s,a);u>c;)t[c++]=e;return t}},425:function(e,t,a){var r=a(28).f,n=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in n||a(10)&&r(n,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var r=a(0),n=a.n(r),o=a(421);t.a=function(e){var t=e.children,a=e.name;return n.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},428:function(e,t,a){"use strict";var r=a(432),n=a(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var a=function(e){var t;switch(e.arrayFormat){case"index":return function(e,a,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=a):r[e]=a};case"bracket":return function(e,a,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],a):r[e]=[a]:r[e]=a};default:return function(e,t,a){void 0!==a[e]?a[e]=[].concat(a[e],t):a[e]=t}}}(t=n({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),n=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),a(decodeURIComponent(n),o,r)})),Object.keys(r).sort().reduce((function(e,t){var a=r[t];return Boolean(a)&&"object"==typeof a&&!Array.isArray(a)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(a):e[t]=a,e}),Object.create(null))):r},t.stringify=function(e,t){var a=function(e){switch(e.arrayFormat){case"index":return function(t,a,r){return null===a?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(a,e)].join("")};case"bracket":return function(t,a){return null===a?o(t,e):[o(t,e),"[]=",o(a,e)].join("")};default:return function(t,a){return null===a?o(t,e):[o(t,e),"=",o(a,e)].join("")}}}(t=n({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var n=e[r];if(void 0===n)return"";if(null===n)return o(r,t);if(Array.isArray(n)){var i=[];return n.slice().forEach((function(e){void 0!==e&&i.push(a(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(n,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=(a(420),a(428)),i=a.n(o);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),b=l[0],d=l[1];return n.a.createElement("div",{className:"steps steps--h"+a},t,!o&&!b&&n.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",n.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",n.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&n.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",n.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,a){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see e8b0321f.9c64b53f.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[249],{401:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return c})),a.d(t,"rightToc",(function(){return s})),a.d(t,"default",(function(){return l}));var r=a(1),n=a(9),o=(a(0),a(425)),i=(a(434),a(429),a(424),{last_modified_on:"2023-06-07",$schema:"/.meta/.schemas/guides.json",title:"Seed Database",description:"Learn how to seed your database with Qovery",author_github:"https://github.com/evoxmusic",tags:["type: guide","technology: qovery"]}),c={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Seed Database",description:"Learn how to seed your database with Qovery",permalink:"/guides/advanced/seed-database",readingTime:"2 min read",source:"@site/guides/advanced/seed-database.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Seed Database",truncated:!1,prevItem:{title:"Production",permalink:"/guides/advanced/production"},nextItem:{title:"Setting up Cloudflare and Custom Domain on Qovery",permalink:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery"}},s=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",children:[]}],u={rightToc:s};function l(e){var t=e.components,a=Object(n.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},u,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Seeding a database is a common task when developing an application. It allows you to populate your database with some data to test your application.\nQovery provides multiple ways to seed your database."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"Here are some resources you can use to seed your database with Qovery."),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Title"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Author"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/data-seeding-in-postgres/"}),"Seed your database with a SQL script (simple)")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/data-seeding-in-postgres/"}),"Seed your database with a SQL script and a Docker ENTRYPOINT instruction")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-postgres-database-with-sql-script"}),"Seed your database with a SQL script (advanced)")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-postgres-database-with-sql-script"}),"Seed your database with a SQL script and a Lifecycle Job")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-database-with-replibyte"}),"Seed your database with Replibyte (advanced)")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://github.com/Qovery/lifecycle-job-examples/tree/main/examples/seed-database-with-replibyte"}),"Seed your database with Replibyte and a Lifecycle Job")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"Migrate your database schema")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/how-to-run-commands-at-application-startup/"}),"Migrate your database schema with a Docker ENTRYPOINT instruction")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Qovery")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=seed%20database"}),"Forum")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"https://discuss.qovery.com/search?q=seed%20database"}),'List "Seed Database" threads from Qovery community forum')),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Community")))),Object(o.b)("h2",{id:"qa"},"Q&A"),Object(o.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}l.isMDXComponent=!0},423:function(e,t,a){var r;!function(){"use strict";var a={}.hasOwnProperty;function n(){for(var e=[],t=0;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var u=n.a.createContext({}),l=function(e){var t=n.a.useContext(u),a=t;return e&&(a="function"==typeof e?e(t):c({},t,{},e)),a},b=function(e){var t=l(e.components);return n.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},p=Object(r.forwardRef)((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),b=l(a),p=r,m=b["".concat(i,".").concat(p)]||b[p]||d[p]||o;return a?n.a.createElement(m,c({ref:t},u,{components:a})):n.a.createElement(m,c({ref:t},u))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=p;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,a),s=i>2?arguments[2]:void 0,u=void 0===s?a:n(s,a);u>c;)t[c++]=e;return t}},428:function(e,t,a){var r=a(28).f,n=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in n||a(10)&&r(n,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var r=a(0),n=a.n(r),o=a(424);t.a=function(e){var t=e.children,a=e.name;return n.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},n.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},433:function(e,t,a){"use strict";var r=a(435),n=a(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var a=function(e){var t;switch(e.arrayFormat){case"index":return function(e,a,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=a):r[e]=a};case"bracket":return function(e,a,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],a):r[e]=[a]:r[e]=a};default:return function(e,t,a){void 0!==a[e]?a[e]=[].concat(a[e],t):a[e]=t}}}(t=n({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),n=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),a(decodeURIComponent(n),o,r)})),Object.keys(r).sort().reduce((function(e,t){var a=r[t];return Boolean(a)&&"object"==typeof a&&!Array.isArray(a)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(a):e[t]=a,e}),Object.create(null))):r},t.stringify=function(e,t){var a=function(e){switch(e.arrayFormat){case"index":return function(t,a,r){return null===a?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(a,e)].join("")};case"bracket":return function(t,a){return null===a?o(t,e):[o(t,e),"[]=",o(a,e)].join("")};default:return function(t,a){return null===a?o(t,e):[o(t,e),"=",o(a,e)].join("")}}}(t=n({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var n=e[r];if(void 0===n)return"";if(null===n)return o(r,t);if(Array.isArray(n)){var i=[];return n.slice().forEach((function(e){void 0!==e&&i.push(a(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(n,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=(a(423),a(433)),i=a.n(o);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),b=l[0],d=l[1];return n.a.createElement("div",{className:"steps steps--h"+a},t,!o&&!b&&n.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",n.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",n.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&n.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",n.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,a){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/eb0c7ce5.e02ddfe3.js.LICENSE.txt b/e8b0321f.9c64b53f.js.LICENSE.txt similarity index 100% rename from eb0c7ce5.e02ddfe3.js.LICENSE.txt rename to e8b0321f.9c64b53f.js.LICENSE.txt diff --git a/e9c994cf.b6e0768e.js b/e9c994cf.93a7041a.js similarity index 82% rename from e9c994cf.b6e0768e.js rename to e9c994cf.93a7041a.js index 685f1e64b9..95bddf2b6f 100644 --- a/e9c994cf.b6e0768e.js +++ b/e9c994cf.93a7041a.js @@ -1,2 +1,2 @@ -/*! For license information please see e9c994cf.b6e0768e.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[247],{399:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return d}));var r=n(1),a=n(9),o=(n(0),n(422)),i=n(431),c=n(421),l=n(426),u=(n(429),{last_modified_on:"2022-02-25",$schema:"/.meta/.schemas/guides.json",title:"Setup VPC peering on AWS with Qovery",description:"How to peer a Qovery VPC with an existing VPC on AWS",author_github:"https://github.com/l0ck3",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),b={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Setup VPC peering on AWS with Qovery",description:"How to peer a Qovery VPC with an existing VPC on AWS",permalink:"/guides/tutorial/aws-vpc-peering-with-qovery",readingTime:"6 min read",source:"@site/guides/tutorial/aws-vpc-peering-with-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Setup VPC peering on AWS with Qovery",truncated:!1,prevItem:{title:"Setting up Cloudflare and Custom Domain on Qovery",permalink:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery"},nextItem:{title:"Terraform",permalink:"/guides/advanced/terraform"}},s=[{value:"Goal",id:"goal",children:[]}],p={rightToc:s};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"While Qovery is all you need to deploy and run your applications in AWS, you might have existing resources in another VPC that you want to access from your Qovery applications.\nThis tutorial will show you how to set up VPC peering between the Qovery VPC and an existing one in your account."),Object(o.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have an existing AWS VPC with a resource you need to access, like an RDS database"),Object(o.b)("li",{parentName:"ul"},"You have a ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.qovery.com/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes"}),"Qovery cluster ready on your AWS account")))),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Make sure the CIDR blocks of your two VPCs don't overlap. AWS won't allow the peering connection otherwise.",Object(o.b)("br",null),Object(o.b)("br",null),"To match this requirement, you can customize the Qovery VPC CIDR at cluster creation:",Object(o.b)("br",null),Object(o.b)("br",null),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/custom-cidr.png",alt:"Customise Qovery CIDR"}))),Object(o.b)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"In this tutorial, we will connect an existing VPC on our AWS accounts with the VPC of a Qovery managed cluster.\nWe should then be able to deploy an application using a PostgresSQL RDS instance in our existing VPC."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"gather-the-necessary-information"},"Gather the necessary information"),Object(o.b)("p",null,"Before we begin, you will need to gather some information. It is recommended that you keep this information at hand in a file for convenience."),Object(o.b)("p",null,"At the end of this step 1, you should have those elements:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Name"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Content"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"x.x.x.x/x")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-xxx")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"y.y.y.y/y")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-yyy")))),Object(o.b)("p",null,"Keep in mind the following convention:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Existing VPC: your current VPC infrastructure (not managed by Qovery)"),Object(o.b)("li",{parentName:"ul"},"Qovery VPC: the VPC deployed and managed by Qovery")),Object(o.b)("p",null),Object(o.b)("h5",{id:"your-existing-vpc-id"},"Your existing VPC ID"),Object(o.b)("p",null,"To get your existing VPC ID in your AWS console, go to: ",Object(o.b)("inlineCode",{parentName:"p"},"VPC > Your VPCs"),", find the VPC you would like to use as a peering target, and copy its ID"),Object(o.b)("p",null,"You will be able to have those information:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Name"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Content"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"x.x.x.x/x")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-xxx")))),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/vpc-console-1.png",alt:"AWS console VPC list"})),Object(o.b)("h5",{id:"the-qovery-vpc-id"},"The Qovery VPC ID"),Object(o.b)("p",null,"You can use the same method to get the Qovery VPC ID. It should be named ",Object(o.b)("inlineCode",{parentName:"p"},"qovery-eks-workers"),"."),Object(o.b)("p",null,"You will be able to have those information:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Name"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Content"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"x.x.x.x/x")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-xxx")))),Object(o.b)("p",null)),Object(o.b)("li",null,Object(o.b)("h5",{id:"the-cidr-ranges-of-both-vpcs"},"The CIDR ranges of both VPCs"),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Make sure the CIDR blocks of your two VPCs don't overlap or you won't be able to create the peering connection."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/find-cidr.png",alt:"AWS console VPC CIDR ranges"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-peering-connection"},"Create a peering connection"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"A VPC peering connection is a networking connection between two VPCs that enables you to route traffic between them privately.")),Object(o.b)("p",null,"In the AWS console, go to ",Object(o.b)("inlineCode",{parentName:"p"},"VPC > Peering connections")," and click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create peering connection")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Give it a name"),Object(o.b)("li",{parentName:"ul"},"As a requester, select your Qovery VPC"),Object(o.b)("li",{parentName:"ul"},"As an accepter, select your existing VPC"),Object(o.b)("li",{parentName:"ul"},"Click on ",Object(o.b)("inlineCode",{parentName:"li"},"Create peering connection"))),Object(o.b)("br",null),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/peering-form.png",alt:"AWS create VPC peering form"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"accept-the-peering-request"},"Accept the peering request"),Object(o.b)("p",null,"Once created, the peering connection needs to be accepted.\nOn the peering connection view, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Actions")," then ",Object(o.b)("inlineCode",{parentName:"p"},"Accept request")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/accept-peering-request.png",alt:"AWS accept VPC peering request"})),Object(o.b)("p",null,"You should see your peering connection marked as ",Object(o.b)("inlineCode",{parentName:"p"},"Active")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/peering-active.png",alt:"AWS VPC peering active"})),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("b",null,"Take note of the peering connection ID. You will need it later."))),Object(o.b)("li",null,Object(o.b)("h4",{id:"update-existing-vpc-route-table"},"Update existing VPC route table"),Object(o.b)("p",null,"In the AWS console of your ",Object(o.b)("strong",{parentName:"p"},"non Qovery VPC"),", go to ",Object(o.b)("inlineCode",{parentName:"p"},"VPC > Route Tables"),".\nYou can filter the list using the IDs you noted at step 1 to find the routing table for your existing VPC."),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"Thanks Kevin M. for your contribution here \ud83d\ude0a")),Object(o.b)("p",null,"For your existing VPC edit the route table:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/existing-rt.png",alt:"AWS VPC Qovery Route Table"})),Object(o.b)("p",null,"Click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Edit routes")," button then ",Object(o.b)("inlineCode",{parentName:"p"},"Add route"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/existing-rt-add.png",alt:"AWS VPC Qovery Route Table add route"})),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"As a destination, enter the CIDR of your Qovery VPC"),Object(o.b)("li",{parentName:"ul"},"As a target, select the ",Object(o.b)("inlineCode",{parentName:"li"},"Peering connection")," you created earlier")),Object(o.b)("p",null,"Click ",Object(o.b)("inlineCode",{parentName:"p"},"Save changes"),"."),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Do not alter existing routes. Make sure you are adding a new one.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"update-qovery-vpc-route-table"},"Update Qovery VPC route table"),Object(o.b)("p",null,"This part needs to be done through the Qovery console."),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Make sure you are adding a new route. Do not edit or remove existing routes to avoid service interruption."),Object(o.b)("p",null,"In the cluster settings, under the ",Object(o.b)("inlineCode",{parentName:"p"},"Network")," tab, click ",Object(o.b)("inlineCode",{parentName:"p"},"ADD ROUTE")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/qovery-rt.png",alt:"AWS VPC Qovery Route Table add route"})),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"As a destination, enter the CIDR of your existing VPC"),Object(o.b)("li",{parentName:"ul"},"As a target, enter the ID of the peering connection you created earlier"),Object(o.b)("li",{parentName:"ul"},"You can put anything you want as a description.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/qovery-rt-added.png",alt:"AWS VPC Qovery Route Table add route"})),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,'You need to update your cluster to apply the configuration change. Click on the cluster ellipsis > "update".'))),Object(o.b)("li",null,Object(o.b)("h4",{id:"update-the-security-groups"},"Update the security groups"),Object(o.b)("p",null,"Our two VPCs are now connected, but we still need to update the security groups to allow communication between the Qovery applications and your existing resources."),Object(o.b)("p",null,"What rules to put on your security groups depends on what you are trying to achieve.\nIn our case, we would like to access an RDS instance from our Qovery applications."),Object(o.b)("p",null,"We will edit the RDS security group in our existing VPC to add an inbound rule allowing PostgreSQL traffic from our Qovery instances:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/pg-inbound-rule.png",alt:"AWS Security Group inbound rules"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"deploy-an-application"},"Deploy an application"),Object(o.b)("p",null,"You should now be able to deploy an application using the RDS PostgreSQL database on your Qovery cluster.\nRefer to ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"this guide")," if you need help deploying an application on Qovery.")))),Object(o.b)("p",null,"You can learn more about VPC peering on AWS here: ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html"}),"https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html")))}d.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),b=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},s=function(e){var t=b(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),s=b(n),d=r,m=s["".concat(i,".").concat(d)]||s[d]||p[d]||o;return n?a.a.createElement(m,c({ref:t},u,{components:n})):a.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(430),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,s=Object(c.a)(b),p=Object(a.useRef)(!1),d=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!d&&s&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,s]),b&&s?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var n,r;d&&e&&s&&(n=e,r=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:b})):o.a.createElement("a",Object(r.a)({},e,{href:b}))}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,l=e.rightIcon,u=e.size,b=e.target,s=e.to,p=c()("jump-to","jump-to--"+u,n),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return b?a.a.createElement("a",{href:s,target:b,className:p},d):a.a.createElement(o.a,{to:s,className:p},d)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),b=Object(r.useState)(null),s=b[0],p=b[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!s&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==s&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see e9c994cf.93a7041a.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[250],{402:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return b})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return d}));var r=n(1),a=n(9),o=(n(0),n(425)),i=n(434),c=n(424),l=n(429),u=(n(431),{last_modified_on:"2022-02-25",$schema:"/.meta/.schemas/guides.json",title:"Setup VPC peering on AWS with Qovery",description:"How to peer a Qovery VPC with an existing VPC on AWS",author_github:"https://github.com/l0ck3",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),b={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Setup VPC peering on AWS with Qovery",description:"How to peer a Qovery VPC with an existing VPC on AWS",permalink:"/guides/tutorial/aws-vpc-peering-with-qovery",readingTime:"6 min read",source:"@site/guides/tutorial/aws-vpc-peering-with-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"Setup VPC peering on AWS with Qovery",truncated:!1,prevItem:{title:"Setting up Cloudflare and Custom Domain on Qovery",permalink:"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery"},nextItem:{title:"Terraform",permalink:"/guides/advanced/terraform"}},s=[{value:"Goal",id:"goal",children:[]}],p={rightToc:s};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"While Qovery is all you need to deploy and run your applications in AWS, you might have existing resources in another VPC that you want to access from your Qovery applications.\nThis tutorial will show you how to set up VPC peering between the Qovery VPC and an existing one in your account."),Object(o.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have an existing AWS VPC with a resource you need to access, like an RDS database"),Object(o.b)("li",{parentName:"ul"},"You have a ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://hub.qovery.com/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes"}),"Qovery cluster ready on your AWS account")))),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Make sure the CIDR blocks of your two VPCs don't overlap. AWS won't allow the peering connection otherwise.",Object(o.b)("br",null),Object(o.b)("br",null),"To match this requirement, you can customize the Qovery VPC CIDR at cluster creation:",Object(o.b)("br",null),Object(o.b)("br",null),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/custom-cidr.png",alt:"Customise Qovery CIDR"}))),Object(o.b)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"In this tutorial, we will connect an existing VPC on our AWS accounts with the VPC of a Qovery managed cluster.\nWe should then be able to deploy an application using a PostgresSQL RDS instance in our existing VPC."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"gather-the-necessary-information"},"Gather the necessary information"),Object(o.b)("p",null,"Before we begin, you will need to gather some information. It is recommended that you keep this information at hand in a file for convenience."),Object(o.b)("p",null,"At the end of this step 1, you should have those elements:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Name"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Content"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"x.x.x.x/x")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-xxx")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"y.y.y.y/y")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-yyy")))),Object(o.b)("p",null,"Keep in mind the following convention:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Existing VPC: your current VPC infrastructure (not managed by Qovery)"),Object(o.b)("li",{parentName:"ul"},"Qovery VPC: the VPC deployed and managed by Qovery")),Object(o.b)("p",null),Object(o.b)("h5",{id:"your-existing-vpc-id"},"Your existing VPC ID"),Object(o.b)("p",null,"To get your existing VPC ID in your AWS console, go to: ",Object(o.b)("inlineCode",{parentName:"p"},"VPC > Your VPCs"),", find the VPC you would like to use as a peering target, and copy its ID"),Object(o.b)("p",null,"You will be able to have those information:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Name"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Content"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"x.x.x.x/x")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC destination name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-xxx")))),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/vpc-console-1.png",alt:"AWS console VPC list"})),Object(o.b)("h5",{id:"the-qovery-vpc-id"},"The Qovery VPC ID"),Object(o.b)("p",null,"You can use the same method to get the Qovery VPC ID. It should be named ",Object(o.b)("inlineCode",{parentName:"p"},"qovery-eks-workers"),"."),Object(o.b)("p",null,"You will be able to have those information:"),Object(o.b)("table",null,Object(o.b)("thead",{parentName:"table"},Object(o.b)("tr",{parentName:"thead"},Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Name"),Object(o.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Content"))),Object(o.b)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source CIDR")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"x.x.x.x/x")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("strong",{parentName:"td"},"VPC source name")),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"vpc-xxx")))),Object(o.b)("p",null)),Object(o.b)("li",null,Object(o.b)("h5",{id:"the-cidr-ranges-of-both-vpcs"},"The CIDR ranges of both VPCs"),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Make sure the CIDR blocks of your two VPCs don't overlap or you won't be able to create the peering connection."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/find-cidr.png",alt:"AWS console VPC CIDR ranges"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"create-a-peering-connection"},"Create a peering connection"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"A VPC peering connection is a networking connection between two VPCs that enables you to route traffic between them privately.")),Object(o.b)("p",null,"In the AWS console, go to ",Object(o.b)("inlineCode",{parentName:"p"},"VPC > Peering connections")," and click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create peering connection")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Give it a name"),Object(o.b)("li",{parentName:"ul"},"As a requester, select your Qovery VPC"),Object(o.b)("li",{parentName:"ul"},"As an accepter, select your existing VPC"),Object(o.b)("li",{parentName:"ul"},"Click on ",Object(o.b)("inlineCode",{parentName:"li"},"Create peering connection"))),Object(o.b)("br",null),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/peering-form.png",alt:"AWS create VPC peering form"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"accept-the-peering-request"},"Accept the peering request"),Object(o.b)("p",null,"Once created, the peering connection needs to be accepted.\nOn the peering connection view, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Actions")," then ",Object(o.b)("inlineCode",{parentName:"p"},"Accept request")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/accept-peering-request.png",alt:"AWS accept VPC peering request"})),Object(o.b)("p",null,"You should see your peering connection marked as ",Object(o.b)("inlineCode",{parentName:"p"},"Active")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/peering-active.png",alt:"AWS VPC peering active"})),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("b",null,"Take note of the peering connection ID. You will need it later."))),Object(o.b)("li",null,Object(o.b)("h4",{id:"update-existing-vpc-route-table"},"Update existing VPC route table"),Object(o.b)("p",null,"In the AWS console of your ",Object(o.b)("strong",{parentName:"p"},"non Qovery VPC"),", go to ",Object(o.b)("inlineCode",{parentName:"p"},"VPC > Route Tables"),".\nYou can filter the list using the IDs you noted at step 1 to find the routing table for your existing VPC."),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"Thanks Kevin M. for your contribution here \ud83d\ude0a")),Object(o.b)("p",null,"For your existing VPC edit the route table:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/existing-rt.png",alt:"AWS VPC Qovery Route Table"})),Object(o.b)("p",null,"Click on the ",Object(o.b)("inlineCode",{parentName:"p"},"Edit routes")," button then ",Object(o.b)("inlineCode",{parentName:"p"},"Add route"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/existing-rt-add.png",alt:"AWS VPC Qovery Route Table add route"})),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"As a destination, enter the CIDR of your Qovery VPC"),Object(o.b)("li",{parentName:"ul"},"As a target, select the ",Object(o.b)("inlineCode",{parentName:"li"},"Peering connection")," you created earlier")),Object(o.b)("p",null,"Click ",Object(o.b)("inlineCode",{parentName:"p"},"Save changes"),"."),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Do not alter existing routes. Make sure you are adding a new one.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"update-qovery-vpc-route-table"},"Update Qovery VPC route table"),Object(o.b)("p",null,"This part needs to be done through the Qovery console."),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},"Make sure you are adding a new route. Do not edit or remove existing routes to avoid service interruption."),Object(o.b)("p",null,"In the cluster settings, under the ",Object(o.b)("inlineCode",{parentName:"p"},"Network")," tab, click ",Object(o.b)("inlineCode",{parentName:"p"},"ADD ROUTE")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/qovery-rt.png",alt:"AWS VPC Qovery Route Table add route"})),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"As a destination, enter the CIDR of your existing VPC"),Object(o.b)("li",{parentName:"ul"},"As a target, enter the ID of the peering connection you created earlier"),Object(o.b)("li",{parentName:"ul"},"You can put anything you want as a description.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/qovery-rt-added.png",alt:"AWS VPC Qovery Route Table add route"})),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,'You need to update your cluster to apply the configuration change. Click on the cluster ellipsis > "update".'))),Object(o.b)("li",null,Object(o.b)("h4",{id:"update-the-security-groups"},"Update the security groups"),Object(o.b)("p",null,"Our two VPCs are now connected, but we still need to update the security groups to allow communication between the Qovery applications and your existing resources."),Object(o.b)("p",null,"What rules to put on your security groups depends on what you are trying to achieve.\nIn our case, we would like to access an RDS instance from our Qovery applications."),Object(o.b)("p",null,"We will edit the RDS security group in our existing VPC to add an inbound rule allowing PostgreSQL traffic from our Qovery instances:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/aws-vpc-peering-with-qovery/pg-inbound-rule.png",alt:"AWS Security Group inbound rules"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"deploy-an-application"},"Deploy an application"),Object(o.b)("p",null,"You should now be able to deploy an application using the RDS PostgreSQL database on your Qovery cluster.\nRefer to ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"this guide")," if you need help deploying an application on Qovery.")))),Object(o.b)("p",null,"You can learn more about VPC peering on AWS here: ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html"}),"https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html")))}d.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=a.a.createContext({}),b=function(e){var t=a.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},s=function(e){var t=b(e.components);return a.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),s=b(n),d=r,m=s["".concat(i,".").concat(d)]||s[d]||p[d]||o;return n?a.a.createElement(m,c({ref:t},u,{components:n})):a.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,u=void 0===l?n:a(l,n);u>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(432),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,s=Object(c.a)(b),p=Object(a.useRef)(!1),d=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!d&&s&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,s]),b&&s?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var n,r;d&&e&&s&&(n=e,r=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:b})):o.a.createElement("a",Object(r.a)({},e,{href:b}))}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,l=e.rightIcon,u=e.size,b=e.target,s=e.to,p=c()("jump-to","jump-to--"+u,n),d=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},i&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+i})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return b?a.a.createElement("a",{href:s,target:b,className:p},d):a.a.createElement(o.a,{to:s,className:p},d)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),b=Object(r.useState)(null),s=b[0],p=b[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!s&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==s&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/f26e55ec.2e5c32dd.js.LICENSE.txt b/e9c994cf.93a7041a.js.LICENSE.txt similarity index 100% rename from f26e55ec.2e5c32dd.js.LICENSE.txt rename to e9c994cf.93a7041a.js.LICENSE.txt diff --git a/eb0c7ce5.e02ddfe3.js b/eb0c7ce5.c7cae1ab.js similarity index 73% rename from eb0c7ce5.e02ddfe3.js rename to eb0c7ce5.c7cae1ab.js index d374e49c15..506e0d9a8b 100644 --- a/eb0c7ce5.e02ddfe3.js +++ b/eb0c7ce5.c7cae1ab.js @@ -1,2 +1,2 @@ -/*! For license information please see eb0c7ce5.e02ddfe3.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[248],{400:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return d})),n.d(t,"default",(function(){return b}));var r=n(1),o=n(9),a=(n(0),n(422)),c=n(431),i=n(421),l=n(426),u=(n(429),{last_modified_on:"2022-01-27",$schema:"/.meta/.schemas/guides.json",title:"How to connect to a managed MongoDB instance on AWS",description:"How to connect to a managed MongoDB instance on AWS from your local client.",author_github:"https://github.com/l0ck3",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to connect to a managed MongoDB instance on AWS",description:"How to connect to a managed MongoDB instance on AWS from your local client.",permalink:"/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws",readingTime:"3 min read",source:"@site/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to connect to a managed MongoDB instance on AWS",truncated:!1,prevItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3"},nextItem:{title:"How to connect to your EKS cluster with kubectl",permalink:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl"}},d=[{value:"Goal",id:"goal",children:[]}],p={rightToc:d};function b(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"When creating a managed MongoDB instance on AWS via Qovery, you don't get a publicly accessible endpoint. While it is good from a security point of view, you still might need to connect to it from a local client. "),Object(a.b)(i.a,{type:"note",mdxType:"Alert"},"Public endpoint for managed MongoDB instance will be available in Q1 2022. This is a temporary workaround."),Object(a.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have a managed MongoDB instance up and running"),Object(a.b)("li",{parentName:"ul"},"You have access to your Kubernetes cluster through kubectl: ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"see how here")))),Object(a.b)("h2",{id:"goal"},"Goal"),Object(a.b)("p",null,"This tutorial will show you how to connect to your managed MongoDB instance private endpoint from your local machine, through your EKS cluster."),Object(a.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"open-two-terminal-windows-with-access-to-your-kubernetes-cluster"},"Open two terminal windows with access to your Kubernetes cluster"),Object(a.b)("p",null,"We will need to run two different commands to forward your local traffic to your database.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"export-the-required-environment-variables"},"Export the required environment variables"),Object(a.b)("p",null,"In each terminal window, export some env variables: "),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"export SERVICE_NAME=mongodb-tunnel\nexport ENDPOINT=\nexport PORT=\nexport LOCAL_PORT=8080 # you can use any other port available on your computer\n"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"run-a-socat-container-in-your-cluster"},"Run a socat container in your cluster"),Object(a.b)("p",null,Object(a.b)("inlineCode",{parentName:"p"},"socat")," is a relay for bidirectional data transfers between two independent data channels.\nIt will forward all traffic between your computer and your database."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"kubectl run ${SERVICE_NAME} --image=alpine/socat \\\n -it --tty --rm --expose=true --port=${PORT} \\\n -- \\\n tcp-listen:${PORT},fork,reuseaddr \\\n tcp-connect:${ENDPOINT}:${PORT}\n"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"start-port-forwarding-to-your-socat-pod"},"Start port-forwarding to your socat pod"),Object(a.b)("p",null,"To access your ",Object(a.b)("inlineCode",{parentName:"p"},"socat")," pod from your container you will need to start a port-forwarding."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"kubectl port-forward service/${SERVICE_NAME} ${LOCAL_PORT}:${PORT}\n"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"download-the-mongodb-certificate"},"Download the MongoDB certificate"),Object(a.b)("p",null,"Connections to MongoDB instances on AWS use TLS. You will need the certificate to connect.\nYou can download it here: ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem"}),"https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"connect-to-your-db-instance"},"Connect to your DB instance"),Object(a.b)("p",null,"In this example we are using the Mongo Shell, but you can use any other client to connect to it.\nThe credentials are available on the Qovery console."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"mongosh --host 127.0.0.1 \\\n --port ${LOCAL_PORT} \\\n --username \\\n --tls --tlsCAFile /rds-combined-ca-bundle.pem \\\n --tlsAllowInvalidCertificates\n")),Object(a.b)(i.a,{type:"note",mdxType:"Alert"},"Since 127.0.0.1 is not listed in the certificate, you need to allow invalid certificates.")))))}b.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},d=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=s(n),b=r,m=d["".concat(c,".").concat(b)]||d[b]||p[b]||a;return n?o.a.createElement(m,i({ref:t},u,{components:n})):o.a.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,c=new Array(a);c[0]=b;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var u=2;u1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,u=void 0===l?n:o(l,n);u>i;)t[i++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),c=n(39),i=n(430),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,d=Object(i.a)(s),p=Object(o.useRef)(!1),b=u.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!b&&d&&window.docusaurus.prefetch(s),function(){b&&t&&t.disconnect()}}),[s,b,d]),s&&d?a.a.createElement(c.b,Object(r.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,r;b&&e&&d&&(n=e,r=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:s})):a.a.createElement("a",Object(r.a)({},e,{href:s}))}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var c=[];return o.slice().forEach((function(e){void 0!==e&&c.push(n(r,e,c.length))})),c.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(427),c=n(420),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,c=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,d=e.to,p=i()("jump-to","jump-to--"+u,n),b=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},c&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+c})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?o.a.createElement("a",{href:d,target:s,className:p},b):o.a.createElement(a.a,{to:d,className:p},b)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(420),n(428)),c=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(r.useState)(null),d=s[0],p=s[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!d&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==d&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see eb0c7ce5.c7cae1ab.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[251],{403:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return d})),n.d(t,"default",(function(){return b}));var r=n(1),o=n(9),a=(n(0),n(425)),c=n(434),i=n(424),l=n(429),u=(n(431),{last_modified_on:"2022-01-27",$schema:"/.meta/.schemas/guides.json",title:"How to connect to a managed MongoDB instance on AWS",description:"How to connect to a managed MongoDB instance on AWS from your local client.",author_github:"https://github.com/l0ck3",tags:["type: tutorial","cloud_provider: aws"],hide_pagination:!0}),s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to connect to a managed MongoDB instance on AWS",description:"How to connect to a managed MongoDB instance on AWS from your local client.",permalink:"/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws",readingTime:"3 min read",source:"@site/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"cloud_provider: aws",permalink:"/guides/tags/cloud-provider-aws"}],title:"How to connect to a managed MongoDB instance on AWS",truncated:!1,prevItem:{title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3",permalink:"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3"},nextItem:{title:"How to connect to your EKS cluster with kubectl",permalink:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl"}},d=[{value:"Goal",id:"goal",children:[]}],p={rightToc:d};function b(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"When creating a managed MongoDB instance on AWS via Qovery, you don't get a publicly accessible endpoint. While it is good from a security point of view, you still might need to connect to it from a local client. "),Object(a.b)(i.a,{type:"note",mdxType:"Alert"},"Public endpoint for managed MongoDB instance will be available in Q1 2022. This is a temporary workaround."),Object(a.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"You have a managed MongoDB instance up and running"),Object(a.b)("li",{parentName:"ul"},"You have access to your Kubernetes cluster through kubectl: ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/"}),"see how here")))),Object(a.b)("h2",{id:"goal"},"Goal"),Object(a.b)("p",null,"This tutorial will show you how to connect to your managed MongoDB instance private endpoint from your local machine, through your EKS cluster."),Object(a.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"open-two-terminal-windows-with-access-to-your-kubernetes-cluster"},"Open two terminal windows with access to your Kubernetes cluster"),Object(a.b)("p",null,"We will need to run two different commands to forward your local traffic to your database.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"export-the-required-environment-variables"},"Export the required environment variables"),Object(a.b)("p",null,"In each terminal window, export some env variables: "),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"export SERVICE_NAME=mongodb-tunnel\nexport ENDPOINT=\nexport PORT=\nexport LOCAL_PORT=8080 # you can use any other port available on your computer\n"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"run-a-socat-container-in-your-cluster"},"Run a socat container in your cluster"),Object(a.b)("p",null,Object(a.b)("inlineCode",{parentName:"p"},"socat")," is a relay for bidirectional data transfers between two independent data channels.\nIt will forward all traffic between your computer and your database."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"kubectl run ${SERVICE_NAME} --image=alpine/socat \\\n -it --tty --rm --expose=true --port=${PORT} \\\n -- \\\n tcp-listen:${PORT},fork,reuseaddr \\\n tcp-connect:${ENDPOINT}:${PORT}\n"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"start-port-forwarding-to-your-socat-pod"},"Start port-forwarding to your socat pod"),Object(a.b)("p",null,"To access your ",Object(a.b)("inlineCode",{parentName:"p"},"socat")," pod from your container you will need to start a port-forwarding."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"kubectl port-forward service/${SERVICE_NAME} ${LOCAL_PORT}:${PORT}\n"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"download-the-mongodb-certificate"},"Download the MongoDB certificate"),Object(a.b)("p",null,"Connections to MongoDB instances on AWS use TLS. You will need the certificate to connect.\nYou can download it here: ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem"}),"https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"connect-to-your-db-instance"},"Connect to your DB instance"),Object(a.b)("p",null,"In this example we are using the Mongo Shell, but you can use any other client to connect to it.\nThe credentials are available on the Qovery console."),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"mongosh --host 127.0.0.1 \\\n --port ${LOCAL_PORT} \\\n --username \\\n --tls --tlsCAFile /rds-combined-ca-bundle.pem \\\n --tlsAllowInvalidCertificates\n")),Object(a.b)(i.a,{type:"note",mdxType:"Alert"},"Since 127.0.0.1 is not listed in the certificate, you need to allow invalid certificates.")))))}b.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),s=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},d=function(e){var t=s(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},b=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=s(n),b=r,m=d["".concat(c,".").concat(b)]||d[b]||p[b]||a;return n?o.a.createElement(m,i({ref:t},u,{components:n})):o.a.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,c=new Array(a);c[0]=b;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:r,c[1]=i;for(var u=2;u1?arguments[1]:void 0,n),l=c>2?arguments[2]:void 0,u=void 0===l?n:o(l,n);u>i;)t[i++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),c=n(39),i=n(432),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,d=Object(i.a)(s),p=Object(o.useRef)(!1),b=u.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!b&&d&&window.docusaurus.prefetch(s),function(){b&&t&&t.disconnect()}}),[s,b,d]),s&&d?a.a.createElement(c.b,Object(r.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,r;b&&e&&d&&(n=e,r=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:s})):a.a.createElement("a",Object(r.a)({},e,{href:s}))}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(430),c=n(423),i=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,c=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,d=e.to,p=i()("jump-to","jump-to--"+u,n),b=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},c&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+c})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?o.a.createElement("a",{href:d,target:s,className:p},b):o.a.createElement(a.a,{to:d,className:p},b)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var c=[];return o.slice().forEach((function(e){void 0!==e&&c.push(n(r,e,c.length))})),c.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(423),n(433)),c=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(r.useState)(null),d=s[0],p=s[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!d&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==d&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/f3d8c143.119885e9.js.LICENSE.txt b/eb0c7ce5.c7cae1ab.js.LICENSE.txt similarity index 100% rename from f3d8c143.119885e9.js.LICENSE.txt rename to eb0c7ce5.c7cae1ab.js.LICENSE.txt diff --git a/f0f90e68.d22bdaf4.js b/f0f90e68.d81b93a4.js similarity index 94% rename from f0f90e68.d22bdaf4.js rename to f0f90e68.d81b93a4.js index 9aefe47b28..dc8c31a11a 100644 --- a/f0f90e68.d22bdaf4.js +++ b/f0f90e68.d81b93a4.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[249],{401:function(e,r,t){"use strict";t.r(r),t.d(r,"frontMatter",(function(){return i})),t.d(r,"metadata",(function(){return c})),t.d(r,"rightToc",(function(){return u})),t.d(r,"default",(function(){return p}));var n=t(1),o=t(9),a=(t(0),t(422)),i={last_modified_on:"2022-07-09",title:"Terraform",description:"Learn how to use Terraform with Qovery"},c={id:"using-qovery/interface/terraform-interface",title:"Terraform",description:"Learn how to use Terraform with Qovery",source:"@site/docs/using-qovery/interface/terraform-interface.md",permalink:"/docs/using-qovery/interface/terraform-interface",sidebar:"docs",previous:{title:"REST API",permalink:"/docs/using-qovery/interface/rest-api"},next:{title:"Integrations",permalink:"/docs/using-qovery/integration"}},u=[],f={rightToc:u};function p(e){var r=e.components,t=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},f,t,{components:r,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Check out ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"this Terraform documentation"),"."))}p.isMDXComponent=!0},422:function(e,r,t){"use strict";t.d(r,"a",(function(){return s})),t.d(r,"b",(function(){return y}));var n=t(0),o=t.n(n);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function c(e){for(var r=1;r=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var f=o.a.createContext({}),p=function(e){var r=o.a.useContext(f),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},s=function(e){var r=p(e.components);return o.a.createElement(f.Provider,{value:r},e.children)},l={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},m=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,f=u(e,["components","mdxType","originalType","parentName"]),s=p(t),m=n,y=s["".concat(i,".").concat(m)]||s[m]||l[m]||a;return t?o.a.createElement(y,c({ref:r},f,{components:t})):o.a.createElement(y,c({ref:r},f))}));function y(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var a=t.length,i=new Array(a);i[0]=m;var c={};for(var u in r)hasOwnProperty.call(r,u)&&(c[u]=r[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var f=2;f=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var f=o.a.createContext({}),p=function(e){var r=o.a.useContext(f),t=r;return e&&(t="function"==typeof e?e(r):c({},r,{},e)),t},s=function(e){var r=p(e.components);return o.a.createElement(f.Provider,{value:r},e.children)},l={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},m=Object(n.forwardRef)((function(e,r){var t=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,f=u(e,["components","mdxType","originalType","parentName"]),s=p(t),m=n,y=s["".concat(i,".").concat(m)]||s[m]||l[m]||a;return t?o.a.createElement(y,c({ref:r},f,{components:t})):o.a.createElement(y,c({ref:r},f))}));function y(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var a=t.length,i=new Array(a);i[0]=m;var c={};for(var u in r)hasOwnProperty.call(r,u)&&(c[u]=r[u]);c.originalType=e,c.mdxType="string"==typeof e?e:n,i[1]=c;for(var f=2;f=0||(r[o]=e[o]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(r[o]=e[o])}return r}var u=r.a.createContext({}),s=function(e){var t=r.a.useContext(u),o=t;return e&&(o="function"==typeof e?e(t):l({},t,{},e)),o},p=function(e){var t=s(e.components);return r.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var o=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(o),d=n,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return o?r.a.createElement(m,l({ref:t},u,{components:o})):r.a.createElement(m,l({ref:t},u))}));function m(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=o.length,i=new Array(a);i[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:n,i[1]=l;for(var u=2;u1?arguments[1]:void 0,o),c=i>2?arguments[2]:void 0,u=void 0===c?o:r(c,o);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see f26e55ec.afcd3cb2.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[254],{406:function(e,t,o){"use strict";o.r(t),o.d(t,"frontMatter",(function(){return l})),o.d(t,"metadata",(function(){return c})),o.d(t,"rightToc",(function(){return u})),o.d(t,"default",(function(){return p}));var n=o(1),r=o(9),a=(o(0),o(425)),i=o(424),l={last_modified_on:"2022-01-26",$schema:"/.meta/.schemas/guides.json",title:"Working with Git Submodules",description:"How to use Git Submodules on Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Working with Git Submodules",description:"How to use Git Submodules on Qovery",permalink:"/guides/tutorial/working-with-git-submodules",readingTime:"2 min read",source:"@site/guides/tutorial/working-with-git-submodules.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Working with Git Submodules",truncated:!1,prevItem:{title:"Using Amazon SQS and Lambda on Qovery",permalink:"/guides/tutorial/aws-sqs-lambda-with-qovery"},nextItem:{title:"Zero to Hero - How to deploy your apps on AWS in 30 minutes",permalink:"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes"}},u=[{value:"Example",id:"example",children:[]},{value:"Private Submodules",id:"private-submodules",children:[]}],s={rightToc:u};function p(e){var t=e.components,o=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},s,o,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Some applications use ",Object(a.b)("strong",{parentName:"p"},"Git Submodules")," to resolve their dependencies. Git submodules are a feature of the Git SCM that allow you to include the files of one Git repository into another.\nThis short guide will explain how to use Git Submodules on Qovery."),Object(a.b)("h3",{id:"example"},"Example"),Object(a.b)("p",null,"To include the ",Object(a.b)("strong",{parentName:"p"},"Foo")," source code into the ",Object(a.b)("strong",{parentName:"p"},"Bar")," project, use the following commands:"),Object(a.b)("pre",null,Object(a.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ cd ~/code/Bar\n\n$ git submodule add https://github.com/myusername/Foo somefolder/Foo\nCloning into 'somefolder/Foo'...\nremote: Counting objects: 26, done.\nremote: Compressing objects: 100% (17/17), done.\nremote: Total 26 (delta 8), reused 19 (delta 5)\nUnpacking objects: 100% (26/26), done.\n")),Object(a.b)("p",null,"This would create a new submodule called ",Object(a.b)("strong",{parentName:"p"},"Foo")," and place ",Object(a.b)("strong",{parentName:"p"},"Foo")," code into ",Object(a.b)("strong",{parentName:"p"},"somefolder/Foo")," directory of ",Object(a.b)("strong",{parentName:"p"},"Bar")," app."),Object(a.b)("p",null,"After a Git Submodule is added locally, you need to commit it to your app repository:"),Object(a.b)("pre",null,Object(a.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),'$ git commit -am "adding a submodule"\n[master 314ef62] adding a submodule\n2 files changed, 4 insertions(+)\n')),Object(a.b)("p",null,"Committed submodule source code can be used by your application and is available in Qovery CI/CD build/deployment pipeline."),Object(a.b)("h3",{id:"private-submodules"},"Private Submodules"),Object(a.b)("p",null,"Qovery does not have access to locally available credentials, so if you want to use some way of authentication, there are two ways to achieve it."),Object(a.b)("h4",{id:"use-http-basic-authentication-url-scheme"},"Use HTTP basic authentication URL scheme:"),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Note the embedded credentials in the URL")),Object(a.b)("pre",null,Object(a.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ git submodule add https://username:password@github.com/myusername/FooBar\n")),Object(a.b)("p",null,"This adds a private Git Submodule to the application while still allowing it to resolve in non-local environments."),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"This solution is not recommended.\nSince the credentials are stored in plaintext in the ",Object(a.b)("inlineCode",{parentName:"p"},".git/submodules")," directory, you should prefer the SSH / Git option.")),Object(a.b)("h4",{id:"ssh--git-protocol-submodules"},"SSH / Git protocol Submodules"),Object(a.b)("p",null,"For Qovery to be able to access those private submodules when cloning your application repository, you need to add a secret named ",Object(a.b)("inlineCode",{parentName:"p"},"GIT_SSH_KEY_xxx"),",\n(where xxx can be replaced by anything), containing a private SSH key with access to your Git repository."),Object(a.b)("p",null,"SSH:"),Object(a.b)("pre",null,Object(a.b)("code",Object(n.a)({parentName:"pre"},{}),'[submodule "path/to/module"]\n url = ssh://user/repo\n')),Object(a.b)("p",null,"Git:"),Object(a.b)("pre",null,Object(a.b)("code",Object(n.a)({parentName:"pre"},{}),'[submodule "path/to/module"]\n url = git://github.com/torvalds/linux.git\n')))}p.isMDXComponent=!0},423:function(e,t,o){var n;!function(){"use strict";var o={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[o]=e[o]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(r[o]=e[o])}return r}var u=r.a.createContext({}),s=function(e){var t=r.a.useContext(u),o=t;return e&&(o="function"==typeof e?e(t):l({},t,{},e)),o},p=function(e){var t=s(e.components);return r.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var o=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(o),d=n,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return o?r.a.createElement(m,l({ref:t},u,{components:o})):r.a.createElement(m,l({ref:t},u))}));function m(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=o.length,i=new Array(a);i[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:n,i[1]=l;for(var u=2;u1?arguments[1]:void 0,o),c=i>2?arguments[2]:void 0,u=void 0===c?o:r(c,o);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file diff --git a/f756422c.634ffbc6.js.LICENSE.txt b/f26e55ec.afcd3cb2.js.LICENSE.txt similarity index 100% rename from f756422c.634ffbc6.js.LICENSE.txt rename to f26e55ec.afcd3cb2.js.LICENSE.txt diff --git a/f26e55ec.2e5c32dd.js b/f3d8c143.8e5e24d9.js similarity index 93% rename from f26e55ec.2e5c32dd.js rename to f3d8c143.8e5e24d9.js index 0671fadbc2..6e770b3abd 100644 --- a/f26e55ec.2e5c32dd.js +++ b/f3d8c143.8e5e24d9.js @@ -1,2 +1,2 @@ -/*! For license information please see f26e55ec.2e5c32dd.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[251],{403:function(e,t,o){"use strict";o.r(t),o.d(t,"frontMatter",(function(){return l})),o.d(t,"metadata",(function(){return c})),o.d(t,"rightToc",(function(){return u})),o.d(t,"default",(function(){return p}));var n=o(1),r=o(9),a=(o(0),o(422)),i=o(421),l={last_modified_on:"2022-01-26",$schema:"/.meta/.schemas/guides.json",title:"Working with Git Submodules",description:"How to use Git Submodules on Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Working with Git Submodules",description:"How to use Git Submodules on Qovery",permalink:"/guides/tutorial/working-with-git-submodules",readingTime:"2 min read",source:"@site/guides/tutorial/working-with-git-submodules.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Working with Git Submodules",truncated:!1,prevItem:{title:"Using Amazon SQS and Lambda on Qovery",permalink:"/guides/tutorial/aws-sqs-lambda-with-qovery"},nextItem:{title:"Zero to Hero - How to deploy your apps on AWS in 30 minutes",permalink:"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes"}},u=[{value:"Example",id:"example",children:[]},{value:"Private Submodules",id:"private-submodules",children:[]}],s={rightToc:u};function p(e){var t=e.components,o=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},s,o,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Some applications use ",Object(a.b)("strong",{parentName:"p"},"Git Submodules")," to resolve their dependencies. Git submodules are a feature of the Git SCM that allow you to include the files of one Git repository into another.\nThis short guide will explain how to use Git Submodules on Qovery."),Object(a.b)("h3",{id:"example"},"Example"),Object(a.b)("p",null,"To include the ",Object(a.b)("strong",{parentName:"p"},"Foo")," source code into the ",Object(a.b)("strong",{parentName:"p"},"Bar")," project, use the following commands:"),Object(a.b)("pre",null,Object(a.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ cd ~/code/Bar\n\n$ git submodule add https://github.com/myusername/Foo somefolder/Foo\nCloning into 'somefolder/Foo'...\nremote: Counting objects: 26, done.\nremote: Compressing objects: 100% (17/17), done.\nremote: Total 26 (delta 8), reused 19 (delta 5)\nUnpacking objects: 100% (26/26), done.\n")),Object(a.b)("p",null,"This would create a new submodule called ",Object(a.b)("strong",{parentName:"p"},"Foo")," and place ",Object(a.b)("strong",{parentName:"p"},"Foo")," code into ",Object(a.b)("strong",{parentName:"p"},"somefolder/Foo")," directory of ",Object(a.b)("strong",{parentName:"p"},"Bar")," app."),Object(a.b)("p",null,"After a Git Submodule is added locally, you need to commit it to your app repository:"),Object(a.b)("pre",null,Object(a.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),'$ git commit -am "adding a submodule"\n[master 314ef62] adding a submodule\n2 files changed, 4 insertions(+)\n')),Object(a.b)("p",null,"Committed submodule source code can be used by your application and is available in Qovery CI/CD build/deployment pipeline."),Object(a.b)("h3",{id:"private-submodules"},"Private Submodules"),Object(a.b)("p",null,"Qovery does not have access to locally available credentials, so if you want to use some way of authentication, there are two ways to achieve it."),Object(a.b)("h4",{id:"use-http-basic-authentication-url-scheme"},"Use HTTP basic authentication URL scheme:"),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Note the embedded credentials in the URL")),Object(a.b)("pre",null,Object(a.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ git submodule add https://username:password@github.com/myusername/FooBar\n")),Object(a.b)("p",null,"This adds a private Git Submodule to the application while still allowing it to resolve in non-local environments."),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"This solution is not recommended.\nSince the credentials are stored in plaintext in the ",Object(a.b)("inlineCode",{parentName:"p"},".git/submodules")," directory, you should prefer the SSH / Git option.")),Object(a.b)("h4",{id:"ssh--git-protocol-submodules"},"SSH / Git protocol Submodules"),Object(a.b)("p",null,"For Qovery to be able to access those private submodules when cloning your application repository, you need to add a secret named ",Object(a.b)("inlineCode",{parentName:"p"},"GIT_SSH_KEY_xxx"),",\n(where xxx can be replaced by anything), containing a private SSH key with access to your Git repository."),Object(a.b)("p",null,"SSH:"),Object(a.b)("pre",null,Object(a.b)("code",Object(n.a)({parentName:"pre"},{}),'[submodule "path/to/module"]\n url = ssh://user/repo\n')),Object(a.b)("p",null,"Git:"),Object(a.b)("pre",null,Object(a.b)("code",Object(n.a)({parentName:"pre"},{}),'[submodule "path/to/module"]\n url = git://github.com/torvalds/linux.git\n')))}p.isMDXComponent=!0},420:function(e,t,o){var n;!function(){"use strict";var o={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[o]=e[o]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(r[o]=e[o])}return r}var u=r.a.createContext({}),s=function(e){var t=r.a.useContext(u),o=t;return e&&(o="function"==typeof e?e(t):l({},t,{},e)),o},p=function(e){var t=s(e.components);return r.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var o=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(o),d=n,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return o?r.a.createElement(m,l({ref:t},u,{components:o})):r.a.createElement(m,l({ref:t},u))}));function m(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=o.length,i=new Array(a);i[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:n,i[1]=l;for(var u=2;u1?arguments[1]:void 0,o),c=i>2?arguments[2]:void 0,u=void 0===c?o:r(c,o);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see f3d8c143.8e5e24d9.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[255],{407:function(e,t,o){"use strict";o.r(t),o.d(t,"frontMatter",(function(){return l})),o.d(t,"metadata",(function(){return c})),o.d(t,"rightToc",(function(){return u})),o.d(t,"default",(function(){return p}));var n=o(1),r=o(9),a=(o(0),o(425)),i=o(424),l={last_modified_on:"2022-01-26",$schema:"/.meta/.schemas/guides.json",title:"Working with Git Submodules",description:"How to use Git Submodules on Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},c={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Working with Git Submodules",description:"How to use Git Submodules on Qovery",permalink:"/guides/tutorial/working-with-git-submodules",readingTime:"2 min read",source:"@site/guides/tutorial/working-with-git-submodules.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Working with Git Submodules",truncated:!1,prevItem:{title:"Using Amazon SQS and Lambda on Qovery",permalink:"/guides/tutorial/aws-sqs-lambda-with-qovery"},nextItem:{title:"Zero to Hero - How to deploy your apps on AWS in 30 minutes",permalink:"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes"}},u=[{value:"Example",id:"example",children:[]},{value:"Private Submodules",id:"private-submodules",children:[]}],s={rightToc:u};function p(e){var t=e.components,o=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},s,o,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Some applications use ",Object(a.b)("strong",{parentName:"p"},"Git Submodules")," to resolve their dependencies. Git submodules are a feature of the Git SCM that allow you to include the files of one Git repository into another.\nThis short guide will explain how to use Git Submodules on Qovery."),Object(a.b)("h3",{id:"example"},"Example"),Object(a.b)("p",null,"To include the ",Object(a.b)("strong",{parentName:"p"},"Foo")," source code into the ",Object(a.b)("strong",{parentName:"p"},"Bar")," project, use the following commands:"),Object(a.b)("pre",null,Object(a.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ cd ~/code/Bar\n\n$ git submodule add https://github.com/myusername/Foo somefolder/Foo\nCloning into 'somefolder/Foo'...\nremote: Counting objects: 26, done.\nremote: Compressing objects: 100% (17/17), done.\nremote: Total 26 (delta 8), reused 19 (delta 5)\nUnpacking objects: 100% (26/26), done.\n")),Object(a.b)("p",null,"This would create a new submodule called ",Object(a.b)("strong",{parentName:"p"},"Foo")," and place ",Object(a.b)("strong",{parentName:"p"},"Foo")," code into ",Object(a.b)("strong",{parentName:"p"},"somefolder/Foo")," directory of ",Object(a.b)("strong",{parentName:"p"},"Bar")," app."),Object(a.b)("p",null,"After a Git Submodule is added locally, you need to commit it to your app repository:"),Object(a.b)("pre",null,Object(a.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),'$ git commit -am "adding a submodule"\n[master 314ef62] adding a submodule\n2 files changed, 4 insertions(+)\n')),Object(a.b)("p",null,"Committed submodule source code can be used by your application and is available in Qovery CI/CD build/deployment pipeline."),Object(a.b)("h3",{id:"private-submodules"},"Private Submodules"),Object(a.b)("p",null,"Qovery does not have access to locally available credentials, so if you want to use some way of authentication, there are two ways to achieve it."),Object(a.b)("h4",{id:"use-http-basic-authentication-url-scheme"},"Use HTTP basic authentication URL scheme:"),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Note the embedded credentials in the URL")),Object(a.b)("pre",null,Object(a.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"$ git submodule add https://username:password@github.com/myusername/FooBar\n")),Object(a.b)("p",null,"This adds a private Git Submodule to the application while still allowing it to resolve in non-local environments."),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"This solution is not recommended.\nSince the credentials are stored in plaintext in the ",Object(a.b)("inlineCode",{parentName:"p"},".git/submodules")," directory, you should prefer the SSH / Git option.")),Object(a.b)("h4",{id:"ssh--git-protocol-submodules"},"SSH / Git protocol Submodules"),Object(a.b)("p",null,"For Qovery to be able to access those private submodules when cloning your application repository, you need to add a secret named ",Object(a.b)("inlineCode",{parentName:"p"},"GIT_SSH_KEY_xxx"),",\n(where xxx can be replaced by anything), containing a private SSH key with access to your Git repository."),Object(a.b)("p",null,"SSH:"),Object(a.b)("pre",null,Object(a.b)("code",Object(n.a)({parentName:"pre"},{}),'[submodule "path/to/module"]\n url = ssh://user/repo\n')),Object(a.b)("p",null,"Git:"),Object(a.b)("pre",null,Object(a.b)("code",Object(n.a)({parentName:"pre"},{}),'[submodule "path/to/module"]\n url = git://github.com/torvalds/linux.git\n')))}p.isMDXComponent=!0},423:function(e,t,o){var n;!function(){"use strict";var o={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[o]=e[o]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(r[o]=e[o])}return r}var u=r.a.createContext({}),s=function(e){var t=r.a.useContext(u),o=t;return e&&(o="function"==typeof e?e(t):l({},t,{},e)),o},p=function(e){var t=s(e.components);return r.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(n.forwardRef)((function(e,t){var o=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(o),d=n,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return o?r.a.createElement(m,l({ref:t},u,{components:o})):r.a.createElement(m,l({ref:t},u))}));function m(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=o.length,i=new Array(a);i[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:n,i[1]=l;for(var u=2;u1?arguments[1]:void 0,o),c=i>2?arguments[2]:void 0,u=void 0===c?o:r(c,o);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file diff --git a/fb1d0a83.46851466.js.LICENSE.txt b/f3d8c143.8e5e24d9.js.LICENSE.txt similarity index 100% rename from fb1d0a83.46851466.js.LICENSE.txt rename to f3d8c143.8e5e24d9.js.LICENSE.txt diff --git a/ab8f5b83.7ad61e2b.js b/f7098925.c179454d.js similarity index 96% rename from ab8f5b83.7ad61e2b.js rename to f7098925.c179454d.js index 31d0970a1f..62bc5bb746 100644 --- a/ab8f5b83.7ad61e2b.js +++ b/f7098925.c179454d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[168],{320:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return p})),n.d(t,"metadata",(function(){return d})),n.d(t,"rightToc",(function(){return h})),n.d(t,"default",(function(){return g}));var a=n(1),r=n(9),o=(n(0),n(422)),i=n(421),l=n(429),s=n(431),c=n(434),b=n(441),u=n(426),p={last_modified_on:"2023-04-23",$schema:"/.meta/.schemas/guides.json",title:"URL Shortener API with Kotlin (Part 1/2)",description:"Create a URL shortener API with Kotlin, the micro-framework Ktor and PostgreSQL",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","language: kotlin","database: postgresql"],hide_pagination:!0},d={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"URL Shortener API with Kotlin (Part 1/2)",description:"Create a URL shortener API with Kotlin, the micro-framework Ktor and PostgreSQL",permalink:"/guides/tutorial/url-shortener-api-with-kotlin",readingTime:"14 min read",source:"@site/guides/tutorial/url-shortener-api-with-kotlin.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"language: kotlin",permalink:"/guides/tags/language-kotlin"},{label:"database: postgresql",permalink:"/guides/tags/database-postgresql"}],title:"URL Shortener API with Kotlin (Part 1/2)",truncated:!1,prevItem:{title:"Terraform",permalink:"/guides/advanced/terraform"},nextItem:{title:"Use an API gateway in front of multiple services",permalink:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services"}},h=[{value:"Introduction",id:"introduction",children:[]},{value:"What is a URL shortener?",id:"what-is-a-url-shortener",children:[]},{value:"Ktor principles",id:"ktor-principles",children:[{value:"Kotlin",id:"kotlin",children:[]},{value:"Functional programming",id:"functional-programming",children:[]},{value:"Asynchronous",id:"asynchronous",children:[]}]},{value:"HTTP Server",id:"http-server",children:[]},{value:"URL Encoder",id:"url-encoder",children:[{value:"Handle identifier collision",id:"handle-identifier-collision",children:[]}]},{value:"URL Decoder",id:"url-decoder",children:[]},{value:"Redirect",id:"redirect",children:[]},{value:"Stats: clicks over time",id:"stats-clicks-over-time",children:[]},{value:"Try the API",id:"try-the-api",children:[]},{value:"Connect to a PostgreSQL database with Exposed",id:"connect-to-a-postgresql-database-with-exposed",children:[]},{value:"Deploy in the Cloud with Qovery",id:"deploy-in-the-cloud-with-qovery",children:[{value:"Install Qovery CLI",id:"install-qovery-cli",children:[]},{value:"Sign up",id:"sign-up",children:[]},{value:"Create an application",id:"create-an-application",children:[]},{value:"Create a new project",id:"create-a-new-project",children:[]},{value:"Create a new environment",id:"create-a-new-environment",children:[]},{value:"Create a new application",id:"create-a-new-application",children:[]},{value:"Deploy a database",id:"deploy-a-database",children:[]},{value:"Connect to PostgreSQL",id:"connect-to-postgresql",children:[]},{value:"Deploy",id:"deploy",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],m={rightToc:h};function g(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},m,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"The source code for this post can be found on this ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/ktor-url-shortener"}),"github repo")),Object(o.b)("h2",{id:"introduction"},"Introduction"),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://ktor.io/"}),"Ktor")," is a brand new micro-framework created by the Jetbrains team, and running over the JVM. Jetbrains are the authors of ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://kotlinlang.org/"}),"Kotlin")," - which is now the official programming language for Android, and one of the most popular programming language on the JVM. Kotlin is gaining popularity on server-side and multi-platform application development."),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"Ktor is a framework for building asynchronous servers and clients in connected systems using the powerful Kotlin programming language.")),Object(o.b)("p",null,"In this article, you will learn:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"How to design a simple URL shortener."),Object(o.b)("li",{parentName:"ul"},"How to use the Ktor micro-framework with Kotlin"),Object(o.b)("li",{parentName:"ul"},"How to deploy a Ktor application")),Object(o.b)("p",null,"I have +4 years of experience using Spring, and I wanted to give a try to Ktor, which seems promising. Creating a URL shortener is an excellent way to start."),Object(o.b)("h2",{id:"what-is-a-url-shortener"},"What is a URL shortener?"),Object(o.b)("p",null,"A URL shortener is a simple tool that takes a long URL and turns it into a very short one"),Object(o.b)("p",null,Object(o.b)("img",Object(a.a)({parentName:"p"},{src:"https://uploads-ssl.webflow.com/5de176c0d41c9b4a1dbbb0aa/5e655859bc2ae5c7371efa36_urlshortener%20image.png",alt:"Flow of URL shortening - from original URL to short URL"}))),Object(o.b)("p",null,"It is commonly used for 3 reasons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Tracking clicks"),Object(o.b)("li",{parentName:"ul"},"Make URL much more concise."),Object(o.b)("li",{parentName:"ul"},"Hide original URL")),Object(o.b)("p",null,"One famous freemium provider is bit.ly (see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://uploads-ssl.webflow.com/5de176c0d41c9b4a1dbbb0aa/5e655a34bc2ae5452b1f124b_bitly.gif"}),"here"),")"),Object(o.b)("p",null,"In this article we will make a basic bit.ly like URL shortener. Let\u2019s go"),Object(o.b)("h2",{id:"ktor-principles"},"Ktor principles"),Object(o.b)("p",null,"Before starting I want to introduce the 3 main principles of Ktor."),Object(o.b)("h3",{id:"kotlin"},"Kotlin"),Object(o.b)("p",null,"Kotlin is the language used to develop on Ktor. It is an object-oriented and functional language. It is very stable and runs on the JVM. Kotlin is 100% interoperable with Java and allows you to benefit from its ecosystem (libraries, build system, etc.)."),Object(o.b)("h3",{id:"functional-programming"},"Functional programming"),Object(o.b)("p",null,"Ktor leverages the power of Kotlin and has a very functional approach. When writing code, everything seems obvious. It's very similar to what you can see on NodeJS. For me, coming from the Spring world, I find it very efficient to read and use."),Object(o.b)("h3",{id:"asynchronous"},"Asynchronous"),Object(o.b)("p",null,"Kotlin provides asynchronous code execution, thanks to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://kotlinlang.org/docs/reference/coroutines-overview.html"}),"coroutines"),". Ktor exploits this feature to its full potential, and even if you have the impression that you are writing code in a blocking manner, this is not the case. Ktor makes your life easier."),Object(o.b)("h2",{id:"http-server"},"HTTP Server"),Object(o.b)("p",null,"Here is a complete and simple example of how to expose an HTTP server (",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"http://localhost:8080"}),"http://localhost:8080"),") with Ktor."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'fun main(args: Array): Unit = io.ktor.server.netty.EngineMain.main(args)\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n routing {\n get("/") {\n call.respondText("Hello World", contentType = ContentType.Text.Plain)\n }\n }\n}\n')),Object(o.b)("h2",{id:"url-encoder"},"URL Encoder"),Object(o.b)("p",null,"The URL encoder will translate an incoming address into a smaller URL. The idea is to provide an ID that will identify the final URL. Using a hash function is perfect for this operation. However, the operation is non-reversible, meaning you can\u2019t retrieve the final URL by the generated identifier."),Object(o.b)("p",null,"Function to transform a long URL into a shorter URL"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// String extension\nfun String.encodeToID(): String {\n // hash String with MD5\n val hashBytes = MessageDigest.getInstance("MD5").digest(this.toByteArray(Charsets.UTF_8))\n // transform to human readable MD5 String\n val hashString = String.format("%032x", BigInteger(1, hashBytes))\n // truncate MD5 String\n val truncatedHashString = hashString.take(6)\n // return id\n return truncatedHashString\n}\n')),Object(o.b)("p",null,"We expose the function through the REST API"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// Request object\ndata class Request(val url: String) {\n fun toResponse(): Response = Response(url, url.encodeToID())\n}\n\n// Response object\ndata class Response(val originalURL: String, private val id: String) {\n val shortURL: String = "http://localhost:8080/$id"\n}\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n install(ContentNegotiation) {\n jackson {\n enable(SerializationFeature.INDENT_OUTPUT)\n propertyNamingStrategy = PropertyNamingStrategy.SNAKE_CASE\n }\n }\n\n // Hash Table Response object by ID\n val responseByID = mutableMapOf()\n\n routing {\n post("/api/v1/encode") {\n // Deserialize JSON body to Request object\n val request = call.receive()\n\n // find the Response object if it already exists\n val retrievedResponse = responseByID[request.url.encodeToID()]\n if (retrievedResponse != null) {\n // cache hit\n log.debug("cache hit $retrievedResponse")\n return@post call.respond(retrievedResponse)\n }\n\n // cache miss\n val response = request.toResponse()\n responseByID[request.url.encodeToID()] = response\n log.debug("cache miss $response")\n\n // Serialize Response object to JSON body\n call.respond(response)\n }\n }\n}\n')),Object(o.b)("h3",{id:"handle-identifier-collision"},"Handle identifier collision"),Object(o.b)("p",null,"Using a hash function makes no guarantee that it is not already being used. If it is in use, then you need to change it to another one. Note: even if the probability to have a collision is very low, you should handle this case."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// String extension (function signature has changed)\nfun String.encodeToID(truncateLength: Int = 6): String {\n // hash String with MD5\n val hashBytes = MessageDigest.getInstance("MD5").digest(this.toByteArray(Charsets.UTF_8))\n // transform to human readable MD5 String\n val hashString = String.format("%032x", BigInteger(1, hashBytes))\n // truncate MD5 String\n val truncatedHashString = hashString.take(truncateLength)\n // return id\n return truncatedHashString\n}\n\n//...\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n // ...\n // Hash Table Response object by id\n val responseByID = mutableMapOf()\n\n fun getIdentifier(url: String, truncateLength: Int = 6): String {\n val id = url.encodeToID()\n\n val retrievedResponse = responseByID[id]\n if (retrievedResponse?.originalURL != url) {\n // collision spotted !\n return getIdentifier(url, truncateLength + 1)\n }\n\n return id\n }\n\n routing {\n post("/api/v1/encode") {\n // Deserialize JSON body to Request object\n val request = call.receive()\n\n // find the Response object if it already exists\n val id = getID(request.url)\n val retrievedResponse = responseByID[id]\n if (retrievedResponse != null) {\n // cache hit\n log.debug("cache hit $retrievedResponse")\n return@post call.respond(retrievedResponse)\n }\n\n // cache miss\n val response = request.toResponse()\n responseByID[id] = response\n log.debug("cache miss $response")\n\n // Serialize Response object to JSON body\n call.respond(response)\n }\n }\n}\n')),Object(o.b)("h2",{id:"url-decoder"},"URL Decoder"),Object(o.b)("p",null,"Decoding the URL is the process of returning the original URL from the short URL. This is the reverse operation made by the URL Encoder"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),"val shortURL = getShortURL(request.url)\nval retrievedResponse = responseByID[shortURL]\nretrievedResponse?.originalURL // return original URL or null\n")),Object(o.b)("h2",{id:"redirect"},"Redirect"),Object(o.b)("p",null,"When a user clicks on a short URL, the user is redirected to the final URL. HTTP protocol allows to do this naturally by returning a 302 status code and a redirection URL."),Object(o.b)("p",null,"With Ktor the redirection is as simple as calling a method with the final URL as a parameter."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'call.respondRedirect("https://www.qovery.com")\n')),Object(o.b)("p",null,"What we expect is that when the user visits ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"http://localhost:8080/fbc951"}),"http://localhost:8080/fbc951")," he is redirected to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com"}),"https://www.qovery.com"),". If the URL is incorrect then redirect to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.google.com"}),"https://www.google.com")),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n // ...\n routing {\n get("/{id}") {\n val id = call.parameters["id"]\n val retrievedResponse = id?.let { responseByID[it] }\n\n if (id.isNullOrBlank() || retrievedResponse == null) {\n return@get call.respondRedirect("https://www.google.com")\n }\n\n log.debug("redirect to: $retrievedResponse")\n call.respondRedirect(retrievedResponse.originalURL)\n }\n // ...\n }\n}\n')),Object(o.b)("h2",{id:"stats-clicks-over-time"},"Stats: clicks over time"),Object(o.b)("p",null,"Something that is really useful on products like bit.ly is the stats provided (click over time, referrers, country of visitors). Here is how to store click over time and make them available through the API"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// added\ndata class Stat(val clicksOverTime: MutableList = mutableListOf())\n\n// Response object (modified with Stat)\ndata class Response(val originalURL: String, private val id: String, val stat: Stat = Stat()) {\n val shortURL: String = "http://localhost:8080/$id"\n}\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n install(ContentNegotiation) {\n jackson {\n // ...\n // add this line to return Date object as ISO8601 format\n disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)\n }\n }\n // ...\n routing {\n // ...\n get("/api/v1/url/{id}/stat") {\n val id = call.parameters["id"]\n val retrievedResponse = id?.let { responseByID[it] }\n\n if (id.isNullOrBlank() || retrievedResponse == null) {\n return@get call.respond(HttpStatusCode.NoContent)\n }\n\n call.respond(retrievedResponse.stat)\n }\n // ...\n }\n}\n')),Object(o.b)("h2",{id:"try-the-api"},"Try the API"),Object(o.b)("p",null,"Run the application"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ ./gradlew run\n//...\n2020-03-12 09:28:08.150 [main] INFO Application - No ktor.deployment.watch patterns specified, automatic reload is not active\n2020-03-12 09:28:08.606 [main] INFO Application - Responding at http://0.0.0.0:8080\n")),Object(o.b)("p",null,"Then execute the commands"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'# generate a short URL\n$ curl -X POST -d \'{"url": "https://www.qovery.com"}\' -H "Content-type: application/json" "http://localhost:8080/api/v1/encode"\n{\n "original_url": "https://www.qovery.com",\n "stat": {\n "clicks_over_time": []\n },\n "short_url": "http://localhost:8080/fbc951"\n}\n\n# generate 4 fake clicks\n$ curl -X GET \'http://localhost:8080/fbc951\'\n$ curl -X GET \'http://localhost:8080/fbc951\'\n$ curl -X GET \'http://localhost:8080/fbc951\'\n$ curl -X GET \'http://localhost:8080/fbc951\'\n\n# show stat\n$ curl -X GET \'http://localhost:8080/api/v1/url/fbc951/stat\'\n{\n "clicks_over_time": [\n "2020-03-11T21:10:52.354+0000",\n "2020-03-11T21:10:54.093+0000",\n "2020-03-11T21:12:34.987+0000",\n "2020-03-11T21:12:37.223+0000"\n ]\n}\n')),Object(o.b)("h2",{id:"connect-to-a-postgresql-database-with-exposed"},"Connect to a PostgreSQL database with Exposed"),Object(o.b)("p",null,"By storing the data in memory, we lose all the data every time the application restart. Which is problematic for running in production. To make the data persistent we will store it in a PostgreSQL database. We will have to add 1 new dependency - ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/JetBrains/Exposed"}),"Exposed"),". Exposed (with ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/brettwooldridge/HikariCP"}),"Hikari Connection Pool"),") is a lightweight SQL library on top of JDBC driver for Kotlin. With exposed it is possible to access databases in two flavours: typesafe SQL wrapping DSL and lightweight Data Access Objects (DAO)."),Object(o.b)("p",null,"Add the dependencies to your build.gradle (or POM.xml)"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'repositories {\n jcenter()\n}\n\ndependencies {\n // Connection Pool and PostgreSQL driver\n implementation("com.zaxxer:HikariCP:3.4.2")\n implementation("org.postgresql:postgresql:42.2.11")\n\n // Exposed\n implementation("org.jetbrains.exposed:exposed-core:0.22.1")\n implementation("org.jetbrains.exposed:exposed-dao:0.22.1")\n implementation("org.jetbrains.exposed:exposed-jdbc:0.22.1")\n implementation("org.jetbrains.exposed:exposed-java-time:0.22.1")\n}\n')),Object(o.b)("p",null,"We need to have 2 distincts tables, one containing all the final URLs with their correspond identifier"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'object ResponseTable : Table("response") {\n val id = varchar("id", 32)\n val originalURL = varchar("original_url", 2048)\n override val primaryKey: PrimaryKey = PrimaryKey(id)\n}\n')),Object(o.b)("p",null,"And a second one with all the clicking points"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'object ClickOverTimeTable : Table("click_over_time") {\n val id = integer("id").autoIncrement()\n val clickDate = datetime("click_date")\n val response = reference("response_id", onDelete = ReferenceOption.CASCADE, refColumn = ResponseTable.id)\n override val primaryKey: PrimaryKey = PrimaryKey(id)\n}\n')),Object(o.b)("p",null,"We need to create the tables as defined above programmatically"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'fun initDatabase() {\n val config = HikariConfig().apply {\n jdbcUrl = "jdbc:postgresql://127.0.0.1:5432/exposed"\n username = "exposed"\n password = "exposed"\n driverClassName = "org.postgresql.Driver"\n }\n\n Database.connect(HikariDataSource(config))\n\n transaction {\n // create tables if they do not exist\n SchemaUtils.createMissingTablesAndColumns(RequestTable, ClickOverTimeTable)\n }\n}\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n initDatabase()\n // ...\n}\n')),Object(o.b)("p",null,"We have to replace the Hash Table used to store the data by the PostgreSQL database (see the final code ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/ktor-url-shortener/blob/with_postgresql/src/Application.kt"}),"here"),")"),Object(o.b)("h2",{id:"deploy-in-the-cloud-with-qovery"},"Deploy in the Cloud with Qovery"),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com"}),"Qovery")," is going to help us to deploy the final application in the Cloud without the need to configure the CI/CD, network, security, load balancing, database and all the DevOps tasks"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"Qovery is a deployment platform that helps all developers to deploy their applications in the Cloud in just a few seconds")),Object(o.b)(u.a,{name:"tutorial",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Your code need to be hosted on Github/Gitlab/Bitbucket"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://ktor.io/quickstart/quickstart/docker.html"}),"Package your Ktor application to build and run it on Docker")))),Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"web",placeholder:"Select your interface",select:!1,size:null,values:[{group:"Interfaces",label:"Web",value:"web"},{group:"Interfaces",label:"CLI",value:"cli"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"web",mdxType:"TabItem"},Object(o.b)("li",null,Object(o.b)("p",null,"Sign in to the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web interface"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("a",{href:"https://onboarding.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.jpg",alt:"Qovery Sign-up page"}))))),Object(o.b)(b.a,{value:"cli",mdxType:"TabItem"},Object(o.b)("li",null,Object(o.b)("h3",{id:"install-qovery-cli"},"Install Qovery CLI"),Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"linux",placeholder:"Select your OS",select:!1,size:null,values:[{group:"Platforms",label:"Linux",value:"linux"},{group:"Platforms",label:"MacOS",value:"macos"},{group:"Platforms",label:"Windows",value:"windows"},{group:"Platforms",label:"Docker",value:"docker"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"universal",values:[{label:"*nix",value:"universal"},{label:"Arch Linux",value:"arch"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"universal",mdxType:"TabItem"},Object(o.b)("p",null,"To download and install Qovery CLI on any Linux distribution:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(b.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(b.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Linux manually by downloading the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(o.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(o.b)(b.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"homebrew",values:[{label:"Homebrew",value:"homebrew"},{label:"Script",value:"script"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"homebrew",mdxType:"TabItem"},Object(o.b)("p",null,"The common solution to install a command line binary on the MacOS is to use ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery brew repository\n$ brew tap Qovery/qovery-cli\n\n# Install the CLI\n$ brew install qovery-cli\n"))),Object(o.b)(b.a,{value:"script",mdxType:"TabItem"},Object(o.b)("p",null,"To download and install Qovery CLI from the command line:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(b.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Mac OS manually by downloading the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(o.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(o.b)(b.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"scoop",mdxType:"TabItem"},Object(o.b)("p",null,"The classic way to install binaries on Windows is to use ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery bucket\n$ scoop bucket add qovery https://github.com/Qovery/scoop-qovery-cli\n\n# Install the CLI\n$ scoop install qovery-cli\n"))),Object(o.b)(b.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Windows manually by downloading the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to\n",Object(o.b)("inlineCode",{parentName:"p"},"C:\\Windows"),".")))),Object(o.b)(b.a,{value:"docker",mdxType:"TabItem"},Object(o.b)("p",null,"Install Docker on your local machine and run the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Pull and Run the latest Qovery CLI\n$ docker run ghcr.io/qovery/qovery-cli:latest help\n")),Object(o.b)("p",null,"Change ",Object(o.b)("inlineCode",{parentName:"p"},"latest")," by the version you want to use. For example, to use the version 0.58.4, run:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ docker run ghcr.io/qovery/qovery-cli:0.58.4 help\n")),Object(o.b)("p",null,"Note: ",Object(o.b)("inlineCode",{parentName:"p"},"ghcr.io")," is the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/pkgs/container/qovery-cli"}),"GitHub Container Registry"),".")))),Object(o.b)("li",null,Object(o.b)("h3",{id:"sign-up"},"Sign up"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using an environment without access to GUI or a browser, you can use headless authentication instead:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth --headless\n"))),Object(o.b)("p",null,"Your browser window with sign-in options will open."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/qovery_signup.svg",alt:"Qovery Sign-up page"})),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/apps/qovery/installations/new"}),"Click here")," to authorize Qovery to clone and build your applications."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/github_signup.svg",alt:"Connect Github"})),Object(o.b)("p",null,"Congratulations, you are logged-in.")))),Object(o.b)("h3",{id:"create-an-application"},"Create an application"),Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h3",{id:"create-a-new-project"},"Create a new project"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/heroku/heroku-2.png",alt:"Migrate from Heroku"}))),Object(o.b)("li",null,Object(o.b)("h3",{id:"create-a-new-environment"},"Create a new environment"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/heroku/heroku-3.png",alt:"Migrate from Heroku"}))),Object(o.b)("li",null,Object(o.b)("h3",{id:"create-a-new-application"},"Create a new application"),Object(o.b)("p",null,"To follow the guide, ",Object(o.b)("a",{href:"https://github.com/evoxmusic/ktor-url-shortener.git"},"you can fork and use our repository")),Object(o.b)("p",null,"Use the forked repository (and branch ",Object(o.b)("strong",{parentName:"p"},"master"),") while creating the application in the repository field:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/rust/rust.png",alt:"Migrate from Heroku"}))),Object(o.b)("li",null,Object(o.b)("p",null,"After the application is created: "),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate application settings"),Object(o.b)("li",{parentName:"ul"},"Select ",Object(o.b)("strong",{parentName:"li"},"Port")),Object(o.b)("li",{parentName:"ul"},"Add port 8080")),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros-1.png",alt:"Microservices"})),Object(o.b)("p",null,"This will expose your application and make accessible in the public internet.")))),Object(o.b)("h3",{id:"deploy-a-database"},"Deploy a database"),Object(o.b)("p",null,"Create and deploy a new database."),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},"Name the new database **my-pql-db** to follow the guide flawlessly"),Object(o.b)("p",null,"To learn how to do it, you can ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"follow this guide"),"."),Object(o.b)("h3",{id:"connect-to-postgresql"},"Connect to PostgreSQL"),Object(o.b)("p",null,"Qovery add dynamically all required environment variables to connect to the database at the runtime of the container."),Object(o.b)("p",null,"You can list them all in ",Object(o.b)("strong",{parentName:"p"},"Environment Variables")," ",Object(o.b)("strong",{parentName:"p"},"Secrets")," section in your application overview, as described in ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/managing-environment-variables/"}),"envs guide"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/db-envs.png",alt:"DB Secrets"})),Object(o.b)("p",null,"To use them:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'fun initDatabase() {\n val config = HikariConfig().apply {\n jdbcUrl = "jdbc:${System.getenv("QOVERY_DATABASE_MY_PQL_DB_CONNECTION_URI_WITHOUT_CREDENTIALS")}"\n username = System.getenv("QOVERY_DATABASE_MY_PQL_DB_USERNAME")\n password = System.getenv("QOVERY_DATABASE_MY_PQL_DB_PASSWORD")\n driverClassName = "org.postgresql.Driver"\n }\n\n Database.connect(HikariDataSource(config))\n\n transaction {\n // create tables if they do not exist\n SchemaUtils.createMissingTablesAndColumns(RequestTable, ClickOverTimeTable)\n }\n}\n')),Object(o.b)("h3",{id:"deploy"},"Deploy"),Object(o.b)("p",null,"To deploy your application and database, click ",Object(o.b)("strong",{parentName:"p"},"Action")," and ",Object(o.b)("strong",{parentName:"p"},"Deploy")," button in your environments list view:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deploy-env.png",alt:"Kotlin URL Shortener"})),Object(o.b)("p",null,"To get public URL to the application, open application details and click on ",Object(o.b)("strong",{parentName:"p"},"Action")," ",Object(o.b)("strong",{parentName:"p"},"Open"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deploy-env-1.png",alt:"Kotlin URL Shortener"})),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/open-app.png",alt:"Kotlin URL Shortener"})),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"We have seen that creating an URL shortener API with Ktor and Kotlin is extremely simple. Connecting the application to PostgreSQL is very easy with the Exposed library. In just a few lines of code, the service is fully functional and can be deployed in production very quickly with the help of Qovery. In the next part, we will see how to create a web interface connecting to this API to convert our URLs without using the curl command."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Part 2"),": bind a web interface to the API - ","[link coming soon]"),Object(o.b)(l.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}g.isMDXComponent=!0},421:function(e,t,n){"use strict";n(423);var a=n(0),r=n.n(a),o=n(420),i=n.n(o);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,o=e.icon,l=e.type,s=null;switch(l){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return r.a.createElement("div",{className:i()(n,"alert","alert--"+l,{"alert--fill":a,"alert--icon":!1!==o}),role:"alert"},!1!==o&&r.a.createElement("i",{className:i()("feather","icon-"+(o||s))}),t)}},425:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var a=n(0),r=n.n(a),o=n(421);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(430),s=n(20),c=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,b=n||s,u=Object(l.a)(b),p=Object(r.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var n,a;d&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:b})):o.a.createElement("a",Object(a.a)({},e,{href:b}))}},429:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(427),i=n(420),l=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,s=e.rightIcon,c=e.size,b=e.target,u=e.to,p=l()("jump-to","jump-to--"+c,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return b?r.a.createElement("a",{href:u,target:b,className:p},d):r.a.createElement(o.a,{to:u,className:p},d)}},430:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},c="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),b=Object(a.useState)(null),u=b[0],p=b[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:c,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},434:function(e,t,n){"use strict";var a=n(1),r=(n(439),n(436),n(52),n(29),n(22),n(21),n(0)),o=n.n(r),i=n(446),l=n(420),s=n.n(l),c=n(428),b=n.n(c),u=n(445),p=37,d=39;function h(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,r=e.className,i=e.handleKeydown,l=e.style,c=e.values,b=e.selectedValue,u=e.tabRefs;return o.a.createElement("div",{className:n?"tabs--centered":null},o.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:s()("tabs",r,{"tabs--block":t}),style:l},c.map((function(e){var t=e.value,n=e.label;return o.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:s()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return i(u,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function m(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,r=e.size,l=e.values,s=l;if(s[0].group){var c=_.groupBy(s,"group");s=Object.keys(c).map((function(e){return{label:e,options:c[e]}}))}return o.a.createElement(i.a,{className:"react-select-container react-select--"+r,classNamePrefix:"react-select",options:s,isClearable:n,placeholder:t,value:l.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,i=e.groupId,l=e.label,s=e.placeholder,c=e.select,g=e.size,v=(e.style,e.values),j=e.urlKey,O=Object(u.a)(),f=O.tabGroupChoices,y=O.setTabGroupChoices,w=Object(r.useState)(n),N=w[0],k=w[1];if(null!=i){var T=f[i];null!=T&&T!==N&&k(T)}var R=function(e){k(e),null!=i&&y(i,e)},S=[],I=function(e,t,n){switch(n.keyCode){case d:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(r.useEffect)((function(){if("undefined"!=typeof window&&window.location&&j){var e=b.a.parse(window.location.search);e[j]&&k(e[j])}}),[]),o.a.createElement(o.a.Fragment,null,o.a.createElement("div",{className:"margin-bottom--"+(g||"md")},l&&o.a.createElement("div",{className:"margin-vert--sm"},l),v.length>1&&(c?o.a.createElement(m,Object(a.a)({changeSelectedValue:R,handleKeydown:I,placeholder:s,selectedValue:N,size:g,tabRefs:S},e)):o.a.createElement(h,Object(a.a)({changeSelectedValue:R,handleKeydown:I,selectedValue:N,tabRefs:S},e)))),r.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},441:function(e,t,n){"use strict";var a=n(0),r=n.n(a);t.a=function(e){return r.a.createElement(r.a.Fragment,null,e.children)}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[256],{408:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return p})),n.d(t,"metadata",(function(){return d})),n.d(t,"rightToc",(function(){return h})),n.d(t,"default",(function(){return g}));var a=n(1),r=n(9),o=(n(0),n(425)),i=n(424),l=n(431),s=n(434),c=n(437),b=n(444),u=n(429),p={last_modified_on:"2023-04-23",$schema:"/.meta/.schemas/guides.json",title:"URL Shortener API with Kotlin (Part 1/2)",description:"Create a URL shortener API with Kotlin, the micro-framework Ktor and PostgreSQL",author_github:"https://github.com/evoxmusic",tags:["type: tutorial","language: kotlin","database: postgresql"],hide_pagination:!0},d={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"URL Shortener API with Kotlin (Part 1/2)",description:"Create a URL shortener API with Kotlin, the micro-framework Ktor and PostgreSQL",permalink:"/guides/tutorial/url-shortener-api-with-kotlin",readingTime:"14 min read",source:"@site/guides/tutorial/url-shortener-api-with-kotlin.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"language: kotlin",permalink:"/guides/tags/language-kotlin"},{label:"database: postgresql",permalink:"/guides/tags/database-postgresql"}],title:"URL Shortener API with Kotlin (Part 1/2)",truncated:!1,prevItem:{title:"Terraform",permalink:"/guides/advanced/terraform"},nextItem:{title:"Use an API gateway in front of multiple services",permalink:"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services"}},h=[{value:"Introduction",id:"introduction",children:[]},{value:"What is a URL shortener?",id:"what-is-a-url-shortener",children:[]},{value:"Ktor principles",id:"ktor-principles",children:[{value:"Kotlin",id:"kotlin",children:[]},{value:"Functional programming",id:"functional-programming",children:[]},{value:"Asynchronous",id:"asynchronous",children:[]}]},{value:"HTTP Server",id:"http-server",children:[]},{value:"URL Encoder",id:"url-encoder",children:[{value:"Handle identifier collision",id:"handle-identifier-collision",children:[]}]},{value:"URL Decoder",id:"url-decoder",children:[]},{value:"Redirect",id:"redirect",children:[]},{value:"Stats: clicks over time",id:"stats-clicks-over-time",children:[]},{value:"Try the API",id:"try-the-api",children:[]},{value:"Connect to a PostgreSQL database with Exposed",id:"connect-to-a-postgresql-database-with-exposed",children:[]},{value:"Deploy in the Cloud with Qovery",id:"deploy-in-the-cloud-with-qovery",children:[{value:"Install Qovery CLI",id:"install-qovery-cli",children:[]},{value:"Sign up",id:"sign-up",children:[]},{value:"Create an application",id:"create-an-application",children:[]},{value:"Create a new project",id:"create-a-new-project",children:[]},{value:"Create a new environment",id:"create-a-new-environment",children:[]},{value:"Create a new application",id:"create-a-new-application",children:[]},{value:"Deploy a database",id:"deploy-a-database",children:[]},{value:"Connect to PostgreSQL",id:"connect-to-postgresql",children:[]},{value:"Deploy",id:"deploy",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],m={rightToc:h};function g(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},m,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"The source code for this post can be found on this ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/ktor-url-shortener"}),"github repo")),Object(o.b)("h2",{id:"introduction"},"Introduction"),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://ktor.io/"}),"Ktor")," is a brand new micro-framework created by the Jetbrains team, and running over the JVM. Jetbrains are the authors of ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://kotlinlang.org/"}),"Kotlin")," - which is now the official programming language for Android, and one of the most popular programming language on the JVM. Kotlin is gaining popularity on server-side and multi-platform application development."),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"Ktor is a framework for building asynchronous servers and clients in connected systems using the powerful Kotlin programming language.")),Object(o.b)("p",null,"In this article, you will learn:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"How to design a simple URL shortener."),Object(o.b)("li",{parentName:"ul"},"How to use the Ktor micro-framework with Kotlin"),Object(o.b)("li",{parentName:"ul"},"How to deploy a Ktor application")),Object(o.b)("p",null,"I have +4 years of experience using Spring, and I wanted to give a try to Ktor, which seems promising. Creating a URL shortener is an excellent way to start."),Object(o.b)("h2",{id:"what-is-a-url-shortener"},"What is a URL shortener?"),Object(o.b)("p",null,"A URL shortener is a simple tool that takes a long URL and turns it into a very short one"),Object(o.b)("p",null,Object(o.b)("img",Object(a.a)({parentName:"p"},{src:"https://uploads-ssl.webflow.com/5de176c0d41c9b4a1dbbb0aa/5e655859bc2ae5c7371efa36_urlshortener%20image.png",alt:"Flow of URL shortening - from original URL to short URL"}))),Object(o.b)("p",null,"It is commonly used for 3 reasons:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Tracking clicks"),Object(o.b)("li",{parentName:"ul"},"Make URL much more concise."),Object(o.b)("li",{parentName:"ul"},"Hide original URL")),Object(o.b)("p",null,"One famous freemium provider is bit.ly (see ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://uploads-ssl.webflow.com/5de176c0d41c9b4a1dbbb0aa/5e655a34bc2ae5452b1f124b_bitly.gif"}),"here"),")"),Object(o.b)("p",null,"In this article we will make a basic bit.ly like URL shortener. Let\u2019s go"),Object(o.b)("h2",{id:"ktor-principles"},"Ktor principles"),Object(o.b)("p",null,"Before starting I want to introduce the 3 main principles of Ktor."),Object(o.b)("h3",{id:"kotlin"},"Kotlin"),Object(o.b)("p",null,"Kotlin is the language used to develop on Ktor. It is an object-oriented and functional language. It is very stable and runs on the JVM. Kotlin is 100% interoperable with Java and allows you to benefit from its ecosystem (libraries, build system, etc.)."),Object(o.b)("h3",{id:"functional-programming"},"Functional programming"),Object(o.b)("p",null,"Ktor leverages the power of Kotlin and has a very functional approach. When writing code, everything seems obvious. It's very similar to what you can see on NodeJS. For me, coming from the Spring world, I find it very efficient to read and use."),Object(o.b)("h3",{id:"asynchronous"},"Asynchronous"),Object(o.b)("p",null,"Kotlin provides asynchronous code execution, thanks to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://kotlinlang.org/docs/reference/coroutines-overview.html"}),"coroutines"),". Ktor exploits this feature to its full potential, and even if you have the impression that you are writing code in a blocking manner, this is not the case. Ktor makes your life easier."),Object(o.b)("h2",{id:"http-server"},"HTTP Server"),Object(o.b)("p",null,"Here is a complete and simple example of how to expose an HTTP server (",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"http://localhost:8080"}),"http://localhost:8080"),") with Ktor."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'fun main(args: Array): Unit = io.ktor.server.netty.EngineMain.main(args)\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n routing {\n get("/") {\n call.respondText("Hello World", contentType = ContentType.Text.Plain)\n }\n }\n}\n')),Object(o.b)("h2",{id:"url-encoder"},"URL Encoder"),Object(o.b)("p",null,"The URL encoder will translate an incoming address into a smaller URL. The idea is to provide an ID that will identify the final URL. Using a hash function is perfect for this operation. However, the operation is non-reversible, meaning you can\u2019t retrieve the final URL by the generated identifier."),Object(o.b)("p",null,"Function to transform a long URL into a shorter URL"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// String extension\nfun String.encodeToID(): String {\n // hash String with MD5\n val hashBytes = MessageDigest.getInstance("MD5").digest(this.toByteArray(Charsets.UTF_8))\n // transform to human readable MD5 String\n val hashString = String.format("%032x", BigInteger(1, hashBytes))\n // truncate MD5 String\n val truncatedHashString = hashString.take(6)\n // return id\n return truncatedHashString\n}\n')),Object(o.b)("p",null,"We expose the function through the REST API"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// Request object\ndata class Request(val url: String) {\n fun toResponse(): Response = Response(url, url.encodeToID())\n}\n\n// Response object\ndata class Response(val originalURL: String, private val id: String) {\n val shortURL: String = "http://localhost:8080/$id"\n}\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n install(ContentNegotiation) {\n jackson {\n enable(SerializationFeature.INDENT_OUTPUT)\n propertyNamingStrategy = PropertyNamingStrategy.SNAKE_CASE\n }\n }\n\n // Hash Table Response object by ID\n val responseByID = mutableMapOf()\n\n routing {\n post("/api/v1/encode") {\n // Deserialize JSON body to Request object\n val request = call.receive()\n\n // find the Response object if it already exists\n val retrievedResponse = responseByID[request.url.encodeToID()]\n if (retrievedResponse != null) {\n // cache hit\n log.debug("cache hit $retrievedResponse")\n return@post call.respond(retrievedResponse)\n }\n\n // cache miss\n val response = request.toResponse()\n responseByID[request.url.encodeToID()] = response\n log.debug("cache miss $response")\n\n // Serialize Response object to JSON body\n call.respond(response)\n }\n }\n}\n')),Object(o.b)("h3",{id:"handle-identifier-collision"},"Handle identifier collision"),Object(o.b)("p",null,"Using a hash function makes no guarantee that it is not already being used. If it is in use, then you need to change it to another one. Note: even if the probability to have a collision is very low, you should handle this case."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// String extension (function signature has changed)\nfun String.encodeToID(truncateLength: Int = 6): String {\n // hash String with MD5\n val hashBytes = MessageDigest.getInstance("MD5").digest(this.toByteArray(Charsets.UTF_8))\n // transform to human readable MD5 String\n val hashString = String.format("%032x", BigInteger(1, hashBytes))\n // truncate MD5 String\n val truncatedHashString = hashString.take(truncateLength)\n // return id\n return truncatedHashString\n}\n\n//...\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n // ...\n // Hash Table Response object by id\n val responseByID = mutableMapOf()\n\n fun getIdentifier(url: String, truncateLength: Int = 6): String {\n val id = url.encodeToID()\n\n val retrievedResponse = responseByID[id]\n if (retrievedResponse?.originalURL != url) {\n // collision spotted !\n return getIdentifier(url, truncateLength + 1)\n }\n\n return id\n }\n\n routing {\n post("/api/v1/encode") {\n // Deserialize JSON body to Request object\n val request = call.receive()\n\n // find the Response object if it already exists\n val id = getID(request.url)\n val retrievedResponse = responseByID[id]\n if (retrievedResponse != null) {\n // cache hit\n log.debug("cache hit $retrievedResponse")\n return@post call.respond(retrievedResponse)\n }\n\n // cache miss\n val response = request.toResponse()\n responseByID[id] = response\n log.debug("cache miss $response")\n\n // Serialize Response object to JSON body\n call.respond(response)\n }\n }\n}\n')),Object(o.b)("h2",{id:"url-decoder"},"URL Decoder"),Object(o.b)("p",null,"Decoding the URL is the process of returning the original URL from the short URL. This is the reverse operation made by the URL Encoder"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),"val shortURL = getShortURL(request.url)\nval retrievedResponse = responseByID[shortURL]\nretrievedResponse?.originalURL // return original URL or null\n")),Object(o.b)("h2",{id:"redirect"},"Redirect"),Object(o.b)("p",null,"When a user clicks on a short URL, the user is redirected to the final URL. HTTP protocol allows to do this naturally by returning a 302 status code and a redirection URL."),Object(o.b)("p",null,"With Ktor the redirection is as simple as calling a method with the final URL as a parameter."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'call.respondRedirect("https://www.qovery.com")\n')),Object(o.b)("p",null,"What we expect is that when the user visits ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"http://localhost:8080/fbc951"}),"http://localhost:8080/fbc951")," he is redirected to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com"}),"https://www.qovery.com"),". If the URL is incorrect then redirect to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.google.com"}),"https://www.google.com")),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n // ...\n routing {\n get("/{id}") {\n val id = call.parameters["id"]\n val retrievedResponse = id?.let { responseByID[it] }\n\n if (id.isNullOrBlank() || retrievedResponse == null) {\n return@get call.respondRedirect("https://www.google.com")\n }\n\n log.debug("redirect to: $retrievedResponse")\n call.respondRedirect(retrievedResponse.originalURL)\n }\n // ...\n }\n}\n')),Object(o.b)("h2",{id:"stats-clicks-over-time"},"Stats: clicks over time"),Object(o.b)("p",null,"Something that is really useful on products like bit.ly is the stats provided (click over time, referrers, country of visitors). Here is how to store click over time and make them available through the API"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'// added\ndata class Stat(val clicksOverTime: MutableList = mutableListOf())\n\n// Response object (modified with Stat)\ndata class Response(val originalURL: String, private val id: String, val stat: Stat = Stat()) {\n val shortURL: String = "http://localhost:8080/$id"\n}\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n install(ContentNegotiation) {\n jackson {\n // ...\n // add this line to return Date object as ISO8601 format\n disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)\n }\n }\n // ...\n routing {\n // ...\n get("/api/v1/url/{id}/stat") {\n val id = call.parameters["id"]\n val retrievedResponse = id?.let { responseByID[it] }\n\n if (id.isNullOrBlank() || retrievedResponse == null) {\n return@get call.respond(HttpStatusCode.NoContent)\n }\n\n call.respond(retrievedResponse.stat)\n }\n // ...\n }\n}\n')),Object(o.b)("h2",{id:"try-the-api"},"Try the API"),Object(o.b)("p",null,"Run the application"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ ./gradlew run\n//...\n2020-03-12 09:28:08.150 [main] INFO Application - No ktor.deployment.watch patterns specified, automatic reload is not active\n2020-03-12 09:28:08.606 [main] INFO Application - Responding at http://0.0.0.0:8080\n")),Object(o.b)("p",null,"Then execute the commands"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'# generate a short URL\n$ curl -X POST -d \'{"url": "https://www.qovery.com"}\' -H "Content-type: application/json" "http://localhost:8080/api/v1/encode"\n{\n "original_url": "https://www.qovery.com",\n "stat": {\n "clicks_over_time": []\n },\n "short_url": "http://localhost:8080/fbc951"\n}\n\n# generate 4 fake clicks\n$ curl -X GET \'http://localhost:8080/fbc951\'\n$ curl -X GET \'http://localhost:8080/fbc951\'\n$ curl -X GET \'http://localhost:8080/fbc951\'\n$ curl -X GET \'http://localhost:8080/fbc951\'\n\n# show stat\n$ curl -X GET \'http://localhost:8080/api/v1/url/fbc951/stat\'\n{\n "clicks_over_time": [\n "2020-03-11T21:10:52.354+0000",\n "2020-03-11T21:10:54.093+0000",\n "2020-03-11T21:12:34.987+0000",\n "2020-03-11T21:12:37.223+0000"\n ]\n}\n')),Object(o.b)("h2",{id:"connect-to-a-postgresql-database-with-exposed"},"Connect to a PostgreSQL database with Exposed"),Object(o.b)("p",null,"By storing the data in memory, we lose all the data every time the application restart. Which is problematic for running in production. To make the data persistent we will store it in a PostgreSQL database. We will have to add 1 new dependency - ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/JetBrains/Exposed"}),"Exposed"),". Exposed (with ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/brettwooldridge/HikariCP"}),"Hikari Connection Pool"),") is a lightweight SQL library on top of JDBC driver for Kotlin. With exposed it is possible to access databases in two flavours: typesafe SQL wrapping DSL and lightweight Data Access Objects (DAO)."),Object(o.b)("p",null,"Add the dependencies to your build.gradle (or POM.xml)"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'repositories {\n jcenter()\n}\n\ndependencies {\n // Connection Pool and PostgreSQL driver\n implementation("com.zaxxer:HikariCP:3.4.2")\n implementation("org.postgresql:postgresql:42.2.11")\n\n // Exposed\n implementation("org.jetbrains.exposed:exposed-core:0.22.1")\n implementation("org.jetbrains.exposed:exposed-dao:0.22.1")\n implementation("org.jetbrains.exposed:exposed-jdbc:0.22.1")\n implementation("org.jetbrains.exposed:exposed-java-time:0.22.1")\n}\n')),Object(o.b)("p",null,"We need to have 2 distincts tables, one containing all the final URLs with their correspond identifier"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'object ResponseTable : Table("response") {\n val id = varchar("id", 32)\n val originalURL = varchar("original_url", 2048)\n override val primaryKey: PrimaryKey = PrimaryKey(id)\n}\n')),Object(o.b)("p",null,"And a second one with all the clicking points"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'object ClickOverTimeTable : Table("click_over_time") {\n val id = integer("id").autoIncrement()\n val clickDate = datetime("click_date")\n val response = reference("response_id", onDelete = ReferenceOption.CASCADE, refColumn = ResponseTable.id)\n override val primaryKey: PrimaryKey = PrimaryKey(id)\n}\n')),Object(o.b)("p",null,"We need to create the tables as defined above programmatically"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'fun initDatabase() {\n val config = HikariConfig().apply {\n jdbcUrl = "jdbc:postgresql://127.0.0.1:5432/exposed"\n username = "exposed"\n password = "exposed"\n driverClassName = "org.postgresql.Driver"\n }\n\n Database.connect(HikariDataSource(config))\n\n transaction {\n // create tables if they do not exist\n SchemaUtils.createMissingTablesAndColumns(RequestTable, ClickOverTimeTable)\n }\n}\n\n@kotlin.jvm.JvmOverloads\nfun Application.module(testing: Boolean = false) {\n initDatabase()\n // ...\n}\n')),Object(o.b)("p",null,"We have to replace the Hash Table used to store the data by the PostgreSQL database (see the final code ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/evoxmusic/ktor-url-shortener/blob/with_postgresql/src/Application.kt"}),"here"),")"),Object(o.b)("h2",{id:"deploy-in-the-cloud-with-qovery"},"Deploy in the Cloud with Qovery"),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com"}),"Qovery")," is going to help us to deploy the final application in the Cloud without the need to configure the CI/CD, network, security, load balancing, database and all the DevOps tasks"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"Qovery is a deployment platform that helps all developers to deploy their applications in the Cloud in just a few seconds")),Object(o.b)(u.a,{name:"tutorial",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Your code need to be hosted on Github/Gitlab/Bitbucket"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://ktor.io/quickstart/quickstart/docker.html"}),"Package your Ktor application to build and run it on Docker")))),Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"web",placeholder:"Select your interface",select:!1,size:null,values:[{group:"Interfaces",label:"Web",value:"web"},{group:"Interfaces",label:"CLI",value:"cli"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"web",mdxType:"TabItem"},Object(o.b)("li",null,Object(o.b)("p",null,"Sign in to the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Qovery web interface"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("a",{href:"https://onboarding.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.jpg",alt:"Qovery Sign-up page"}))))),Object(o.b)(b.a,{value:"cli",mdxType:"TabItem"},Object(o.b)("li",null,Object(o.b)("h3",{id:"install-qovery-cli"},"Install Qovery CLI"),Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"linux",placeholder:"Select your OS",select:!1,size:null,values:[{group:"Platforms",label:"Linux",value:"linux"},{group:"Platforms",label:"MacOS",value:"macos"},{group:"Platforms",label:"Windows",value:"windows"},{group:"Platforms",label:"Docker",value:"docker"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"universal",values:[{label:"*nix",value:"universal"},{label:"Arch Linux",value:"arch"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"universal",mdxType:"TabItem"},Object(o.b)("p",null,"To download and install Qovery CLI on any Linux distribution:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(b.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(b.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Linux manually by downloading the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(o.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(o.b)(b.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"homebrew",values:[{label:"Homebrew",value:"homebrew"},{label:"Script",value:"script"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"homebrew",mdxType:"TabItem"},Object(o.b)("p",null,"The common solution to install a command line binary on the MacOS is to use ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery brew repository\n$ brew tap Qovery/qovery-cli\n\n# Install the CLI\n$ brew install qovery-cli\n"))),Object(o.b)(b.a,{value:"script",mdxType:"TabItem"},Object(o.b)("p",null,"To download and install Qovery CLI from the command line:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(b.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Mac OS manually by downloading the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to a folder into your shell ",Object(o.b)("inlineCode",{parentName:"p"},"PATH"),".")))),Object(o.b)(b.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(c.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(b.a,{value:"scoop",mdxType:"TabItem"},Object(o.b)("p",null,"The classic way to install binaries on Windows is to use ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Add Qovery bucket\n$ scoop bucket add qovery https://github.com/Qovery/scoop-qovery-cli\n\n# Install the CLI\n$ scoop install qovery-cli\n"))),Object(o.b)(b.a,{value:"manual",mdxType:"TabItem"},Object(o.b)("p",null,"Install the Qovery CLI on Windows manually by downloading the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/releases"}),"latest release"),", and uncompress its content to\n",Object(o.b)("inlineCode",{parentName:"p"},"C:\\Windows"),".")))),Object(o.b)(b.a,{value:"docker",mdxType:"TabItem"},Object(o.b)("p",null,"Install Docker on your local machine and run the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Pull and Run the latest Qovery CLI\n$ docker run ghcr.io/qovery/qovery-cli:latest help\n")),Object(o.b)("p",null,"Change ",Object(o.b)("inlineCode",{parentName:"p"},"latest")," by the version you want to use. For example, to use the version 0.58.4, run:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ docker run ghcr.io/qovery/qovery-cli:0.58.4 help\n")),Object(o.b)("p",null,"Note: ",Object(o.b)("inlineCode",{parentName:"p"},"ghcr.io")," is the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/pkgs/container/qovery-cli"}),"GitHub Container Registry"),".")))),Object(o.b)("li",null,Object(o.b)("h3",{id:"sign-up"},"Sign up"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using an environment without access to GUI or a browser, you can use headless authentication instead:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth --headless\n"))),Object(o.b)("p",null,"Your browser window with sign-in options will open."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/qovery_signup.svg",alt:"Qovery Sign-up page"})),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/apps/qovery/installations/new"}),"Click here")," to authorize Qovery to clone and build your applications."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/github_signup.svg",alt:"Connect Github"})),Object(o.b)("p",null,"Congratulations, you are logged-in.")))),Object(o.b)("h3",{id:"create-an-application"},"Create an application"),Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h3",{id:"create-a-new-project"},"Create a new project"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/heroku/heroku-2.png",alt:"Migrate from Heroku"}))),Object(o.b)("li",null,Object(o.b)("h3",{id:"create-a-new-environment"},"Create a new environment"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/heroku/heroku-3.png",alt:"Migrate from Heroku"}))),Object(o.b)("li",null,Object(o.b)("h3",{id:"create-a-new-application"},"Create a new application"),Object(o.b)("p",null,"To follow the guide, ",Object(o.b)("a",{href:"https://github.com/evoxmusic/ktor-url-shortener.git"},"you can fork and use our repository")),Object(o.b)("p",null,"Use the forked repository (and branch ",Object(o.b)("strong",{parentName:"p"},"master"),") while creating the application in the repository field:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/rust/rust.png",alt:"Migrate from Heroku"}))),Object(o.b)("li",null,Object(o.b)("p",null,"After the application is created: "),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Navigate application settings"),Object(o.b)("li",{parentName:"ul"},"Select ",Object(o.b)("strong",{parentName:"li"},"Port")),Object(o.b)("li",{parentName:"ul"},"Add port 8080")),Object(o.b)("p",{align:"left"},Object(o.b)("img",{src:"/img/micro/micros-1.png",alt:"Microservices"})),Object(o.b)("p",null,"This will expose your application and make accessible in the public internet.")))),Object(o.b)("h3",{id:"deploy-a-database"},"Deploy a database"),Object(o.b)("p",null,"Create and deploy a new database."),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},"Name the new database **my-pql-db** to follow the guide flawlessly"),Object(o.b)("p",null,"To learn how to do it, you can ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/create-a-database/"}),"follow this guide"),"."),Object(o.b)("h3",{id:"connect-to-postgresql"},"Connect to PostgreSQL"),Object(o.b)("p",null,"Qovery add dynamically all required environment variables to connect to the database at the runtime of the container."),Object(o.b)("p",null,"You can list them all in ",Object(o.b)("strong",{parentName:"p"},"Environment Variables")," ",Object(o.b)("strong",{parentName:"p"},"Secrets")," section in your application overview, as described in ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/getting-started/managing-environment-variables/"}),"envs guide"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/db-envs.png",alt:"DB Secrets"})),Object(o.b)("p",null,"To use them:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-kotlin"}),'fun initDatabase() {\n val config = HikariConfig().apply {\n jdbcUrl = "jdbc:${System.getenv("QOVERY_DATABASE_MY_PQL_DB_CONNECTION_URI_WITHOUT_CREDENTIALS")}"\n username = System.getenv("QOVERY_DATABASE_MY_PQL_DB_USERNAME")\n password = System.getenv("QOVERY_DATABASE_MY_PQL_DB_PASSWORD")\n driverClassName = "org.postgresql.Driver"\n }\n\n Database.connect(HikariDataSource(config))\n\n transaction {\n // create tables if they do not exist\n SchemaUtils.createMissingTablesAndColumns(RequestTable, ClickOverTimeTable)\n }\n}\n')),Object(o.b)("h3",{id:"deploy"},"Deploy"),Object(o.b)("p",null,"To deploy your application and database, click ",Object(o.b)("strong",{parentName:"p"},"Action")," and ",Object(o.b)("strong",{parentName:"p"},"Deploy")," button in your environments list view:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deploy-env.png",alt:"Kotlin URL Shortener"})),Object(o.b)("p",null,"To get public URL to the application, open application details and click on ",Object(o.b)("strong",{parentName:"p"},"Action")," ",Object(o.b)("strong",{parentName:"p"},"Open"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deploy-env-1.png",alt:"Kotlin URL Shortener"})),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/open-app.png",alt:"Kotlin URL Shortener"})),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"We have seen that creating an URL shortener API with Ktor and Kotlin is extremely simple. Connecting the application to PostgreSQL is very easy with the Exposed library. In just a few lines of code, the service is fully functional and can be deployed in production very quickly with the help of Qovery. In the next part, we will see how to create a web interface connecting to this API to convert our URLs without using the curl command."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Part 2"),": bind a web interface to the API - ","[link coming soon]"),Object(o.b)(l.a,{to:"/guides/tutorial/",mdxType:"Jump"},"Tutorial"))}g.isMDXComponent=!0},424:function(e,t,n){"use strict";n(426);var a=n(0),r=n.n(a),o=n(423),i=n.n(o);n(132);t.a=function(e){var t=e.children,n=e.classNames,a=e.fill,o=e.icon,l=e.type,s=null;switch(l){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return r.a.createElement("div",{className:i()(n,"alert","alert--"+l,{"alert--fill":a,"alert--icon":!1!==o}),role:"alert"},!1!==o&&r.a.createElement("i",{className:i()("feather","icon-"+(o||s))}),t)}},428:function(e,t,n){var a=n(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||n(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var a=n(0),r=n.n(a),o=n(424);t.a=function(e){var t=e.children,n=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(432),s=n(20),c=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,b=n||s,u=Object(l.a)(b),p=Object(r.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?o.a.createElement(i.b,Object(a.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(b),p.current=!0)},innerRef:function(e){var n,a;d&&e&&u&&(n=e,a=function(){window.docusaurus.prefetch(b)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),a())}))}))).observe(n))},to:b})):o.a.createElement("a",Object(a.a)({},e,{href:b}))}},431:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(430),i=n(423),l=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,s=e.rightIcon,c=e.size,b=e.target,u=e.to,p=l()("jump-to","jump-to--"+c,n),d=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},i&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+i})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return b?r.a.createElement("a",{href:u,target:b,className:p},d):r.a.createElement(o.a,{to:u,className:p},d)}},432:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},434:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+l+" failed",body:"The tutorial on:\n\n"+l+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},c="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),b=Object(a.useState)(null),u=b[0],p=b[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:c,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},437:function(e,t,n){"use strict";var a=n(1),r=(n(442),n(439),n(52),n(29),n(22),n(21),n(0)),o=n.n(r),i=n(449),l=n(423),s=n.n(l),c=n(433),b=n.n(c),u=n(448),p=37,d=39;function h(e){var t=e.block,n=e.centered,a=e.changeSelectedValue,r=e.className,i=e.handleKeydown,l=e.style,c=e.values,b=e.selectedValue,u=e.tabRefs;return o.a.createElement("div",{className:n?"tabs--centered":null},o.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:s()("tabs",r,{"tabs--block":t}),style:l},c.map((function(e){var t=e.value,n=e.label;return o.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===t,className:s()("tab-item",{"tab-item--active":b===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return i(u,e.target,e)},onFocus:function(){return a(t)},onClick:function(){return a(t)}},n)}))))}function m(e){var t=e.placeholder,n=e.selectedValue,a=e.changeSelectedValue,r=e.size,l=e.values,s=l;if(s[0].group){var c=_.groupBy(s,"group");s=Object.keys(c).map((function(e){return{label:e,options:c[e]}}))}return o.a.createElement(i.a,{className:"react-select-container react-select--"+r,classNamePrefix:"react-select",options:s,isClearable:n,placeholder:t,value:l.find((function(e){return e.value==n})),onChange:function(e){return a(e?e.value:null)}})}t.a=function(e){e.block,e.centered;var t=e.children,n=e.defaultValue,i=e.groupId,l=e.label,s=e.placeholder,c=e.select,g=e.size,v=(e.style,e.values),j=e.urlKey,O=Object(u.a)(),f=O.tabGroupChoices,y=O.setTabGroupChoices,w=Object(r.useState)(n),N=w[0],k=w[1];if(null!=i){var T=f[i];null!=T&&T!==N&&k(T)}var R=function(e){k(e),null!=i&&y(i,e)},S=[],I=function(e,t,n){switch(n.keyCode){case d:!function(e,t){var n=e.indexOf(t)+1;e[n]?e[n].focus():e[0].focus()}(e,t);break;case p:!function(e,t){var n=e.indexOf(t)-1;e[n]?e[n].focus():e[e.length-1].focus()}(e,t)}};return Object(r.useEffect)((function(){if("undefined"!=typeof window&&window.location&&j){var e=b.a.parse(window.location.search);e[j]&&k(e[j])}}),[]),o.a.createElement(o.a.Fragment,null,o.a.createElement("div",{className:"margin-bottom--"+(g||"md")},l&&o.a.createElement("div",{className:"margin-vert--sm"},l),v.length>1&&(c?o.a.createElement(m,Object(a.a)({changeSelectedValue:R,handleKeydown:I,placeholder:s,selectedValue:N,size:g,tabRefs:S},e)):o.a.createElement(h,Object(a.a)({changeSelectedValue:R,handleKeydown:I,selectedValue:N,tabRefs:S},e)))),r.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},444:function(e,t,n){"use strict";var a=n(0),r=n.n(a);t.a=function(e){return r.a.createElement(r.a.Fragment,null,e.children)}}}]); \ No newline at end of file diff --git a/f756422c.634ffbc6.js b/f756422c.b9899556.js similarity index 94% rename from f756422c.634ffbc6.js rename to f756422c.b9899556.js index fa32600afb..8656f3ef6a 100644 --- a/f756422c.634ffbc6.js +++ b/f756422c.b9899556.js @@ -1,2 +1,2 @@ -/*! For license information please see f756422c.634ffbc6.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[254],{406:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return p})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return b}));var o=n(1),r=n(9),i=(n(0),n(422)),a=n(421),c=n(431),l={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Mono repository",description:"How to deploy applications using Monorepository with Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: guide","technology: qovery"]},p={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Mono repository",description:"How to deploy applications using Monorepository with Qovery",permalink:"/guides/advanced/monorepository",readingTime:"3 min read",source:"@site/guides/advanced/monorepository.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Mono repository",truncated:!1,prevItem:{title:"Monitoring",permalink:"/guides/advanced/monitoring"},nextItem:{title:"Preview Environments",permalink:"/guides/advanced/use-preview-environments"}},s=[{value:"Deploying multiple applications using one repository",id:"deploying-multiple-applications-using-one-repository",children:[{value:"First application",id:"first-application",children:[]},{value:"Second application",id:"second-application",children:[]}]},{value:"Deploying application with multiple configurations using one repository",id:"deploying-application-with-multiple-configurations-using-one-repository",children:[{value:"First application",id:"first-application-1",children:[]},{value:"Second application",id:"second-application-1",children:[]}]},{value:"Q&A",id:"qa",children:[]}],u={rightToc:s};function b(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(a.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"This guide is a bit outdated. We are working on a new version of it. Stay tuned!")),Object(i.b)("p",null,"Qovery provides a very simple way of working with ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://en.wikipedia.org/wiki/Monorepo"}),"monorepositories"),".\nYou can deploy multiple applications using the same git repository or deploy the same application in many different modes/configurations."),Object(i.b)("h2",{id:"deploying-multiple-applications-using-one-repository"},"Deploying multiple applications using one repository"),Object(i.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/getting-started/deploy-your-first-application/"}),"Create new applications")," or navigate to existing ones")),Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to application settings"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-6.png",alt:"Monorepository"}))),Object(i.b)("li",null,Object(i.b)("p",null,"To deploy multiple apps using one repository, set up the app to target your monorepo. Additionally, you need to set up the folder in which your application resides."),Object(i.b)("h3",{id:"first-application"},"First application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-1.png",alt:"Monorepository"})),Object(i.b)("h3",{id:"second-application"},"Second application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-2.png",alt:"Monorepository"})),Object(i.b)("p",null,"As you see in the examples above, we used one repository (",Object(i.b)("inlineCode",{parentName:"p"},"poc-factory/tweetifier"),") in two applications:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"timescale"),Object(i.b)("li",{parentName:"ul"},"core")),Object(i.b)("p",null,"All we need to do to deploy multiple applications using one repository is:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Select the application name"),Object(i.b)("li",{parentName:"ul"},"Select our repository"),Object(i.b)("li",{parentName:"ul"},"Select the application root folder")),Object(i.b)("p",null,"That's it. Using monorepositories with Qovery is that simple."),Object(i.b)("p",null,"Those applications may be a part of the same project or different projects; it's all up to you and your configuration."),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},"Each commit to the repository will make sure all applications affected will be redeployed and up-to-date.")))),Object(i.b)("h2",{id:"deploying-application-with-multiple-configurations-using-one-repository"},"Deploying application with multiple configurations using one repository"),Object(i.b)("p",null,"A special case of monorepository is a situation when one repository is used to deploy multiple applications with the same source code but different configurations or modes. Application behaviour depends on provided config, like environment variables and secrets."),Object(i.b)("p",null,"Qovery supports this case well. The steps do not differ much from the steps from the previous example:"),Object(i.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/getting-started/deploy-your-first-application/"}),"Create new applications")," or navigate to existing ones")),Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to application settings"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-6.png",alt:"Monorepository"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Configure application repositories:"),Object(i.b)("h3",{id:"first-application-1"},"First application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-3.png",alt:"Monorepository"})),Object(i.b)("h3",{id:"second-application-1"},"Second application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-4.png",alt:"Monorepository"}))),Object(i.b)("p",null,"As you see in the examples above, we used one repository (",Object(i.b)("inlineCode",{parentName:"p"},"poc-factory/tweetifier"),") in two applications:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"app-1"),Object(i.b)("li",{parentName:"ul"},"app-2")),Object(i.b)("br",null),Object(i.b)("p",null,"Those applications use the same application root path - ",Object(i.b)("inlineCode",{parentName:"p"},"/"),", so they can be build using the same source code. To adjust the behavior of applications to meet your needs, use ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"environment variables or secrets"),".\nIt allows you to run multiple applications using the same source code in different modes."),Object(i.b)("p",null,"You can set up secret or env variables in your application ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variables")," section:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-5.png",alt:"Monorepository"})))),Object(i.b)("h2",{id:"qa"},"Q&A"),Object(i.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}b.isMDXComponent=!0},420:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=r.a.createContext({}),s=function(e){var t=r.a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=s(e.components);return r.a.createElement(p.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(n),d=o,m=u["".concat(a,".").concat(d)]||u[d]||b[d]||i;return n?r.a.createElement(m,c({ref:t},p,{components:n})):r.a.createElement(m,c({ref:t},p))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,a[1]=c;for(var p=2;p1?arguments[1]:void 0,n),l=a>2?arguments[2]:void 0,p=void 0===l?n:r(l,n);p>c;)t[c++]=e;return t}},428:function(e,t,n){"use strict";var o=n(432),r=n(51);function i(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(r),i,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[i(t,e),"[",o,"]"].join(""):[i(t,e),"[",i(o,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return i(o,t);if(Array.isArray(r)){var a=[];return r.slice().forEach((function(e){void 0!==e&&a.push(n(o,e,a.length))})),a.join("&")}return i(o,t)+"="+i(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(420),n(428)),a=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},p="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(l),s=Object(o.useState)(null),u=s[0],b=s[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:p,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see f756422c.b9899556.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[257],{409:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return p})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return b}));var o=n(1),r=n(9),i=(n(0),n(425)),a=n(424),c=n(434),l={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Mono repository",description:"How to deploy applications using Monorepository with Qovery",author_github:"https://github.com/pjeziorowski",tags:["type: guide","technology: qovery"]},p={categories:[{name:"advanced",title:"Advanced",description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",permalink:"/guides/advanced"}],coverLabel:"Mono repository",description:"How to deploy applications using Monorepository with Qovery",permalink:"/guides/advanced/monorepository",readingTime:"3 min read",source:"@site/guides/advanced/monorepository.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Mono repository",truncated:!1,prevItem:{title:"Monitoring",permalink:"/guides/advanced/monitoring"},nextItem:{title:"Preview Environments",permalink:"/guides/advanced/use-preview-environments"}},s=[{value:"Deploying multiple applications using one repository",id:"deploying-multiple-applications-using-one-repository",children:[{value:"First application",id:"first-application",children:[]},{value:"Second application",id:"second-application",children:[]}]},{value:"Deploying application with multiple configurations using one repository",id:"deploying-application-with-multiple-configurations-using-one-repository",children:[{value:"First application",id:"first-application-1",children:[]},{value:"Second application",id:"second-application-1",children:[]}]},{value:"Q&A",id:"qa",children:[]}],u={rightToc:s};function b(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(a.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"This guide is a bit outdated. We are working on a new version of it. Stay tuned!")),Object(i.b)("p",null,"Qovery provides a very simple way of working with ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://en.wikipedia.org/wiki/Monorepo"}),"monorepositories"),".\nYou can deploy multiple applications using the same git repository or deploy the same application in many different modes/configurations."),Object(i.b)("h2",{id:"deploying-multiple-applications-using-one-repository"},"Deploying multiple applications using one repository"),Object(i.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/getting-started/deploy-your-first-application/"}),"Create new applications")," or navigate to existing ones")),Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to application settings"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-6.png",alt:"Monorepository"}))),Object(i.b)("li",null,Object(i.b)("p",null,"To deploy multiple apps using one repository, set up the app to target your monorepo. Additionally, you need to set up the folder in which your application resides."),Object(i.b)("h3",{id:"first-application"},"First application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-1.png",alt:"Monorepository"})),Object(i.b)("h3",{id:"second-application"},"Second application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-2.png",alt:"Monorepository"})),Object(i.b)("p",null,"As you see in the examples above, we used one repository (",Object(i.b)("inlineCode",{parentName:"p"},"poc-factory/tweetifier"),") in two applications:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"timescale"),Object(i.b)("li",{parentName:"ul"},"core")),Object(i.b)("p",null,"All we need to do to deploy multiple applications using one repository is:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Select the application name"),Object(i.b)("li",{parentName:"ul"},"Select our repository"),Object(i.b)("li",{parentName:"ul"},"Select the application root folder")),Object(i.b)("p",null,"That's it. Using monorepositories with Qovery is that simple."),Object(i.b)("p",null,"Those applications may be a part of the same project or different projects; it's all up to you and your configuration."),Object(i.b)(a.a,{type:"info",mdxType:"Alert"},"Each commit to the repository will make sure all applications affected will be redeployed and up-to-date.")))),Object(i.b)("h2",{id:"deploying-application-with-multiple-configurations-using-one-repository"},"Deploying application with multiple configurations using one repository"),Object(i.b)("p",null,"A special case of monorepository is a situation when one repository is used to deploy multiple applications with the same source code but different configurations or modes. Application behaviour depends on provided config, like environment variables and secrets."),Object(i.b)("p",null,"Qovery supports this case well. The steps do not differ much from the steps from the previous example:"),Object(i.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(i.b)("ol",null,Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Console"))),Object(i.b)("li",null,Object(i.b)("p",null,Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://hub.qovery.com/guides/getting-started/deploy-your-first-application/"}),"Create new applications")," or navigate to existing ones")),Object(i.b)("li",null,Object(i.b)("p",null,"Navigate to application settings"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-6.png",alt:"Monorepository"}))),Object(i.b)("li",null,Object(i.b)("p",null,"Configure application repositories:"),Object(i.b)("h3",{id:"first-application-1"},"First application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-3.png",alt:"Monorepository"})),Object(i.b)("h3",{id:"second-application-1"},"Second application"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-4.png",alt:"Monorepository"}))),Object(i.b)("p",null,"As you see in the examples above, we used one repository (",Object(i.b)("inlineCode",{parentName:"p"},"poc-factory/tweetifier"),") in two applications:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"app-1"),Object(i.b)("li",{parentName:"ul"},"app-2")),Object(i.b)("br",null),Object(i.b)("p",null,"Those applications use the same application root path - ",Object(i.b)("inlineCode",{parentName:"p"},"/"),", so they can be build using the same source code. To adjust the behavior of applications to meet your needs, use ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"environment variables or secrets"),".\nIt allows you to run multiple applications using the same source code in different modes."),Object(i.b)("p",null,"You can set up secret or env variables in your application ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variables")," section:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/monorepo/monorepo-5.png",alt:"Monorepository"})))),Object(i.b)("h2",{id:"qa"},"Q&A"),Object(i.b)("p",null,"Do you need more examples? Do you have any questions? Feel free to ask on our ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Community forum"),"."))}b.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=r.a.createContext({}),s=function(e){var t=r.a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},u=function(e){var t=s(e.components);return r.a.createElement(p.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(n),d=o,m=u["".concat(a,".").concat(d)]||u[d]||b[d]||i;return n?r.a.createElement(m,c({ref:t},p,{components:n})):r.a.createElement(m,c({ref:t},p))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,a[1]=c;for(var p=2;p1?arguments[1]:void 0,n),l=a>2?arguments[2]:void 0,p=void 0===l?n:r(l,n);p>c;)t[c++]=e;return t}},433:function(e,t,n){"use strict";var o=n(435),r=n(51);function i(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),i=t.length>0?t.join("="):void 0;i=void 0===i?null:decodeURIComponent(i),n(decodeURIComponent(r),i,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[i(t,e),"[",o,"]"].join(""):[i(t,e),"[",i(o,e),"]=",i(n,e)].join("")};case"bracket":return function(t,n){return null===n?i(t,e):[i(t,e),"[]=",i(n,e)].join("")};default:return function(t,n){return null===n?i(t,e):[i(t,e),"=",i(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return i(o,t);if(Array.isArray(r)){var a=[];return r.slice().forEach((function(e){void 0!==e&&a.push(n(o,e,a.length))})),a.join("&")}return i(o,t)+"="+i(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(423),n(433)),a=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,i=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},p="https://github.com/qovery/documentation/issues/new?"+a.a.stringify(l),s=Object(o.useState)(null),u=s[0],b=s[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!i&&!u&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:p,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/fc376fea.8ee66ca5.js.LICENSE.txt b/f756422c.b9899556.js.LICENSE.txt similarity index 100% rename from fc376fea.8ee66ca5.js.LICENSE.txt rename to f756422c.b9899556.js.LICENSE.txt diff --git a/f7aa8e39.15d16e87.js b/f7aa8e39.f2962777.js similarity index 72% rename from f7aa8e39.15d16e87.js rename to f7aa8e39.f2962777.js index a73b2463df..861174d292 100644 --- a/f7aa8e39.15d16e87.js +++ b/f7aa8e39.f2962777.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[255],{407:function(a){a.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"language-ruby","name":"language: ruby","count":1,"permalink":"/guides/tags/language-ruby"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[258],{410:function(a){a.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"language-ruby","name":"language: ruby","count":1,"permalink":"/guides/tags/language-ruby"}')}}]); \ No newline at end of file diff --git a/fb1d0a83.46851466.js b/fb1d0a83.3ef499cc.js similarity index 72% rename from fb1d0a83.46851466.js rename to fb1d0a83.3ef499cc.js index 140f374d45..e0847d5d8e 100644 --- a/fb1d0a83.46851466.js +++ b/fb1d0a83.3ef499cc.js @@ -1,2 +1,2 @@ -/*! For license information please see fb1d0a83.46851466.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[256],{408:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return f}));var r=n(1),o=n(9),a=(n(0),n(422)),i=n(431),c=n(421),s=n(426),u=(n(429),{last_modified_on:"2022-09-30",$schema:"/.meta/.schemas/guides.json",title:"How to run commands before the application starts",description:"How to run commands before a Qovery application starts",author_github:"https://github.com/l0ck3",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to run commands before the application starts",description:"How to run commands before a Qovery application starts",permalink:"/guides/tutorial/how-to-run-commands-at-application-startup",readingTime:"3 min read",source:"@site/guides/tutorial/how-to-run-commands-at-application-startup.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to run commands before the application starts",truncated:!1,prevItem:{title:"How to integrate Qovery with GitHub Actions",permalink:"/guides/tutorial/how-to-integrate-qovery-with-github-actions"},nextItem:{title:"How to seed a Postgres database on a dev environment",permalink:"/guides/tutorial/data-seeding-in-postgres"}},p=[{value:"Goal",id:"goal",children:[]}],d={rightToc:p};function f(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Running your applications on Qovery is pretty straightforward, but there are many cases where you will need to run some tasks before your application starts, like running database migrations, and it might not be obvious how to do it."),Object(a.b)(s.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Your app is running in Dockerfile mode."))),Object(a.b)("h2",{id:"goal"},"Goal"),Object(a.b)("p",null,"This tutorial will cover how to run tasks when your application is starting. We'll use the case of a database migration with Ruby on Rails, but the same principle can be applied for any framework or command you need to run."),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"add-an-entrypoint-script"},"Add an entrypoint script"),Object(a.b)("p",null,"The first thing to do is to add an entrypoint script. We'll add it to a docker directory at the project's root, but you can put it anywhere you want."),Object(a.b)("p",null,"Let's create the docker/entrypoint.sh with the following content:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'#! /bin/sh\n\nbundle exec rails db:migrate\n\nif [[ $? -eq 0 ]] ; then\n echo -e "\\n== Failed to migrate. Running setup first. ==\\n"\n bundle exec rails db:setup\nfi\n\n# Execute the given or default command:\n\nexec "$@"\n')),Object(a.b)("p",null,"This script will execute the Rails database migration script. If it fails because the database doesn't exist, it will run the setup command instead."),Object(a.b)("p",null,"The last line is necessary to execute the main command of your Dockerfile."),Object(a.b)(c.a,{type:"warning",mdxType:"Alert"},"These instructions will be executed on each running instances of your application. If you're running multiple instances (or autoscaling), make sure instructions in the entrypoint are idempotent.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"give-execution-permission-to-the-entrypoint-script"},"Give execution permission to the entrypoint script"),Object(a.b)("p",null,"You can give execution permission to this file with the following command:"),Object(a.b)("p",null,Object(a.b)("inlineCode",{parentName:"p"},"chmod +x docker/entrypoint.sh"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-the-entrypoint-to-your-dockerfile"},"Add the entrypoint to your Dockerfile"),Object(a.b)("p",null,"You will now need to add an ENTRYPOINT instruction to your Dockerfile. (Make sure the entrypoint.sh file is copied to the image somewhere)"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'# ...\n\n# Dockerfile content omitted for brevity\n\n# ...\n\nENTRYPOINT ["./docker/entrypoint.sh"]\n\nEXPOSE 3000\n\nCMD ["rails", "server", "-p", "3000", "-b", "0.0.0.0"]\n')),Object(a.b)("p",null,"You can learn more about Docker entrypoints here: ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.docker.com/engine/reference/builder/#entrypoint"}),"https://docs.docker.com/engine/reference/builder/#entrypoint"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"deploy-your-application"},"Deploy your application"),Object(a.b)("p",null,"You can now commit and push your changes to your Git repository. The instructions you specified in the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"http://entrypoint.sh/"}),"entrypoint.sh")," file will be executed before the application starts.")))),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},"Lifecycle hooks and shell access will shortly be available on Qovery. You'll be able to manage this more conveniently."))}f.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),l=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),f=r,m=p["".concat(i,".").concat(f)]||p[f]||d[f]||a;return n?o.a.createElement(m,c({ref:t},u,{components:n})):o.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,u=void 0===s?n:o(s,n);u>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),o=n.n(r),a=n(421);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},427:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(430),s=n(20),u=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,l=n||s,p=Object(c.a)(l),d=Object(o.useRef)(!1),f=u.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!f&&p&&window.docusaurus.prefetch(l),function(){f&&t&&t.disconnect()}}),[l,f,p]),l&&p?a.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(l),d.current=!0)},innerRef:function(e){var n,r;f&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(l)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:l})):a.a.createElement("a",Object(r.a)({},e,{href:l}))}},428:function(e,t,n){"use strict";var r=n(432),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,d=c()("jump-to","jump-to--"+u,n),f=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return l?o.a.createElement("a",{href:p,target:l,className:d},f):o.a.createElement(a.a,{to:p,className:d},f)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),p=l[0],d=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see fb1d0a83.3ef499cc.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[259],{411:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return f}));var r=n(1),o=n(9),a=(n(0),n(425)),i=n(434),c=n(424),s=n(429),u=(n(431),{last_modified_on:"2022-09-30",$schema:"/.meta/.schemas/guides.json",title:"How to run commands before the application starts",description:"How to run commands before a Qovery application starts",author_github:"https://github.com/l0ck3",tags:["type: tutorial","technology: qovery"],hide_pagination:!0}),l={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"How to run commands before the application starts",description:"How to run commands before a Qovery application starts",permalink:"/guides/tutorial/how-to-run-commands-at-application-startup",readingTime:"3 min read",source:"@site/guides/tutorial/how-to-run-commands-at-application-startup.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"How to run commands before the application starts",truncated:!1,prevItem:{title:"How to integrate Qovery with GitHub Actions",permalink:"/guides/tutorial/how-to-integrate-qovery-with-github-actions"},nextItem:{title:"How to seed a Postgres database on a dev environment",permalink:"/guides/tutorial/data-seeding-in-postgres"}},p=[{value:"Goal",id:"goal",children:[]}],d={rightToc:p};function f(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},d,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Running your applications on Qovery is pretty straightforward, but there are many cases where you will need to run some tasks before your application starts, like running database migrations, and it might not be obvious how to do it."),Object(a.b)(s.a,{name:"guide",mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Your app is running in Dockerfile mode."))),Object(a.b)("h2",{id:"goal"},"Goal"),Object(a.b)("p",null,"This tutorial will cover how to run tasks when your application is starting. We'll use the case of a database migration with Ruby on Rails, but the same principle can be applied for any framework or command you need to run."),Object(a.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("h4",{id:"add-an-entrypoint-script"},"Add an entrypoint script"),Object(a.b)("p",null,"The first thing to do is to add an entrypoint script. We'll add it to a docker directory at the project's root, but you can put it anywhere you want."),Object(a.b)("p",null,"Let's create the docker/entrypoint.sh with the following content:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'#! /bin/sh\n\nbundle exec rails db:migrate\n\nif [[ $? -eq 0 ]] ; then\n echo -e "\\n== Failed to migrate. Running setup first. ==\\n"\n bundle exec rails db:setup\nfi\n\n# Execute the given or default command:\n\nexec "$@"\n')),Object(a.b)("p",null,"This script will execute the Rails database migration script. If it fails because the database doesn't exist, it will run the setup command instead."),Object(a.b)("p",null,"The last line is necessary to execute the main command of your Dockerfile."),Object(a.b)(c.a,{type:"warning",mdxType:"Alert"},"These instructions will be executed on each running instances of your application. If you're running multiple instances (or autoscaling), make sure instructions in the entrypoint are idempotent.")),Object(a.b)("li",null,Object(a.b)("h4",{id:"give-execution-permission-to-the-entrypoint-script"},"Give execution permission to the entrypoint script"),Object(a.b)("p",null,"You can give execution permission to this file with the following command:"),Object(a.b)("p",null,Object(a.b)("inlineCode",{parentName:"p"},"chmod +x docker/entrypoint.sh"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"add-the-entrypoint-to-your-dockerfile"},"Add the entrypoint to your Dockerfile"),Object(a.b)("p",null,"You will now need to add an ENTRYPOINT instruction to your Dockerfile. (Make sure the entrypoint.sh file is copied to the image somewhere)"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),'# ...\n\n# Dockerfile content omitted for brevity\n\n# ...\n\nENTRYPOINT ["./docker/entrypoint.sh"]\n\nEXPOSE 3000\n\nCMD ["rails", "server", "-p", "3000", "-b", "0.0.0.0"]\n')),Object(a.b)("p",null,"You can learn more about Docker entrypoints here: ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://docs.docker.com/engine/reference/builder/#entrypoint"}),"https://docs.docker.com/engine/reference/builder/#entrypoint"))),Object(a.b)("li",null,Object(a.b)("h4",{id:"deploy-your-application"},"Deploy your application"),Object(a.b)("p",null,"You can now commit and push your changes to your Git repository. The instructions you specified in the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"http://entrypoint.sh/"}),"entrypoint.sh")," file will be executed before the application starts.")))),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},"Lifecycle hooks and shell access will shortly be available on Qovery. You'll be able to manage this more conveniently."))}f.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=o.a.createContext({}),l=function(e){var t=o.a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=l(e.components);return o.a.createElement(u.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),f=r,m=p["".concat(i,".").concat(f)]||p[f]||d[f]||a;return n?o.a.createElement(m,c({ref:t},u,{components:n})):o.a.createElement(m,c({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var u=2;u1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,u=void 0===s?n:o(s,n);u>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,o=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in o||n(10)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),o=n.n(r),a=n(424);t.a=function(e){var t=e.children,n=e.name;return o.a.createElement(a.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},o.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},430:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(432),s=n(20),u=n.n(s);t.a=function(e){var t,n=e.to,s=e.href,l=n||s,p=Object(c.a)(l),d=Object(o.useRef)(!1),f=u.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!f&&p&&window.docusaurus.prefetch(l),function(){f&&t&&t.disconnect()}}),[l,f,p]),l&&p?a.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){d.current||(window.docusaurus.preload(l),d.current=!0)},innerRef:function(e){var n,r;f&&e&&p&&(n=e,r=function(){window.docusaurus.prefetch(l)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){n===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:l})):a.a.createElement("a",Object(r.a)({},e,{href:l}))}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,d=c()("jump-to","jump-to--"+u,n),f=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return l?o.a.createElement("a",{href:p,target:l,className:d},f):o.a.createElement(a.a,{to:p,className:d},f)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},433:function(e,t,n){"use strict";var r=n(435),o=n(51);function a(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=o({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),o=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(o),a,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[a(t,e),"[",r,"]"].join(""):[a(t,e),"[",a(r,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=o({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var o=e[r];if(void 0===o)return"";if(null===o)return a(r,t);if(Array.isArray(o)){var i=[];return o.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(o,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,s={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),l=Object(r.useState)(null),p=l[0],d=l[1];return o.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&o.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",o.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return d("yes")}},"Yes"),"\xa0\xa0",o.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&o.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",o.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/fcb698a1.a89727e5.js.LICENSE.txt b/fb1d0a83.3ef499cc.js.LICENSE.txt similarity index 100% rename from fcb698a1.a89727e5.js.LICENSE.txt rename to fb1d0a83.3ef499cc.js.LICENSE.txt diff --git a/fc376fea.508bae3d.js b/fc376fea.508bae3d.js new file mode 100644 index 0000000000..dbd757cc7d --- /dev/null +++ b/fc376fea.508bae3d.js @@ -0,0 +1,2 @@ +/*! For license information please see fc376fea.508bae3d.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[260],{412:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return l}));var r=n(1),o=n(9),a=(n(0),n(425)),i=n(431),c={last_modified_on:"2023-11-29",title:"Configuration",description:"Everything you need to know to configure and deploy your applications on Qovery",sidebar_label:"hidden",hide_pagination:!0},u={id:"using-qovery/configuration",title:"Configuration",description:"Everything you need to know to configure and deploy your applications on Qovery",source:"@site/docs/using-qovery/configuration.md",permalink:"/docs/using-qovery/configuration",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Slack",permalink:"/docs/using-qovery/integration/slack"},next:{title:"Organization",permalink:"/docs/using-qovery/configuration/organization"}},s=[],p={rightToc:s};function l(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"In the following subsections, you'll learn all you need to know to configure and deploy your apps on Qovery."),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/advanced-settings/",mdxType:"Jump"},"Advanced settings"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/application-health-checks/",mdxType:"Jump"},"Application health checks"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/application/",mdxType:"Jump"},"Application"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/",mdxType:"Jump"},"Cloud service provider"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cluster-advanced-settings/",mdxType:"Jump"},"Cluster advanced settings"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/clusters/",mdxType:"Jump"},"Clusters"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cronjob/",mdxType:"Jump"},"Cronjob"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/database/",mdxType:"Jump"},"Database"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/deployment-rule/",mdxType:"Jump"},"Deployment rule"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/environment-variable/",mdxType:"Jump"},"Environment variable"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/environment/",mdxType:"Jump"},"Environment"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/helm/",mdxType:"Jump"},"Helm"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/lifecycle-job/",mdxType:"Jump"},"Lifecycle job"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/object-storage/",mdxType:"Jump"},"Object storage"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/organization/",mdxType:"Jump"},"Organization"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/project/",mdxType:"Jump"},"Project"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/provider/",mdxType:"Jump"},"Provider"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/service-health-checks/",mdxType:"Jump"},"Service health checks"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/user-account/",mdxType:"Jump"},"User account"))}l.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),p=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},l=function(e){var t=p(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),l=p(n),f=r,m=l["".concat(i,".").concat(f)]||l[f]||d[f]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=f;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:p})):a.a.createElement("a",Object(r.a)({},e,{href:p}))}},431:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(430),i=n(423),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,u=e.rightIcon,s=e.size,p=e.target,l=e.to,d=c()("jump-to","jump-to--"+s,n),f=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return p?o.a.createElement("a",{href:l,target:p,className:d},f):o.a.createElement(a.a,{to:l,className:d},f)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/fcd9bd5b.779d6312.js.LICENSE.txt b/fc376fea.508bae3d.js.LICENSE.txt similarity index 100% rename from fcd9bd5b.779d6312.js.LICENSE.txt rename to fc376fea.508bae3d.js.LICENSE.txt diff --git a/fc376fea.8ee66ca5.js b/fc376fea.8ee66ca5.js deleted file mode 100644 index 958391f521..0000000000 --- a/fc376fea.8ee66ca5.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see fc376fea.8ee66ca5.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[257],{409:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return l}));var r=n(1),o=n(9),a=(n(0),n(422)),i=n(429),c={last_modified_on:"2023-11-25",title:"Configuration",description:"Everything you need to know to configure and deploy your applications on Qovery",sidebar_label:"hidden",hide_pagination:!0},u={id:"using-qovery/configuration",title:"Configuration",description:"Everything you need to know to configure and deploy your applications on Qovery",source:"@site/docs/using-qovery/configuration.md",permalink:"/docs/using-qovery/configuration",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Slack",permalink:"/docs/using-qovery/integration/slack"},next:{title:"Organization",permalink:"/docs/using-qovery/configuration/organization"}},s=[],p={rightToc:s};function l(e){var t=e.components,n=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"In the following subsections, you'll learn all you need to know to configure and deploy your apps on Qovery."),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/advanced-settings/",mdxType:"Jump"},"Advanced settings"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/application-health-checks/",mdxType:"Jump"},"Application health checks"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/application/",mdxType:"Jump"},"Application"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cloud-service-provider/",mdxType:"Jump"},"Cloud service provider"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cluster-advanced-settings/",mdxType:"Jump"},"Cluster advanced settings"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/clusters/",mdxType:"Jump"},"Clusters"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/cronjob/",mdxType:"Jump"},"Cronjob"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/database/",mdxType:"Jump"},"Database"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/deployment-rule/",mdxType:"Jump"},"Deployment rule"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/environment-variable/",mdxType:"Jump"},"Environment variable"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/environment/",mdxType:"Jump"},"Environment"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/lifecycle-job/",mdxType:"Jump"},"Lifecycle job"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/object-storage/",mdxType:"Jump"},"Object storage"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/organization/",mdxType:"Jump"},"Organization"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/project/",mdxType:"Jump"},"Project"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/provider/",mdxType:"Jump"},"Provider"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/service-health-checks/",mdxType:"Jump"},"Service health checks"),Object(a.b)(i.a,{to:"/docs/using-qovery/configuration/user-account/",mdxType:"Jump"},"User account"))}l.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=o.a.createContext({}),p=function(e){var t=o.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},l=function(e){var t=p(e.components);return o.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),l=p(n),f=r,m=l["".concat(i,".").concat(f)]||l[f]||d[f]||a;return n?o.a.createElement(m,c({ref:t},s,{components:n})):o.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=f;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:p})):a.a.createElement("a",Object(r.a)({},e,{href:p}))}},429:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(427),i=n(420),c=n.n(i);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,u=e.rightIcon,s=e.size,p=e.target,l=e.to,d=c()("jump-to","jump-to--"+s,n),f=o.a.createElement("div",{className:"jump-to--inner"},o.a.createElement("div",{className:"jump-to--inner-2"},i&&o.a.createElement("div",{className:"jump-to--left"},o.a.createElement("i",{className:"feather icon-"+i})),o.a.createElement("div",{className:"jump-to--main"},r?o.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),o.a.createElement("div",{className:"jump-to--right"},o.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return p?o.a.createElement("a",{href:l,target:p,className:d},f):o.a.createElement(a.a,{to:l,className:d},f)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/fcb698a1.a89727e5.js b/fcb698a1.70490934.js similarity index 89% rename from fcb698a1.a89727e5.js rename to fcb698a1.70490934.js index 2d1888db92..7b8cf8b59b 100644 --- a/fcb698a1.a89727e5.js +++ b/fcb698a1.70490934.js @@ -1,2 +1,2 @@ -/*! For license information please see fcb698a1.a89727e5.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[258],{410:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),c=(n(0),n(422)),o=n(429),i={last_modified_on:"2023-03-17",title:"Security and Compliance",description:"Learn more about Security and Compliance in Qovery",sidebar_label:"hidden",hide_pagination:!0},u={id:"security-and-compliance",title:"Security and Compliance",description:"Learn more about Security and Compliance in Qovery",source:"@site/docs/security-and-compliance.md",permalink:"/docs/security-and-compliance",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Maintenance",permalink:"/docs/using-qovery/maintenance"},next:{title:"Backup and Restore",permalink:"/docs/security-and-compliance/backup-and-restore"}},s=[],p={rightToc:s};function l(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(c.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(c.b)("p",null,"This section will cover the main Security and Compliance topics:"),Object(c.b)(o.a,{to:"/docs/security-and-compliance/backup-and-restore/",mdxType:"Jump"},"Backup and restore"),Object(c.b)(o.a,{to:"/docs/security-and-compliance/encryption/",mdxType:"Jump"},"Encryption"),Object(c.b)(o.a,{to:"/docs/security-and-compliance/gdpr/",mdxType:"Jump"},"Gdpr"),Object(c.b)(o.a,{to:"/docs/security-and-compliance/soc2/",mdxType:"Jump"},"Soc2"))}l.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),p=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},l=function(e){var t=p(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,c=e.originalType,o=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),l=p(n),m=r,f=l["".concat(o,".").concat(m)]||l[m]||d[m]||c;return n?a.a.createElement(f,i({ref:t},s,{components:n})):a.a.createElement(f,i({ref:t},s))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var c=n.length,o=new Array(c);o[0]=m;var i={};for(var u in t)hasOwnProperty.call(t,u)&&(i[u]=t[u]);i.originalType=e,i.mdxType="string"==typeof e?e:r,o[1]=i;for(var s=2;s0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:p})):c.a.createElement("a",Object(r.a)({},e,{href:p}))}},429:function(e,t,n){"use strict";var r=n(0),a=n.n(r),c=n(427),o=n(420),i=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,o=e.leftIcon,u=e.rightIcon,s=e.size,p=e.target,l=e.to,d=i()("jump-to","jump-to--"+s,n),m=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},o&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+o})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return p?a.a.createElement("a",{href:l,target:p,className:d},m):a.a.createElement(c.a,{to:l,className:d},m)}},430:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file +/*! For license information please see fcb698a1.70490934.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[261],{413:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),c=(n(0),n(425)),o=n(431),i={last_modified_on:"2023-03-17",title:"Security and Compliance",description:"Learn more about Security and Compliance in Qovery",sidebar_label:"hidden",hide_pagination:!0},u={id:"security-and-compliance",title:"Security and Compliance",description:"Learn more about Security and Compliance in Qovery",source:"@site/docs/security-and-compliance.md",permalink:"/docs/security-and-compliance",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Maintenance",permalink:"/docs/using-qovery/maintenance"},next:{title:"Backup and Restore",permalink:"/docs/security-and-compliance/backup-and-restore"}},s=[],p={rightToc:s};function l(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(c.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(c.b)("p",null,"This section will cover the main Security and Compliance topics:"),Object(c.b)(o.a,{to:"/docs/security-and-compliance/backup-and-restore/",mdxType:"Jump"},"Backup and restore"),Object(c.b)(o.a,{to:"/docs/security-and-compliance/encryption/",mdxType:"Jump"},"Encryption"),Object(c.b)(o.a,{to:"/docs/security-and-compliance/gdpr/",mdxType:"Jump"},"Gdpr"),Object(c.b)(o.a,{to:"/docs/security-and-compliance/soc2/",mdxType:"Jump"},"Soc2"))}l.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),p=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},l=function(e){var t=p(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,c=e.originalType,o=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),l=p(n),m=r,f=l["".concat(o,".").concat(m)]||l[m]||d[m]||c;return n?a.a.createElement(f,i({ref:t},s,{components:n})):a.a.createElement(f,i({ref:t},s))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var c=n.length,o=new Array(c);o[0]=m;var i={};for(var u in t)hasOwnProperty.call(t,u)&&(i[u]=t[u]);i.originalType=e,i.mdxType="string"==typeof e?e:r,o[1]=i;for(var s=2;s0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:p})):c.a.createElement("a",Object(r.a)({},e,{href:p}))}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),c=n(430),o=n(423),i=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.className,r=e.badge,o=e.leftIcon,u=e.rightIcon,s=e.size,p=e.target,l=e.to,d=i()("jump-to","jump-to--"+s,n),m=a.a.createElement("div",{className:"jump-to--inner"},a.a.createElement("div",{className:"jump-to--inner-2"},o&&a.a.createElement("div",{className:"jump-to--left"},a.a.createElement("i",{className:"feather icon-"+o})),a.a.createElement("div",{className:"jump-to--main"},r?a.a.createElement("span",{className:"badge badge--primary badge--right"},r):"",t),a.a.createElement("div",{className:"jump-to--right"},a.a.createElement("i",{className:"feather icon-"+(u||"chevron-right")+" arrow"}))));return p?a.a.createElement("a",{href:l,target:p,className:d},m):a.a.createElement(c.a,{to:l,className:d},m)}},432:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))}}]); \ No newline at end of file diff --git a/ff053ed0.f6e07253.js.LICENSE.txt b/fcb698a1.70490934.js.LICENSE.txt similarity index 100% rename from ff053ed0.f6e07253.js.LICENSE.txt rename to fcb698a1.70490934.js.LICENSE.txt diff --git a/fcd9bd5b.779d6312.js b/fcd9bd5b.8a7f6c89.js similarity index 96% rename from fcd9bd5b.779d6312.js rename to fcd9bd5b.8a7f6c89.js index 59f9735b07..676ca8e075 100644 --- a/fcd9bd5b.779d6312.js +++ b/fcd9bd5b.8a7f6c89.js @@ -1,2 +1,2 @@ -/*! For license information please see fcd9bd5b.779d6312.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[259],{411:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return b}));var o=n(1),r=n(9),a=(n(0),n(422)),i=n(421),c=n(431),l={last_modified_on:"2023-06-12",title:"Application Troubleshoot",description:"Everything you need to troubleshoot your application with Qovery",hide_pagination:!0},s={id:"using-qovery/troubleshoot/application-troubleshoot",title:"Application Troubleshoot",description:"Everything you need to troubleshoot your application with Qovery",source:"@site/docs/using-qovery/troubleshoot/application-troubleshoot.md",permalink:"/docs/using-qovery/troubleshoot/application-troubleshoot",sidebar:"docs",previous:{title:"Troubleshoot",permalink:"/docs/using-qovery/troubleshoot"},next:{title:"Database Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/database-troubleshoot"}},u=[{value:"Liveness/Readiness failed, connect: connection refused",id:"livenessreadiness-failed-connect-connection-refused",children:[]},{value:"My app is crashing, how do I connect to investigate?",id:"my-app-is-crashing-how-do-i-connect-to-investigate",children:[]},{value:"0/x nodes are available: x insufficient cpu/ram",id:"0x-nodes-are-available-x-insufficient-cpuram",children:[]},{value:"Can't get my SSL / TLS Certificate",id:"cant-get-my-ssl--tls-certificate",children:[]},{value:"Git Submodules - Error while checkout submodules",id:"git-submodules---error-while-checkout-submodules",children:[]},{value:"Container image xxxxxx.xxx.xx failed to build: Cannot build Application "zXXXXXXXXX" due to an error with docker: Timeout",id:"container-image-xxxxxxxxxxx-failed-to-build-cannot-build-application-zxxxxxxxxx-due-to-an-error-with-docker-timeout",children:[]}],p={rightToc:u};function b(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Within this section you will find the common errors you might encounter when deploying or running your applications with Qovery"),Object(a.b)("h2",{id:"livenessreadiness-failed-connect-connection-refused"},"Liveness/Readiness failed, connect: connection refused"),Object(a.b)("p",null,"If you encounter this kind of error on the Liveness and/or Readiness probe during an application deployment phase:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"Readiness probe failed: dial tcp 100.64.2.230:80: connect: connection refused\nLiveness probe failed: dial tcp 100.64.2.230:80: connect: connection refused\n")),Object(a.b)("p",null,"That means your application may not able to start, or has started but takes too many time to start."),Object(a.b)("p",null,"Here are the possible reasons for starting issues you should check:"),Object(a.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"The declared port on Qovery (here 80), does not match your application's opening port. Check your application port, and ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#ports"}),"set the correct port to your application configuration"),".")),Object(a.b)("li",null,Object(a.b)("p",null,"Ensure your application is not listening onto localhost (127.0.0.1) or a specific IP. But set it to all interfaces (0.0.0.0).")),Object(a.b)("li",null,Object(a.b)("p",null,"Your application takes too long to start and the liveness probe is flagging your application as unhealthy. Try to increase the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application-health-checks/#initial-delay-in-seconds"}),"Liveness ",Object(a.b)("inlineCode",{parentName:"a"},"Initial Delay")," parameter"),", to inform Kubernetes to delay the time before checking your application availability. Set it for example to 120.")))),Object(a.b)("h2",{id:"my-app-is-crashing-how-do-i-connect-to-investigate"},"My app is crashing, how do I connect to investigate?"),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Goal: You want to connect to your container's application to debug your application")),Object(a.b)("p",null,"First, try to use ",Object(a.b)("inlineCode",{parentName:"p"},"qovery shell")," command from the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#shell"}),"Qovery CLI"),". It's a safe method to connect to your container and debug your application."),Object(a.b)("p",null,"If your app is crashing in the first seconds, you'll lose the connection to your container, making the debug almost impossible, then continue reading."),Object(a.b)(i.a,{type:"danger",mdxType:"Alert"},Object(a.b)("p",null,"You can apply this procedure directly on your application OR on a copy having the same setup.\nIf you don't make a copy, doing this procedure directly on the ",Object(a.b)("strong",{parentName:"p"},"PRODUCTION")," application will lead to a downtime in your service. Be sure of what you're doing before going ahead!")),Object(a.b)("p",null,"Your app is crashing very quickly, here is how to keep the full control of your container:"),Object(a.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#ports"}),"Temporary delete the application port from your application configuration"),". This to avoid Kubernetes to restart the container when the port is not open.")),Object(a.b)("li",null,Object(a.b)("p",null,"Into your Dockerfile, comment your ",Object(a.b)("inlineCode",{parentName:"p"},"EXEC")," or ",Object(a.b)("inlineCode",{parentName:"p"},"ENTRYPOINT")," and add a way to make your container sleep. For example:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),'#CMD ["npm", "run", "start"]\nCMD ["tail", "-f", "/dev/null"]\n')),Object(a.b)("p",null,"Commit and push your changes to trigger a new deployment (trigger it manually from the Qovery console if it's not the case).")),Object(a.b)("li",null,Object(a.b)("p",null,"Once the deployment done, you can use ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#shell"}),"qovery shell")," command to connect to your container and debug."),Object(a.b)(i.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,"Once you've finished debugging, ",Object(a.b)("strong",{parentName:"p"},"remember to configure your application port back"),". It's mandatory to avoid downtimes during application releases."))))),Object(a.b)("h2",{id:"0x-nodes-are-available-x-insufficient-cpuram"},"0/x nodes are available: x insufficient cpu/ram"),Object(a.b)("p",null,"If you encounter this kind of error during an application deployment phase:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"0/1 nodes are available: 1 Insufficient cpu (or ram).\n")),Object(a.b)("p",null,"That means that we cannot reserve the necessary resources to deploy your application or database on your cluster due to an insufficient amount of CPU or RAM. Moreover, the cluster auto-scaler cannot be triggered since it has already reached the maximum number of instances for your cluster (valid only for Managed Kubernetes clusters)."),Object(a.b)("p",null,"Here are the possible solutions you can apply:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("p",{parentName:"li"},"Reduce the resources (CPU/RAM) allocated to your existing/new service. Have a review of the deployed services and see if you can save up some resources by reducing their CPU/RAM setting. If you are using a ",Object(a.b)("em",{parentName:"p"},"K3S (EC2) cluster"),", stop your service before changing the settings. Remember to re-deploy the applications when you edit the resource. Have a look at ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#resources"}),"the resource section for more information"),".")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("p",{parentName:"li"},"Select a bigger instance type for your cluster (in terms of CPU/RAM). By increasing it, it will unlock the deployment of your application (since new resources have been added). Check your ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#managing-your-cluster-settings"}),"cluster settings"),", and change the instance type of your cluster.")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("p",{parentName:"li"},"(only for Managed kubernets clusters) Increase the maximum number of nodes of your cluster. By increasing it, it will allow the cluster autoscaler to add a new node and allow the deployment of your application (since new resources have been added). Check your ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#managing-your-cluster-settings"}),"cluster settings"),", and increase the maximum number of nodes of your cluster."))),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Please note that by increasing the number of nodes OR by selecting a bigger instance type you will increase your cloud provider cost. For more information, have a look at our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#what-are-the-different-instance-types-available-when-creating-a-cluster"}),"cluster section"),".")),Object(a.b)("p",null,"Please note that application resource consumption and application resource allocation are not the same. Have a look at ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#resources"}),"the resource section for more information")),Object(a.b)("h2",{id:"cant-get-my-ssl--tls-certificate"},"Can't get my SSL / TLS Certificate"),Object(a.b)("p",null,"When a custom domain is added to an application, it must be configured on your side according to the instructions displayed:"),Object(a.b)("p",{Valign:"center"},Object(a.b)("img",{src:"/img/custom-domain-configuration.png",alt:"Custom Domain Configuration"})),Object(a.b)("p",null,"You can check that your custom domain is well configured using the following command: ",Object(a.b)("inlineCode",{parentName:"p"},"dig CNAME ${YOUR_CUSTOM_DOMAIN} +short"),". On the domain above, we can check the configuration is correct on Google DNS servers:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"$ dig CNAME new.console.qovery.com +short @8.8.8.8\nzdf72de71-z709e1a85-gtw.za8ad0659.bool.sh.\n")),Object(a.b)("p",null,"It should return the same value as the one configured on Qovery. Otherwise, be patient (some minutes depending on DNS registrars) and ensure the DNS modification has been applied. Finally, you can check the content of the ",Object(a.b)("inlineCode",{parentName:"p"},"CNAME")," with:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"$ dig A new.console.qovery.com +short @8.8.8.8\nzdf72de71-z709e1a85-gtw.za8ad0659.bool.sh.\nac8ad80d15e534c549ee10c87aaf82b4-bba68d8f58c6755d.elb.us-east-2.amazonaws.com.\n3.19.99.1\n18.188.137.104\n")),Object(a.b)("p",null,"We can see the destination contains other elements, indicating that the ",Object(a.b)("inlineCode",{parentName:"p"},"CNAME")," is pointing to an endpoint and correctly configured."),Object(a.b)("p",null,"The SSL / TLS Certificate is generated for the whole group of custom domains you define:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"if one custom domain is misconfigured: the certificate can't be generated"),Object(a.b)("li",{parentName:"ul"},"if the certificate has been generated once, but later one custom domain configuration is changed and misconfigured: the certificate can't be generated again")),Object(a.b)("p",null,"If you experience some invalid certificate, here is how you can fix the issue:"),Object(a.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Identify the misconfigured custom domain(s) in your application settings.")),Object(a.b)("li",null,Object(a.b)("p",null,"Fix or delete them.")),Object(a.b)("li",null,Object(a.b)("p",null,"Redeploy your impacted application(s).")))),Object(a.b)("h2",{id:"git-submodules---error-while-checkout-submodules"},"Git Submodules - Error while checkout submodules"),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Error Message"),":"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{}),'Error message: Error while checkout submodules from repository https://github.com/user/repo.git.\nError: Error { code: -1, klass: 23, message: "authentication required but no callback set" }\n')),Object(a.b)("p",null,"There are limitations with the support for Git Submodules. Only public Submodules over HTTPS or private with embedded basic authentication are supported."),Object(a.b)("p",null,"Solution: Follow our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/working-with-git-submodules/"}),"Git Submodules guide")," to make your application working with Git Submodules on Qovery."),Object(a.b)("h2",{id:"container-image-xxxxxxxxxxx-failed-to-build-cannot-build-application-zxxxxxxxxx-due-to-an-error-with-docker-timeout"},'Container image xxxxxx.xxx.xx failed to build: Cannot build Application "zXXXXXXXXX" due to an error with docker: Timeout'),Object(a.b)("p",null,"This error shows up in your deployment logs when the application takes more time to build than the maximum build allowed time (today 1800 seconds). "),Object(a.b)("p",null,"If your application needs more time to build, increase parameter ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/advanced-settings/#application-deployment"}),"build.timeout_max_sec")," within your application advanced settings and trigger again the deployment."))}b.isMDXComponent=!0},420:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=o,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return n?r.a.createElement(m,c({ref:t},s,{components:n})):r.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){"use strict";var o=n(432),r=n(51);function a(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(r),a,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[a(t,e),"[",o,"]"].join(""):[a(t,e),"[",a(o,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return a(o,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(n(o,e,i.length))})),i.join("&")}return a(o,t)+"="+a(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(420),n(428)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(o.useState)(null),p=u[0],b=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see fcd9bd5b.8a7f6c89.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[262],{414:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return b}));var o=n(1),r=n(9),a=(n(0),n(425)),i=n(424),c=n(434),l={last_modified_on:"2023-06-12",title:"Application Troubleshoot",description:"Everything you need to troubleshoot your application with Qovery",hide_pagination:!0},s={id:"using-qovery/troubleshoot/application-troubleshoot",title:"Application Troubleshoot",description:"Everything you need to troubleshoot your application with Qovery",source:"@site/docs/using-qovery/troubleshoot/application-troubleshoot.md",permalink:"/docs/using-qovery/troubleshoot/application-troubleshoot",sidebar:"docs",previous:{title:"Troubleshoot",permalink:"/docs/using-qovery/troubleshoot"},next:{title:"Database Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/database-troubleshoot"}},u=[{value:"Liveness/Readiness failed, connect: connection refused",id:"livenessreadiness-failed-connect-connection-refused",children:[]},{value:"My app is crashing, how do I connect to investigate?",id:"my-app-is-crashing-how-do-i-connect-to-investigate",children:[]},{value:"0/x nodes are available: x insufficient cpu/ram",id:"0x-nodes-are-available-x-insufficient-cpuram",children:[]},{value:"Can't get my SSL / TLS Certificate",id:"cant-get-my-ssl--tls-certificate",children:[]},{value:"Git Submodules - Error while checkout submodules",id:"git-submodules---error-while-checkout-submodules",children:[]},{value:"Container image xxxxxx.xxx.xx failed to build: Cannot build Application "zXXXXXXXXX" due to an error with docker: Timeout",id:"container-image-xxxxxxxxxxx-failed-to-build-cannot-build-application-zxxxxxxxxx-due-to-an-error-with-docker-timeout",children:[]}],p={rightToc:u};function b(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Within this section you will find the common errors you might encounter when deploying or running your applications with Qovery"),Object(a.b)("h2",{id:"livenessreadiness-failed-connect-connection-refused"},"Liveness/Readiness failed, connect: connection refused"),Object(a.b)("p",null,"If you encounter this kind of error on the Liveness and/or Readiness probe during an application deployment phase:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"Readiness probe failed: dial tcp 100.64.2.230:80: connect: connection refused\nLiveness probe failed: dial tcp 100.64.2.230:80: connect: connection refused\n")),Object(a.b)("p",null,"That means your application may not able to start, or has started but takes too many time to start."),Object(a.b)("p",null,"Here are the possible reasons for starting issues you should check:"),Object(a.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"The declared port on Qovery (here 80), does not match your application's opening port. Check your application port, and ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#ports"}),"set the correct port to your application configuration"),".")),Object(a.b)("li",null,Object(a.b)("p",null,"Ensure your application is not listening onto localhost (127.0.0.1) or a specific IP. But set it to all interfaces (0.0.0.0).")),Object(a.b)("li",null,Object(a.b)("p",null,"Your application takes too long to start and the liveness probe is flagging your application as unhealthy. Try to increase the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application-health-checks/#initial-delay-in-seconds"}),"Liveness ",Object(a.b)("inlineCode",{parentName:"a"},"Initial Delay")," parameter"),", to inform Kubernetes to delay the time before checking your application availability. Set it for example to 120.")))),Object(a.b)("h2",{id:"my-app-is-crashing-how-do-i-connect-to-investigate"},"My app is crashing, how do I connect to investigate?"),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Goal: You want to connect to your container's application to debug your application")),Object(a.b)("p",null,"First, try to use ",Object(a.b)("inlineCode",{parentName:"p"},"qovery shell")," command from the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#shell"}),"Qovery CLI"),". It's a safe method to connect to your container and debug your application."),Object(a.b)("p",null,"If your app is crashing in the first seconds, you'll lose the connection to your container, making the debug almost impossible, then continue reading."),Object(a.b)(i.a,{type:"danger",mdxType:"Alert"},Object(a.b)("p",null,"You can apply this procedure directly on your application OR on a copy having the same setup.\nIf you don't make a copy, doing this procedure directly on the ",Object(a.b)("strong",{parentName:"p"},"PRODUCTION")," application will lead to a downtime in your service. Be sure of what you're doing before going ahead!")),Object(a.b)("p",null,"Your app is crashing very quickly, here is how to keep the full control of your container:"),Object(a.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#ports"}),"Temporary delete the application port from your application configuration"),". This to avoid Kubernetes to restart the container when the port is not open.")),Object(a.b)("li",null,Object(a.b)("p",null,"Into your Dockerfile, comment your ",Object(a.b)("inlineCode",{parentName:"p"},"EXEC")," or ",Object(a.b)("inlineCode",{parentName:"p"},"ENTRYPOINT")," and add a way to make your container sleep. For example:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),'#CMD ["npm", "run", "start"]\nCMD ["tail", "-f", "/dev/null"]\n')),Object(a.b)("p",null,"Commit and push your changes to trigger a new deployment (trigger it manually from the Qovery console if it's not the case).")),Object(a.b)("li",null,Object(a.b)("p",null,"Once the deployment done, you can use ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#shell"}),"qovery shell")," command to connect to your container and debug."),Object(a.b)(i.a,{type:"success",mdxType:"Alert"},Object(a.b)("p",null,"Once you've finished debugging, ",Object(a.b)("strong",{parentName:"p"},"remember to configure your application port back"),". It's mandatory to avoid downtimes during application releases."))))),Object(a.b)("h2",{id:"0x-nodes-are-available-x-insufficient-cpuram"},"0/x nodes are available: x insufficient cpu/ram"),Object(a.b)("p",null,"If you encounter this kind of error during an application deployment phase:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"0/1 nodes are available: 1 Insufficient cpu (or ram).\n")),Object(a.b)("p",null,"That means that we cannot reserve the necessary resources to deploy your application or database on your cluster due to an insufficient amount of CPU or RAM. Moreover, the cluster auto-scaler cannot be triggered since it has already reached the maximum number of instances for your cluster (valid only for Managed Kubernetes clusters)."),Object(a.b)("p",null,"Here are the possible solutions you can apply:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("p",{parentName:"li"},"Reduce the resources (CPU/RAM) allocated to your existing/new service. Have a review of the deployed services and see if you can save up some resources by reducing their CPU/RAM setting. If you are using a ",Object(a.b)("em",{parentName:"p"},"K3S (EC2) cluster"),", stop your service before changing the settings. Remember to re-deploy the applications when you edit the resource. Have a look at ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#resources"}),"the resource section for more information"),".")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("p",{parentName:"li"},"Select a bigger instance type for your cluster (in terms of CPU/RAM). By increasing it, it will unlock the deployment of your application (since new resources have been added). Check your ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#managing-your-cluster-settings"}),"cluster settings"),", and change the instance type of your cluster.")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("p",{parentName:"li"},"(only for Managed kubernets clusters) Increase the maximum number of nodes of your cluster. By increasing it, it will allow the cluster autoscaler to add a new node and allow the deployment of your application (since new resources have been added). Check your ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#managing-your-cluster-settings"}),"cluster settings"),", and increase the maximum number of nodes of your cluster."))),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Please note that by increasing the number of nodes OR by selecting a bigger instance type you will increase your cloud provider cost. For more information, have a look at our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#what-are-the-different-instance-types-available-when-creating-a-cluster"}),"cluster section"),".")),Object(a.b)("p",null,"Please note that application resource consumption and application resource allocation are not the same. Have a look at ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application/#resources"}),"the resource section for more information")),Object(a.b)("h2",{id:"cant-get-my-ssl--tls-certificate"},"Can't get my SSL / TLS Certificate"),Object(a.b)("p",null,"When a custom domain is added to an application, it must be configured on your side according to the instructions displayed:"),Object(a.b)("p",{Valign:"center"},Object(a.b)("img",{src:"/img/custom-domain-configuration.png",alt:"Custom Domain Configuration"})),Object(a.b)("p",null,"You can check that your custom domain is well configured using the following command: ",Object(a.b)("inlineCode",{parentName:"p"},"dig CNAME ${YOUR_CUSTOM_DOMAIN} +short"),". On the domain above, we can check the configuration is correct on Google DNS servers:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"$ dig CNAME new.console.qovery.com +short @8.8.8.8\nzdf72de71-z709e1a85-gtw.za8ad0659.bool.sh.\n")),Object(a.b)("p",null,"It should return the same value as the one configured on Qovery. Otherwise, be patient (some minutes depending on DNS registrars) and ensure the DNS modification has been applied. Finally, you can check the content of the ",Object(a.b)("inlineCode",{parentName:"p"},"CNAME")," with:"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{className:"language-bash"}),"$ dig A new.console.qovery.com +short @8.8.8.8\nzdf72de71-z709e1a85-gtw.za8ad0659.bool.sh.\nac8ad80d15e534c549ee10c87aaf82b4-bba68d8f58c6755d.elb.us-east-2.amazonaws.com.\n3.19.99.1\n18.188.137.104\n")),Object(a.b)("p",null,"We can see the destination contains other elements, indicating that the ",Object(a.b)("inlineCode",{parentName:"p"},"CNAME")," is pointing to an endpoint and correctly configured."),Object(a.b)("p",null,"The SSL / TLS Certificate is generated for the whole group of custom domains you define:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"if one custom domain is misconfigured: the certificate can't be generated"),Object(a.b)("li",{parentName:"ul"},"if the certificate has been generated once, but later one custom domain configuration is changed and misconfigured: the certificate can't be generated again")),Object(a.b)("p",null,"If you experience some invalid certificate, here is how you can fix the issue:"),Object(a.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Identify the misconfigured custom domain(s) in your application settings.")),Object(a.b)("li",null,Object(a.b)("p",null,"Fix or delete them.")),Object(a.b)("li",null,Object(a.b)("p",null,"Redeploy your impacted application(s).")))),Object(a.b)("h2",{id:"git-submodules---error-while-checkout-submodules"},"Git Submodules - Error while checkout submodules"),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Error Message"),":"),Object(a.b)("pre",null,Object(a.b)("code",Object(o.a)({parentName:"pre"},{}),'Error message: Error while checkout submodules from repository https://github.com/user/repo.git.\nError: Error { code: -1, klass: 23, message: "authentication required but no callback set" }\n')),Object(a.b)("p",null,"There are limitations with the support for Git Submodules. Only public Submodules over HTTPS or private with embedded basic authentication are supported."),Object(a.b)("p",null,"Solution: Follow our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/tutorial/working-with-git-submodules/"}),"Git Submodules guide")," to make your application working with Git Submodules on Qovery."),Object(a.b)("h2",{id:"container-image-xxxxxxxxxxx-failed-to-build-cannot-build-application-zxxxxxxxxx-due-to-an-error-with-docker-timeout"},'Container image xxxxxx.xxx.xx failed to build: Cannot build Application "zXXXXXXXXX" due to an error with docker: Timeout'),Object(a.b)("p",null,"This error shows up in your deployment logs when the application takes more time to build than the maximum build allowed time (today 1800 seconds). "),Object(a.b)("p",null,"If your application needs more time to build, increase parameter ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/advanced-settings/#application-deployment"}),"build.timeout_max_sec")," within your application advanced settings and trigger again the deployment."))}b.isMDXComponent=!0},423:function(e,t,n){var o;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),u=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=o,m=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;return n?r.a.createElement(m,c({ref:t},s,{components:n})):r.a.createElement(m,c({ref:t},s))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:r(l,n);s>c;)t[c++]=e;return t}},433:function(e,t,n){"use strict";var o=n(435),r=n(51);function a(e,t){return t.encode?t.strict?o(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,o){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===o[e]&&(o[e]={}),o[e][t[1]]=n):o[e]=n};case"bracket":return function(e,n,o){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==o[e]?o[e]=[].concat(o[e],n):o[e]=[n]:o[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=r({arrayFormat:"none"},t)),o=Object.create(null);return"string"!=typeof e?o:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(r),a,o)})),Object.keys(o).sort().reduce((function(e,t){var n=o[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):o},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,o){return null===n?[a(t,e),"[",o,"]"].join(""):[a(t,e),"[",a(o,e),"]=",a(n,e)].join("")};case"bracket":return function(t,n){return null===n?a(t,e):[a(t,e),"[]=",a(n,e)].join("")};default:return function(t,n){return null===n?a(t,e):[a(t,e),"=",a(n,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var r=e[o];if(void 0===r)return"";if(null===r)return a(o,t);if(Array.isArray(r)){var i=[];return r.slice().forEach((function(e){void 0!==e&&i.push(n(o,e,i.length))})),i.join("&")}return a(o,t)+"="+a(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(423),n(433)),i=n.n(a);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(o.useState)(null),p=u[0],b=u[1];return r.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/ff0cde69.3d36ebd5.js.LICENSE.txt b/fcd9bd5b.8a7f6c89.js.LICENSE.txt similarity index 100% rename from ff0cde69.3d36ebd5.js.LICENSE.txt rename to fcd9bd5b.8a7f6c89.js.LICENSE.txt diff --git a/fe264ce1.6cd4155c.js b/fe264ce1.58ec2a69.js similarity index 96% rename from fe264ce1.6cd4155c.js rename to fe264ce1.58ec2a69.js index 81b8079713..8957128cdd 100644 --- a/fe264ce1.6cd4155c.js +++ b/fe264ce1.58ec2a69.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[260],{412:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return l})),r.d(t,"metadata",(function(){return c})),r.d(t,"rightToc",(function(){return u})),r.d(t,"default",(function(){return p}));var o=r(1),n=r(9),a=(r(0),r(422)),l={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery your Google Cloud Platform account",description:"Learn how to install Qovery on your Google Cloud Platform (GCP) account",author_github:"https://github.com/evoxmusic",tags:["type: guide","cloud_provider: gcp"]},c={categories:[{name:"cloud-provider",title:"Cloud Provider",description:"Install Qovery on your favorite cloud provider.",permalink:"/guides/cloud-provider"}],coverLabel:"Install Qovery your Google Cloud Platform account",description:"Learn how to install Qovery on your Google Cloud Platform (GCP) account",permalink:"/guides/cloud-provider/guide-google-cloud-platform",readingTime:"1 min read",source:"@site/guides/cloud-provider/guide-google-cloud-platform.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"cloud_provider: gcp",permalink:"/guides/tags/cloud-provider-gcp"}],title:"Install Qovery your Google Cloud Platform account",truncated:!1,prevItem:{title:"Install Qovery on your Scaleway account",permalink:"/guides/cloud-provider/guide-scaleway"},nextItem:{title:"Integrate your application logs to Cloudwatch",permalink:"/guides/tutorial/cloudwatch-integration"}},u=[],i={rightToc:u};function p(e){var t=e.components,r=Object(n.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},i,r,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Thank you for your interest! You are more and more to request the support of Qovery for ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://cloud.google.com/"}),"Google Cloud Platform")," (GCP). However, we do not support it yet. You have 2 ways of speed up the support:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Upvote the support of Google Cloud Platform ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"https://roadmap.qovery.com/roadmap/support-google-cloud-platform-gcp"}),"here"),"."),Object(a.b)("li",{parentName:"ol"},"We are hiring backend and frontend engineers to build the future of the Cloud. It could be you? \ud83d\ude04 ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"https://jobs.qovery.com"}),"Apply here"))),Object(a.b)("p",null,"Today, Qovery supports the following Cloud providers:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/cloud-provider/guide-amazon-web-services/"}),"Amazon Web Services (AWS)")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/guides/cloud-provider/guide-scaleway/"}),"Scaleway"))))}p.isMDXComponent=!0},422:function(e,t,r){"use strict";r.d(t,"a",(function(){return d})),r.d(t,"b",(function(){return f}));var o=r(0),n=r.n(o);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function l(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function c(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var i=n.a.createContext({}),p=function(e){var t=n.a.useContext(i),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},d=function(e){var t=p(e.components);return n.a.createElement(i.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},m=Object(o.forwardRef)((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,i=u(e,["components","mdxType","originalType","parentName"]),d=p(r),m=o,f=d["".concat(l,".").concat(m)]||d[m]||s[m]||a;return r?n.a.createElement(f,c({ref:t},i,{components:r})):n.a.createElement(f,c({ref:t},i))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,l=new Array(a);l[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:o,l[1]=c;for(var i=2;i=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var i=n.a.createContext({}),p=function(e){var t=n.a.useContext(i),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},d=function(e){var t=p(e.components);return n.a.createElement(i.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return n.a.createElement(n.a.Fragment,{},t)}},m=Object(o.forwardRef)((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,i=u(e,["components","mdxType","originalType","parentName"]),d=p(r),m=o,f=d["".concat(l,".").concat(m)]||d[m]||s[m]||a;return r?n.a.createElement(f,c({ref:t},i,{components:r})):n.a.createElement(f,c({ref:t},i))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,l=new Array(a);l[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c.mdxType="string"==typeof e?e:o,l[1]=c;for(var i=2;i ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Connect to Qovery")),Object(o.b)("h3",{id:"create-your-organization"},"Create your Organization"),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"You can skip this step if you already have an Organization.")),Object(o.b)("p",null,"An organization is a shared account where developers can collaborate across many projects at once. Owners and organization administrators can manage:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Cloud accounts."),Object(o.b)("li",{parentName:"ul"},"Members access."),Object(o.b)("li",{parentName:"ul"},"Billing.")),Object(o.b)("p",null,Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/"}),"Read more")," about Organizations"),Object(o.b)("p",null,"To deploy on your Scaleway account, you have to choose between ",Object(o.b)("strong",{parentName:"p"},"Free"),", ",Object(o.b)("strong",{parentName:"p"},"Professional")," and ",Object(o.b)("strong",{parentName:"p"},"Business")," plan for your organization."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/organization/Qovery_Pricing_Plans.png",alt:"Qovery - Create an Organization and select the plan"})),Object(o.b)("h3",{id:"install-qovery-on-your-scaleway-account"},"Install Qovery on your Scaleway account"),Object(o.b)("p",null,'1/ Go to your organization settings by clicking on the "cog" icon next to your organization name.'),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/organization_settings_clusters_empty.jpg",alt:"Go your organization settings > clusters"})),Object(o.b)("p",null,"2/ Create a cluster, select ",Object(o.b)("em",{parentName:"p"},"Scaleway")," and the region where you want to deploy your apps."),Object(o.b)(i.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"Choose a region close to where your users will use your applications to have better performances.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/organization_settings_create_cluster.jpg",alt:"Create a cluster"})),Object(o.b)("p",null,"3/ Set your Scaleway credentials. (Check out ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/scaleway/"}),"this guide")," if you have no Scaleway credentials)."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/organization_settings_add_credentials.jpg",alt:"Set your cloud credentials"})),Object(o.b)("p",null,"4/ Under the hood, Qovery uses a managed Kubernetes (",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.scaleway.com/en/kubernetes-kapsule/"}),"Scaleway Kapsule"),") to run your applications. You need to specify the CPU and RAM you want per node, and the min/max number of nodes. Qovery will keep low the number of nodes and will only scale up your nodes if your applications really need to scale."),Object(o.b)(i.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"Qovery optimizes and keep your Scaleway costs low.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/organization_settings_cluster_resources.jpg",alt:"Set your cluster resources"})),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},"Qovery might use some temporary free resources on your Kubernetes cluster to perform spotted maintenance operations (e.g. : cluster version upgrades). This is why we recommend a cluster setup with:",Object(o.b)("ul",null,Object(o.b)("li",null,"at least 20% difference between the minimum and the maximum number of nodes;"),Object(o.b)("li",null,"at least 5 nodes as the maximum number of nodes of your cluster;"))),Object(o.b)("p",null,"5/ Click on ",Object(o.b)("strong",{parentName:"p"},"Save")," and ",Object(o.b)("strong",{parentName:"p"},"Deploy"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/organization_settings_clusters_scaleway.jpg",alt:"Scaleway cluster is now available"})),Object(o.b)("p",null,"Congrats! Qovery will be installed within 10 minutes \ud83c\udf89. You will be notified when it is all good.\nIn the meantime, you can take a look at our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"guide section"),"."),Object(o.b)("h2",{id:"deploy-your-application"},"Deploy your application"),Object(o.b)("p",null,"Once Qovery is installed on your Scaleway account, you have the possibility to deploy your application. Take a look to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"our guide")," on how to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"deploy your first application")," with Qovery."),Object(o.b)(c.a,{to:"/guides/getting-started/deploy-your-first-application",mdxType:"Jump"},"Deploy your first application"))}y.isMDXComponent=!0},420:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var u=r.a.createContext({}),s=function(e){var t=r.a.useContext(u),a=t;return e&&(a="function"==typeof e?e(t):i({},t,{},e)),a},p=function(e){var t=s(e.components);return r.a.createElement(u.Provider,{value:t},e.children)},y={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(a),b=n,d=p["".concat(c,".").concat(b)]||p[b]||y[b]||o;return a?r.a.createElement(d,i({ref:t},u,{components:a})):r.a.createElement(d,i({ref:t},u))}));function d(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,c=new Array(o);c[0]=b;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var u=2;u1?arguments[1]:void 0,a),l=c>2?arguments[2]:void 0,u=void 0===l?a:r(l,a);u>i;)t[i++]=e;return t}},425:function(e,t,a){var n=a(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,a){"use strict";a(425);var n=a(0),r=a.n(n),o=a(421);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},427:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),c=a(39),i=a(430),l=a(20),u=a.n(l);t.a=function(e){var t,a=e.to,l=e.href,s=a||l,p=Object(i.a)(s),y=Object(r.useRef)(!1),b=u.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!b&&p&&window.docusaurus.prefetch(s),function(){b&&t&&t.disconnect()}}),[s,b,p]),s&&p?o.a.createElement(c.b,Object(n.a)({},e,{onMouseEnter:function(){y.current||(window.docusaurus.preload(s),y.current=!0)},innerRef:function(e){var a,n;b&&e&&p&&(a=e,n=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:s})):o.a.createElement("a",Object(n.a)({},e,{href:s}))}},428:function(e,t,a){"use strict";var n=a(432),r=a(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var a=function(e){var t;switch(e.arrayFormat){case"index":return function(e,a,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=a):n[e]=a};case"bracket":return function(e,a,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],a):n[e]=[a]:n[e]=a};default:return function(e,t,a){void 0!==a[e]?a[e]=[].concat(a[e],t):a[e]=t}}}(t=r({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),a(decodeURIComponent(r),o,n)})),Object.keys(n).sort().reduce((function(e,t){var a=n[t];return Boolean(a)&&"object"==typeof a&&!Array.isArray(a)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(a):e[t]=a,e}),Object.create(null))):n},t.stringify=function(e,t){var a=function(e){switch(e.arrayFormat){case"index":return function(t,a,n){return null===a?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(a,e)].join("")};case"bracket":return function(t,a){return null===a?o(t,e):[o(t,e),"[]=",o(a,e)].join("")};default:return function(t,a){return null===a?o(t,e):[o(t,e),"=",o(a,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var r=e[n];if(void 0===r)return"";if(null===r)return o(n,t);if(Array.isArray(r)){var c=[];return r.slice().forEach((function(e){void 0!==e&&c.push(a(n,e,c.length))})),c.join("&")}return o(n,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},429:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(427),c=a(420),i=a.n(c);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,c=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,p=e.to,y=i()("jump-to","jump-to--"+u,a),b=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?r.a.createElement("a",{href:p,target:s,className:y},b):r.a.createElement(o.a,{to:p,className:y},b)}},430:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},431:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=(a(420),a(428)),c=a.n(o);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(n.useState)(null),p=s[0],y=s[1];return r.a.createElement("div",{className:"steps steps--h"+a},t,!o&&!p&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return y("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,a){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see ff053ed0.1ea41e6b.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[264],{416:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return l})),a.d(t,"metadata",(function(){return u})),a.d(t,"rightToc",(function(){return s})),a.d(t,"default",(function(){return y}));var n=a(1),r=a(9),o=(a(0),a(425)),c=a(431),i=(a(434),a(429),a(424)),l={last_modified_on:"2023-06-05",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Scaleway account",description:"Learn how to install Qovery on your Scaleway account",author_github:"https://github.com/evoxmusic",tags:["type: guide","cloud_provider: scaleway"]},u={categories:[{name:"cloud-provider",title:"Cloud Provider",description:"Install Qovery on your favorite cloud provider.",permalink:"/guides/cloud-provider"}],coverLabel:"Install Qovery on your Scaleway account",description:"Learn how to install Qovery on your Scaleway account",permalink:"/guides/cloud-provider/guide-scaleway",readingTime:"5 min read",source:"@site/guides/cloud-provider/guide-scaleway.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"cloud_provider: scaleway",permalink:"/guides/tags/cloud-provider-scaleway"}],title:"Install Qovery on your Scaleway account",truncated:!1,prevItem:{title:"Install Qovery on your Microsoft Azure account",permalink:"/guides/cloud-provider/guide-microsoft-azure"},nextItem:{title:"Install Qovery your Google Cloud Platform account",permalink:"/guides/cloud-provider/guide-google-cloud-platform"}},s=[{value:"Before you start",id:"before-you-start",children:[{value:"What is Qovery",id:"what-is-qovery",children:[]},{value:"Why you should use Scaleway",id:"why-you-should-use-scaleway",children:[]},{value:"Why you should not use Scaleway",id:"why-you-should-not-use-scaleway",children:[]}]},{value:"Create a Scaleway account",id:"create-a-scaleway-account",children:[{value:"Get your Scaleway API keys",id:"get-your-scaleway-api-keys",children:[]}]},{value:"Configure Qovery",id:"configure-qovery",children:[{value:"Sign-up to Qovery",id:"sign-up-to-qovery",children:[]},{value:"Create your Organization",id:"create-your-organization",children:[]},{value:"Install Qovery on your Scaleway account",id:"install-qovery-on-your-scaleway-account",children:[]}]},{value:"Deploy your application",id:"deploy-your-application",children:[]}],p={rightToc:s};function y(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},p,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.scaleway.com?ref=qovery"}),"Scaleway")," (SCW) is a platform that offers flexible, reliable, and scalable Cloud computing solutions. The platform is developed with a combination of infrastructure as a service (IaaS), platform as a service (PaaS), and packaged software as a service (SaaS) offerings."),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.qovery.com"}),"Qovery")," is the simplest way to deploy your apps on Scaleway.")),Object(o.b)("p",null,"In this tutorial, I will explain step by step how to deploy your app on Scaleway in 10 minutes. No Scaleway/infrastructure/Cloud knowledge required - no kidding!"),Object(o.b)("h2",{id:"before-you-start"},"Before you start"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"This tutorial is perfect for anyone interested into deploying their apps on Scaleway seamlessly."),Object(o.b)("li",{parentName:"ol"},"If you have any question or suggestion on this tutorial, please contact us via ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.qovery.com/contact"}),"this form")," or ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://discord.qovery.com"}),"Discord"),".")),Object(o.b)("h3",{id:"what-is-qovery"},"What is Qovery"),Object(o.b)("p",null,'Qovery is a platform that makes your app deployment on Scaleway very simple. The installation of Qovery on your Scaleway account takes approximately 10 minutes. Then you\'re ready to deploy your apps "\xe0 la" Heroku-like..'),Object(o.b)("h3",{id:"why-you-should-use-scaleway"},"Why you should use Scaleway"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You want to use a European Cloud provider \ud83c\uddea\ud83c\uddfa."),Object(o.b)("li",{parentName:"ul"},"You want to stay focus on what you are building."),Object(o.b)("li",{parentName:"ul"},"You need to speed up your Go-To-Market and Product Market Fit."),Object(o.b)("li",{parentName:"ul"},"You are looking for a cheapest alternative to AWS.")),Object(o.b)("h3",{id:"why-you-should-not-use-scaleway"},"Why you should not use Scaleway"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You need to host your applications outside of Europe."),Object(o.b)("li",{parentName:"ul"},"You need to use MongoDB in production. (They do not have managed MongoDB)."),Object(o.b)("li",{parentName:"ul"},"You need any specific AWS, GCP or Azure services.")),Object(o.b)("p",null,"Let's start!"),Object(o.b)("h1",{id:"install-qovery-on-scaleway"},"Install Qovery on Scaleway"),Object(o.b)("h2",{id:"create-a-scaleway-account"},"Create a Scaleway account"),Object(o.b)("p",null,Object(o.b)("em",{parentName:"p"},"If you already have a Scaleway account, you can go to the next point.")),Object(o.b)("p",null,"Before creating a Scaleway account, I'd recommend contacting Scaleway to see if you are eligible to free credits. Which is convenient to have at the beginning of a project. If you know that you are not eligible, you can create your account by clicking on the top right button ",Object(o.b)("inlineCode",{parentName:"p"},"Create an Scaleway Account")," of their ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.scaleway.com?ref=qovery"}),"main page"),"."),Object(o.b)("img",{src:"/img/scaleway-create-an-account.jpg",alt:"Create an account on Scaleway"}),Object(o.b)("h3",{id:"get-your-scaleway-api-keys"},"Get your Scaleway API keys"),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/scaleway/"}),"this guide")," to create your Scaleway credentials")),Object(o.b)("p",null,"To install Qovery on your Scaleway account, the ",Object(o.b)("inlineCode",{parentName:"p"},"project id"),", ",Object(o.b)("inlineCode",{parentName:"p"},"secret access key")," and ",Object(o.b)("inlineCode",{parentName:"p"},"access key id")," are required. Here is a comprehensive ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/scaleway/"}),"step-by-step guide")," on how to generate your ",Object(o.b)("inlineCode",{parentName:"p"},"secret access key")," and ",Object(o.b)("inlineCode",{parentName:"p"},"access key id"),". If you already have those keys, then you can go to the next point."),Object(o.b)("h2",{id:"configure-qovery"},"Configure Qovery"),Object(o.b)("h3",{id:"sign-up-to-qovery"},"Sign-up to Qovery"),Object(o.b)("p",null,"Using Qovery is as simple as connect with your ",Object(o.b)("em",{parentName:"p"},"Github"),", ",Object(o.b)("em",{parentName:"p"},"Gitlab")," or ",Object(o.b)("em",{parentName:"p"},"Bitbucket")," account on ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"console.qovery.com"),"."),Object(o.b)("p",null,"-> ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://start.qovery.com"}),"Connect to Qovery")),Object(o.b)("h3",{id:"create-your-organization"},"Create your Organization"),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"You can skip this step if you already have an Organization.")),Object(o.b)("p",null,"An organization is a shared account where developers can collaborate across many projects at once. Owners and organization administrators can manage:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Cloud accounts."),Object(o.b)("li",{parentName:"ul"},"Members access."),Object(o.b)("li",{parentName:"ul"},"Billing.")),Object(o.b)("p",null,Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/"}),"Read more")," about Organizations"),Object(o.b)("p",null,"To deploy on your Scaleway account, you have to choose between ",Object(o.b)("strong",{parentName:"p"},"Free"),", ",Object(o.b)("strong",{parentName:"p"},"Professional")," and ",Object(o.b)("strong",{parentName:"p"},"Business")," plan for your organization."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/organization/Qovery_Pricing_Plans.png",alt:"Qovery - Create an Organization and select the plan"})),Object(o.b)("h3",{id:"install-qovery-on-your-scaleway-account"},"Install Qovery on your Scaleway account"),Object(o.b)("p",null,'1/ Go to your organization settings by clicking on the "cog" icon next to your organization name.'),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/organization_settings_clusters_empty.jpg",alt:"Go your organization settings > clusters"})),Object(o.b)("p",null,"2/ Create a cluster, select ",Object(o.b)("em",{parentName:"p"},"Scaleway")," and the region where you want to deploy your apps."),Object(o.b)(i.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"Choose a region close to where your users will use your applications to have better performances.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/organization_settings_create_cluster.jpg",alt:"Create a cluster"})),Object(o.b)("p",null,"3/ Set your Scaleway credentials. (Check out ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cloud-service-provider/scaleway/"}),"this guide")," if you have no Scaleway credentials)."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/organization_settings_add_credentials.jpg",alt:"Set your cloud credentials"})),Object(o.b)("p",null,"4/ Under the hood, Qovery uses a managed Kubernetes (",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.scaleway.com/en/kubernetes-kapsule/"}),"Scaleway Kapsule"),") to run your applications. You need to specify the CPU and RAM you want per node, and the min/max number of nodes. Qovery will keep low the number of nodes and will only scale up your nodes if your applications really need to scale."),Object(o.b)(i.a,{type:"success",mdxType:"Alert"},Object(o.b)("p",null,"Qovery optimizes and keep your Scaleway costs low.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/organization_settings_cluster_resources.jpg",alt:"Set your cluster resources"})),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},"Qovery might use some temporary free resources on your Kubernetes cluster to perform spotted maintenance operations (e.g. : cluster version upgrades). This is why we recommend a cluster setup with:",Object(o.b)("ul",null,Object(o.b)("li",null,"at least 20% difference between the minimum and the maximum number of nodes;"),Object(o.b)("li",null,"at least 5 nodes as the maximum number of nodes of your cluster;"))),Object(o.b)("p",null,"5/ Click on ",Object(o.b)("strong",{parentName:"p"},"Save")," and ",Object(o.b)("strong",{parentName:"p"},"Deploy"),"."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/organization_settings_clusters_scaleway.jpg",alt:"Scaleway cluster is now available"})),Object(o.b)("p",null,"Congrats! Qovery will be installed within 10 minutes \ud83c\udf89. You will be notified when it is all good.\nIn the meantime, you can take a look at our ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"guide section"),"."),Object(o.b)("h2",{id:"deploy-your-application"},"Deploy your application"),Object(o.b)("p",null,"Once Qovery is installed on your Scaleway account, you have the possibility to deploy your application. Take a look to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/"}),"our guide")," on how to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"deploy your first application")," with Qovery."),Object(o.b)(c.a,{to:"/guides/getting-started/deploy-your-first-application",mdxType:"Jump"},"Deploy your first application"))}y.isMDXComponent=!0},423:function(e,t,a){var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var u=r.a.createContext({}),s=function(e){var t=r.a.useContext(u),a=t;return e&&(a="function"==typeof e?e(t):i({},t,{},e)),a},p=function(e){var t=s(e.components);return r.a.createElement(u.Provider,{value:t},e.children)},y={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},b=Object(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(a),b=n,d=p["".concat(c,".").concat(b)]||p[b]||y[b]||o;return a?r.a.createElement(d,i({ref:t},u,{components:a})):r.a.createElement(d,i({ref:t},u))}));function d(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,c=new Array(o);c[0]=b;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var u=2;u1?arguments[1]:void 0,a),l=c>2?arguments[2]:void 0,u=void 0===l?a:r(l,a);u>i;)t[i++]=e;return t}},428:function(e,t,a){var n=a(28).f,r=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in r||a(10)&&n(r,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,a){"use strict";a(428);var n=a(0),r=a.n(n),o=a(424);t.a=function(e){var t=e.children,a=e.name;return r.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",a||"page"," assumes the following:"),t)}},430:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),c=a(39),i=a(432),l=a(20),u=a.n(l);t.a=function(e){var t,a=e.to,l=e.href,s=a||l,p=Object(i.a)(s),y=Object(r.useRef)(!1),b=u.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!b&&p&&window.docusaurus.prefetch(s),function(){b&&t&&t.disconnect()}}),[s,b,p]),s&&p?o.a.createElement(c.b,Object(n.a)({},e,{onMouseEnter:function(){y.current||(window.docusaurus.preload(s),y.current=!0)},innerRef:function(e){var a,n;b&&e&&p&&(a=e,n=function(){window.docusaurus.prefetch(s)},(t=new window.IntersectionObserver((function(e){e.forEach((function(e){a===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(t.unobserve(a),t.disconnect(),n())}))}))).observe(a))},to:s})):o.a.createElement("a",Object(n.a)({},e,{href:s}))}},431:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(430),c=a(423),i=a.n(c);a(133);t.a=function(e){var t=e.children,a=e.className,n=e.badge,c=e.leftIcon,l=e.rightIcon,u=e.size,s=e.target,p=e.to,y=i()("jump-to","jump-to--"+u,a),b=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},c&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+c})),r.a.createElement("div",{className:"jump-to--main"},n?r.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",t),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(l||"chevron-right")+" arrow"}))));return s?r.a.createElement("a",{href:p,target:s,className:y},b):r.a.createElement(o.a,{to:p,className:y},b)}},432:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},433:function(e,t,a){"use strict";var n=a(435),r=a(51);function o(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var a=function(e){var t;switch(e.arrayFormat){case"index":return function(e,a,n){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=a):n[e]=a};case"bracket":return function(e,a,n){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],a):n[e]=[a]:n[e]=a};default:return function(e,t,a){void 0!==a[e]?a[e]=[].concat(a[e],t):a[e]=t}}}(t=r({arrayFormat:"none"},t)),n=Object.create(null);return"string"!=typeof e?n:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),r=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),a(decodeURIComponent(r),o,n)})),Object.keys(n).sort().reduce((function(e,t){var a=n[t];return Boolean(a)&&"object"==typeof a&&!Array.isArray(a)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(a):e[t]=a,e}),Object.create(null))):n},t.stringify=function(e,t){var a=function(e){switch(e.arrayFormat){case"index":return function(t,a,n){return null===a?[o(t,e),"[",n,"]"].join(""):[o(t,e),"[",o(n,e),"]=",o(a,e)].join("")};case"bracket":return function(t,a){return null===a?o(t,e):[o(t,e),"[]=",o(a,e)].join("")};default:return function(t,a){return null===a?o(t,e):[o(t,e),"=",o(a,e)].join("")}}}(t=r({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(n){var r=e[n];if(void 0===r)return"";if(null===r)return o(n,t);if(Array.isArray(r)){var c=[];return r.slice().forEach((function(e){void 0!==e&&c.push(a(n,e,c.length))})),c.join("&")}return o(n,t)+"="+o(r,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=(a(423),a(433)),c=a.n(o);a(134);t.a=function(e){var t=e.children,a=e.headingDepth,o=e.hideFeedbackQuestion,i="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+i+" failed",body:"The tutorial on:\n\n"+i+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(n.useState)(null),p=s[0],y=s[1];return r.a.createElement("div",{className:"steps steps--h"+a},t,!o&&!p&&r.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",r.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return y("yes")}},"Yes"),"\xa0\xa0",r.a.createElement("a",{href:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&r.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",r.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,a){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/ff91a867.a3d34bea.js.LICENSE.txt b/ff053ed0.1ea41e6b.js.LICENSE.txt similarity index 100% rename from ff91a867.a3d34bea.js.LICENSE.txt rename to ff053ed0.1ea41e6b.js.LICENSE.txt diff --git a/a4401f0f.1cd779ba.js b/ff0cde69.39cbc8bf.js similarity index 93% rename from a4401f0f.1cd779ba.js rename to ff0cde69.39cbc8bf.js index 10005cda19..6621236b02 100644 --- a/a4401f0f.1cd779ba.js +++ b/ff0cde69.39cbc8bf.js @@ -1,2 +1,2 @@ -/*! For license information please see a4401f0f.1cd779ba.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[160],{312:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),o=(n(0),n(422)),i=n(426),c=n(431),l={last_modified_on:"2021-07-22",$schema:"/.meta/.schemas/guides.json",title:"Creating API clients using OpenAPI Tools",description:"How to quickly create a Qovery API client in your language",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Creating API clients using OpenAPI Tools",description:"How to quickly create a Qovery API client in your language",permalink:"/guides/tutorial/generate-qovery-api-client",readingTime:"4 min read",source:"@site/guides/tutorial/generate-qovery-api-client.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Creating API clients using OpenAPI Tools",truncated:!1,prevItem:{title:"Create your Staging environment from your Production environment on AWS",permalink:"/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws"},nextItem:{title:"Customizing Preview URL with Qovery CLI",permalink:"/guides/tutorial/customizing-preview-url-with-qovery-cli"}},u=[{value:"Integration",id:"integration",children:[{value:"Generating API client code",id:"generating-api-client-code",children:[]},{value:"Steps",id:"steps",children:[]},{value:"Under the hood",id:"under-the-hood",children:[]},{value:"Example",id:"example",children:[]}]},{value:"Summary",id:"summary",children:[]}],p={rightToc:u};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"While releasing the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/blog/one-week-before-the-launch-of-qovery-v2-beta-whats-new#open-api"}),"latest major update of Qovery"),", we realized that we need to open our API to our users in order to make them able to\nbuild integrations and customizations they need in their development workflows. This month, we launched a BETA version of the Qovery V2 platform, and alongside this, we ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"made our beta API open")," and ready to play with and experiment."),Object(o.b)("h2",{id:"integration"},"Integration"),Object(o.b)("p",null,"To integrate with the new API, one has a choice of reading the documentation and doing all the necessary plumbing by himself. However, at Qovery, we value developer experience, so we decided to make this process easier and more streamlined."),Object(o.b)("h3",{id:"generating-api-client-code"},"Generating API client code"),Object(o.b)("p",null,"Our API specification is made in a way that makes it very easy to generate API clients in ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/OpenAPITools/openapi-generator#overview"}),"any of the many supported languages"),". We also prepared a script to make this process seamless - all you need to do is to clone our open API repository and run one command to generate the newest client version."),Object(o.b)("h3",{id:"steps"},"Steps"),Object(o.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have installed ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://nodejs.org/en/"}),"Node/NPM")),Object(o.b)("li",{parentName:"ul"},"You have installed ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://github.com/OpenAPITools/openapi-generator#17---npm"}),"Open API Generator")))),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"clone-the-repository"},"Clone the repository"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"$ git clone https://github.com/Qovery/qovery-openapi-spec.git\n$ cd qovery-openapi-spec\n"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"generate-the-client-code"},"Generate the client code"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"$ QOVERY_CLIENT_LANGUAGE=go npm run generate\n")),Object(o.b)("p",null,"where: ",Object(o.b)("strong",{parentName:"p"},"$QOVERY_CLIENT_LANGUAGE")," is the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/OpenAPITools/openapi-generator#overview"}),"language of your choice"),".")),Object(o.b)("li",null,Object(o.b)("h4",{id:"list-the-generated-files"},"List the generated files"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"$ ls out/client\n")),Object(o.b)("p",null,"This folder contains all the files necessary to interact with ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API"),", as well as its documentation. To use it in your project, you can create a repository to store the client files and then import them as a dependency in your project. This part is highly dependant on the language and technology you are using, so it's not covered in this post.")))),Object(o.b)("h3",{id:"under-the-hood"},"Under the hood"),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"npm run generate -- $LANGUAGE")," command under the hood uses the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/OpenAPITools/openapi-generator"}),"open-api-generator")," and a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://swagger.io/specification/"}),"Open API specification")," created to define Qovery API.\nYou can see the specification after cloning ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-openapi-spec"}),"our open api repository")," and running ",Object(o.b)("inlineCode",{parentName:"p"},"npm run build")," in ",Object(o.b)("inlineCode",{parentName:"p"},"_build/openapi.yaml")," file."),Object(o.b)("p",null,"The clients are generated using the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github/OpenAPITools/openapi-generator"}),"open-api-generator")," and the specification file - ",Object(o.b)("inlineCode",{parentName:"p"},"_build/openapi.yaml"),"."),Object(o.b)("h3",{id:"example"},"Example"),Object(o.b)("p",null,"As an example of generated API client, let's use the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli"}),"Qovery CLI"),". The ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/using-qovery/interface/cli/"}),"command-line interface")," of Qovery is using a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-client-go"}),"Go API Client")," that was generated following the steps from this article.\nAfter generating the client, we simply published the ",Object(o.b)("inlineCode",{parentName:"p"},"out/client")," folder as a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-client-go"}),"Git Repository")," and then simply imported the code in the CLI application as a dependency:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-go"}),'package utils\n\nimport (\n "github.com/qovery/qovery-client-go"\n)\n')),Object(o.b)("p",null,"This allowed us to use the generated client code to interact with ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API")," very easily:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-go"}),'token, err := GetAccessToken()\nif err != nil {\n return err\n}\n\nauth := context.WithValue(context.Background(), qovery.ContextAccessToken, string(token))\nclient := qovery.NewAPIClient(qovery.NewConfiguration())\n\norganizations, res, err := client.OrganizationMainCallsApi.ListOrganization(auth).Execute()\nif err != nil {\n return err\n}\nif res.StatusCode >= 400 {\n return errors.New("Received " + res.Status + " response while listing organizations. ")\n}\n')),Object(o.b)("h2",{id:"summary"},"Summary"),Object(o.b)("p",null,Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-openapi-spec.git"}),"Qovery Open API specification")," allows creating ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API")," stubs extremely quickly. At Qovery, we officially support only ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-client-go"}),"Golang Client"),", but if you use a different language, you can generate your own client in a matter of seconds following the steps of this article."))}b.isMDXComponent=!0},420:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=r,h=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return n?a.a.createElement(h,c({ref:t},s,{components:n})):a.a.createElement(h,c({ref:t},s))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>c;)t[c++]=e;return t}},425:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},426:function(e,t,n){"use strict";n(425);var r=n(0),a=n.n(r),o=n(421);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},428:function(e,t,n){"use strict";var r=n(432),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},431:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(420),n(428)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(r.useState)(null),p=u[0],b=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},432:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file +/*! For license information please see ff0cde69.39cbc8bf.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[265],{417:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),o=(n(0),n(425)),i=n(429),c=n(434),l={last_modified_on:"2021-07-22",$schema:"/.meta/.schemas/guides.json",title:"Creating API clients using OpenAPI Tools",description:"How to quickly create a Qovery API client in your language",author_github:"https://github.com/pjeziorowski",tags:["type: tutorial","technology: qovery"],hide_pagination:!0},s={categories:[{name:"tutorial",title:"Tutorial",description:"Additional step-by-step resources to leverage even more Qovery",permalink:"/guides/tutorial"}],coverLabel:"Creating API clients using OpenAPI Tools",description:"How to quickly create a Qovery API client in your language",permalink:"/guides/tutorial/generate-qovery-api-client",readingTime:"4 min read",source:"@site/guides/tutorial/generate-qovery-api-client.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Creating API clients using OpenAPI Tools",truncated:!1,prevItem:{title:"Create your Staging environment from your Production environment on AWS",permalink:"/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws"},nextItem:{title:"Customizing Preview URL with Qovery CLI",permalink:"/guides/tutorial/customizing-preview-url-with-qovery-cli"}},u=[{value:"Integration",id:"integration",children:[{value:"Generating API client code",id:"generating-api-client-code",children:[]},{value:"Steps",id:"steps",children:[]},{value:"Under the hood",id:"under-the-hood",children:[]},{value:"Example",id:"example",children:[]}]},{value:"Summary",id:"summary",children:[]}],p={rightToc:u};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"While releasing the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/blog/one-week-before-the-launch-of-qovery-v2-beta-whats-new#open-api"}),"latest major update of Qovery"),", we realized that we need to open our API to our users in order to make them able to\nbuild integrations and customizations they need in their development workflows. This month, we launched a BETA version of the Qovery V2 platform, and alongside this, we ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"made our beta API open")," and ready to play with and experiment."),Object(o.b)("h2",{id:"integration"},"Integration"),Object(o.b)("p",null,"To integrate with the new API, one has a choice of reading the documentation and doing all the necessary plumbing by himself. However, at Qovery, we value developer experience, so we decided to make this process easier and more streamlined."),Object(o.b)("h3",{id:"generating-api-client-code"},"Generating API client code"),Object(o.b)("p",null,"Our API specification is made in a way that makes it very easy to generate API clients in ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/OpenAPITools/openapi-generator#overview"}),"any of the many supported languages"),". We also prepared a script to make this process seamless - all you need to do is to clone our open API repository and run one command to generate the newest client version."),Object(o.b)("h3",{id:"steps"},"Steps"),Object(o.b)(i.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have installed ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://nodejs.org/en/"}),"Node/NPM")),Object(o.b)("li",{parentName:"ul"},"You have installed ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"https://github.com/OpenAPITools/openapi-generator#17---npm"}),"Open API Generator")))),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"clone-the-repository"},"Clone the repository"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"$ git clone https://github.com/Qovery/qovery-openapi-spec.git\n$ cd qovery-openapi-spec\n"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"generate-the-client-code"},"Generate the client code"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"$ QOVERY_CLIENT_LANGUAGE=go npm run generate\n")),Object(o.b)("p",null,"where: ",Object(o.b)("strong",{parentName:"p"},"$QOVERY_CLIENT_LANGUAGE")," is the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/OpenAPITools/openapi-generator#overview"}),"language of your choice"),".")),Object(o.b)("li",null,Object(o.b)("h4",{id:"list-the-generated-files"},"List the generated files"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"$ ls out/client\n")),Object(o.b)("p",null,"This folder contains all the files necessary to interact with ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API"),", as well as its documentation. To use it in your project, you can create a repository to store the client files and then import them as a dependency in your project. This part is highly dependant on the language and technology you are using, so it's not covered in this post.")))),Object(o.b)("h3",{id:"under-the-hood"},"Under the hood"),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"npm run generate -- $LANGUAGE")," command under the hood uses the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/OpenAPITools/openapi-generator"}),"open-api-generator")," and a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://swagger.io/specification/"}),"Open API specification")," created to define Qovery API.\nYou can see the specification after cloning ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-openapi-spec"}),"our open api repository")," and running ",Object(o.b)("inlineCode",{parentName:"p"},"npm run build")," in ",Object(o.b)("inlineCode",{parentName:"p"},"_build/openapi.yaml")," file."),Object(o.b)("p",null,"The clients are generated using the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github/OpenAPITools/openapi-generator"}),"open-api-generator")," and the specification file - ",Object(o.b)("inlineCode",{parentName:"p"},"_build/openapi.yaml"),"."),Object(o.b)("h3",{id:"example"},"Example"),Object(o.b)("p",null,"As an example of generated API client, let's use the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli"}),"Qovery CLI"),". The ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/using-qovery/interface/cli/"}),"command-line interface")," of Qovery is using a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-client-go"}),"Go API Client")," that was generated following the steps from this article.\nAfter generating the client, we simply published the ",Object(o.b)("inlineCode",{parentName:"p"},"out/client")," folder as a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-client-go"}),"Git Repository")," and then simply imported the code in the CLI application as a dependency:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-go"}),'package utils\n\nimport (\n "github.com/qovery/qovery-client-go"\n)\n')),Object(o.b)("p",null,"This allowed us to use the generated client code to interact with ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API")," very easily:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-go"}),'token, err := GetAccessToken()\nif err != nil {\n return err\n}\n\nauth := context.WithValue(context.Background(), qovery.ContextAccessToken, string(token))\nclient := qovery.NewAPIClient(qovery.NewConfiguration())\n\norganizations, res, err := client.OrganizationMainCallsApi.ListOrganization(auth).Execute()\nif err != nil {\n return err\n}\nif res.StatusCode >= 400 {\n return errors.New("Received " + res.Status + " response while listing organizations. ")\n}\n')),Object(o.b)("h2",{id:"summary"},"Summary"),Object(o.b)("p",null,Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-openapi-spec.git"}),"Qovery Open API specification")," allows creating ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://api-doc.qovery.com/"}),"Qovery API")," stubs extremely quickly. At Qovery, we officially support only ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-client-go"}),"Golang Client"),", but if you use a different language, you can generate your own client in a matter of seconds following the steps of this article."))}b.isMDXComponent=!0},423:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),u=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=r,h=p["".concat(i,".").concat(d)]||p[d]||b[d]||o;return n?a.a.createElement(h,c({ref:t},s,{components:n})):a.a.createElement(h,c({ref:t},s))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:a(l,n);s>c;)t[c++]=e;return t}},428:function(e,t,n){var r=n(28).f,a=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},429:function(e,t,n){"use strict";n(428);var r=n(0),a=n.n(r),o=n(424);t.a=function(e){var t=e.children,n=e.name;return a.a.createElement(o.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},433:function(e,t,n){"use strict";var r=n(435),a=n(51);function o(e,t){return t.encode?t.strict?r(e):encodeURIComponent(e):e}t.extract=function(e){return e.split("?")[1]||""},t.parse=function(e,t){var n=function(e){var t;switch(e.arrayFormat){case"index":return function(e,n,r){t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===r[e]&&(r[e]={}),r[e][t[1]]=n):r[e]=n};case"bracket":return function(e,n,r){t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==r[e]?r[e]=[].concat(r[e],n):r[e]=[n]:r[e]=n};default:return function(e,t,n){void 0!==n[e]?n[e]=[].concat(n[e],t):n[e]=t}}}(t=a({arrayFormat:"none"},t)),r=Object.create(null);return"string"!=typeof e?r:(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var t=e.replace(/\+/g," ").split("="),a=t.shift(),o=t.length>0?t.join("="):void 0;o=void 0===o?null:decodeURIComponent(o),n(decodeURIComponent(a),o,r)})),Object.keys(r).sort().reduce((function(e,t){var n=r[t];return Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((function(e,t){return Number(e)-Number(t)})).map((function(e){return t[e]})):t}(n):e[t]=n,e}),Object.create(null))):r},t.stringify=function(e,t){var n=function(e){switch(e.arrayFormat){case"index":return function(t,n,r){return null===n?[o(t,e),"[",r,"]"].join(""):[o(t,e),"[",o(r,e),"]=",o(n,e)].join("")};case"bracket":return function(t,n){return null===n?o(t,e):[o(t,e),"[]=",o(n,e)].join("")};default:return function(t,n){return null===n?o(t,e):[o(t,e),"=",o(n,e)].join("")}}}(t=a({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var a=e[r];if(void 0===a)return"";if(null===a)return o(r,t);if(Array.isArray(a)){var i=[];return a.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return o(r,t)+"="+o(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},434:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(423),n(433)),i=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,c="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+c+" failed",body:"The tutorial on:\n\n"+c+"\n\nHere's what went wrong:\n\n\x3c!-- Insert command output and details. Thank you for reporting! :) --\x3e"},s="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(l),u=Object(r.useState)(null),p=u[0],b=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!p&&a.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",a.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&a.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",a.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},435:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}}}]); \ No newline at end of file diff --git a/ff0cde69.39cbc8bf.js.LICENSE.txt b/ff0cde69.39cbc8bf.js.LICENSE.txt new file mode 100644 index 0000000000..bae6dd8e22 --- /dev/null +++ b/ff0cde69.39cbc8bf.js.LICENSE.txt @@ -0,0 +1,5 @@ +/*! + Copyright (c) 2017 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames +*/ diff --git a/ff91a867.a3d34bea.js b/ff91a867.1e27550c.js similarity index 51% rename from ff91a867.a3d34bea.js rename to ff91a867.1e27550c.js index c41395fba8..682a007575 100644 --- a/ff91a867.a3d34bea.js +++ b/ff91a867.1e27550c.js @@ -1,2 +1,2 @@ -/*! For license information please see ff91a867.a3d34bea.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[263],{415:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return l})),t.d(n,"metadata",(function(){return u})),t.d(n,"rightToc",(function(){return g})),t.d(n,"default",(function(){return p}));var a=t(1),r=t(9),i=(t(0),t(422)),o=t(421),c=t(429),s=t(426),l={last_modified_on:"2023-09-12",title:"Organization",description:"Learn how to configure Organizations on Qovery",sidebar_label:"hidden"},u={id:"using-qovery/configuration/organization",title:"Organization",description:"Learn how to configure Organizations on Qovery",source:"@site/docs/using-qovery/configuration/organization.md",permalink:"/docs/using-qovery/configuration/organization",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Configuration",permalink:"/docs/using-qovery/configuration"},next:{title:"Members and RBAC",permalink:"/docs/using-qovery/configuration/organization/members-rbac"}},g=[{value:"Creating an Organization",id:"creating-an-organization",children:[{value:"When Signing Up",id:"when-signing-up",children:[]},{value:"After Signing Up",id:"after-signing-up",children:[]}]},{value:"Change an Organization",id:"change-an-organization",children:[]},{value:"Delete an Organization",id:"delete-an-organization",children:[]},{value:"Billing",id:"billing",children:[]},{value:"Organization admin settings",id:"organization-admin-settings",children:[{value:"General Information",id:"general-information",children:[]},{value:"Other Settings",id:"other-settings",children:[]}]}],b={rightToc:g};function p(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},b,t,{components:n,mdxType:"MDXLayout"}),Object(i.b)(s.a,{name:"documentation",mdxType:"Assumptions"},Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"You have a ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/interface/"}),"created an account"),"."))),Object(i.b)("p",null,"An organization is a shared account where developers can collaborate across many projects at once. Owners and organization administrators\ncan manage every aspect of the organization, from the clusters up to the member access."),Object(i.b)("h2",{id:"creating-an-organization"},"Creating an Organization"),Object(i.b)("h3",{id:"when-signing-up"},"When Signing Up"),Object(i.b)("p",null,"When signing up for Qovery, you need to sign in through your Git provider (GitHub, GitLab or Bitbucket). "),Object(i.b)("p",null,"Once this is done, you can create your first organization and the first project within it. Before completing the creation process, you need to choose one of our 3 plans:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Free"),Object(i.b)("li",{parentName:"ul"},"Team"),Object(i.b)("li",{parentName:"ul"},"Enterprise")),Object(i.b)("p",null,"For more information, see ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/pricing"}),"our pricing page"),"."),Object(i.b)("h3",{id:"after-signing-up"},"After Signing Up"),Object(i.b)("p",null,"Qovery lets you create as many as you want organizations. Each organization is independent of the others.\nTo create a new organization:"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"Click on your profile icon button on the left navbar."),Object(i.b)("li",{parentName:"ol"},"Click on the ",Object(i.b)("inlineCode",{parentName:"li"},"+")," button in the top right corner of the dropdown.")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/organization/create_organization_after_signing_up.png",alt:"Qovery - create organization after signing up"})),Object(i.b)("h2",{id:"change-an-organization"},"Change an Organization"),Object(i.b)("p",null,"As a user, you can have access to one or many organizations. Use the dropdown on the bottom left of the navbar to change your organization."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/organization/change_organization.png",alt:"Qovery - change organization"})),Object(i.b)("h2",{id:"delete-an-organization"},"Delete an Organization"),Object(i.b)(o.a,{type:"danger",mdxType:"Alert"},Object(i.b)("p",null,"This is a non-recoverable operation. By deleting your organization, all your data are deleted.")),Object(i.b)("p",null,"To delete your organization, you need to go into the ",Object(i.b)("strong",{parentName:"p"},"Danger Zone")," within your organization settings."),Object(i.b)("h2",{id:"billing"},"Billing"),Object(i.b)("p",null,"This section allows you to retrieve your invoices and as well manage the credit card used for the payments."),Object(i.b)(o.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"To know more on how much Qovery costs - see our ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/pricing"}),"pricing page"),".")),Object(i.b)("h2",{id:"organization-admin-settings"},"Organization admin settings"),Object(i.b)("p",null,"You can access the organization settings using the ",Object(i.b)("inlineCode",{parentName:"p"},"Wheel")," button on the left nav bar"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/organization/access_settings.png",alt:"How to access your organization settings"})),Object(i.b)("h3",{id:"general-information"},"General Information"),Object(i.b)("p",null,"In the ",Object(i.b)("inlineCode",{parentName:"p"},"General Information")," tab:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Company name"),": enter the name of your company."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Description"),": enter a description of your organization."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Website"),": enter the website of your company."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Admin contact emails"),": enter one or several email addresses (separated by commas) on which you want to receive important communications from Qovery.")),Object(i.b)(o.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"We will ",Object(i.b)("strong",{parentName:"p"},"only")," use your admin contact email details to send you communications about infrastructure outages, maintenance updates, and weekly and monthly usage reports.")),Object(i.b)("p",null,"Don't forget to click ",Object(i.b)("inlineCode",{parentName:"p"},"Update")," to save your organization information!"),Object(i.b)("h3",{id:"other-settings"},"Other Settings"),Object(i.b)("p",null,"You can find below a dedicated page for each of the admin settings that can be managed within this section."),Object(i.b)(c.a,{to:"/docs/using-qovery/configuration/organization/api-token/",mdxType:"Jump"},"Api token"),Object(i.b)(c.a,{to:"/docs/using-qovery/configuration/organization/container-registry/",mdxType:"Jump"},"Container registry"),Object(i.b)(c.a,{to:"/docs/using-qovery/configuration/organization/git-repository-access/",mdxType:"Jump"},"Git repository access"),Object(i.b)(c.a,{to:"/docs/using-qovery/configuration/organization/members-rbac/",mdxType:"Jump"},"Members rbac"))}p.isMDXComponent=!0},420:function(e,n,t){var a;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=r.a.createContext({}),u=function(e){var n=r.a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):c({},n,{},e)),t},g=function(e){var n=u(e.components);return r.a.createElement(l.Provider,{value:n},e.children)},b={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},p=Object(a.forwardRef)((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,o=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),g=u(t),p=a,m=g["".concat(o,".").concat(p)]||g[p]||b[p]||i;return t?r.a.createElement(m,c({ref:n},l,{components:t})):r.a.createElement(m,c({ref:n},l))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=p;var c={};for(var s in n)hasOwnProperty.call(n,s)&&(c[s]=n[s]);c.originalType=e,c.mdxType="string"==typeof e?e:a,o[1]=c;for(var l=2;l1?arguments[1]:void 0,t),s=o>2?arguments[2]:void 0,l=void 0===s?t:r(s,t);l>c;)n[c++]=e;return n}},425:function(e,n,t){var a=t(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||t(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},426:function(e,n,t){"use strict";t(425);var a=t(0),r=t.n(a),i=t(421);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},427:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),c=t(430),s=t(20),l=t.n(s);n.a=function(e){var n,t=e.to,s=e.href,u=t||s,g=Object(c.a)(u),b=Object(r.useRef)(!1),p=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&g&&window.docusaurus.prefetch(u),function(){p&&n&&n.disconnect()}}),[u,p,g]),u&&g?i.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var t,a;p&&e&&g&&(t=e,a=function(){window.docusaurus.prefetch(u)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),a())}))}))).observe(t))},to:u})):i.a.createElement("a",Object(a.a)({},e,{href:u}))}},429:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(427),o=t(420),c=t.n(o);t(133);n.a=function(e){var n=e.children,t=e.className,a=e.badge,o=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,g=e.to,b=c()("jump-to","jump-to--"+l,t),p=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},o&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+o})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",n),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:g,target:u,className:b},p):r.a.createElement(i.a,{to:g,className:b},p)}},430:function(e,n,t){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return a}))}}]); \ No newline at end of file +/*! For license information please see ff91a867.1e27550c.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[266],{418:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return l})),t.d(n,"metadata",(function(){return u})),t.d(n,"rightToc",(function(){return g})),t.d(n,"default",(function(){return p}));var a=t(1),r=t(9),i=(t(0),t(425)),o=t(424),c=t(431),s=t(429),l={last_modified_on:"2023-11-30",title:"Organization",description:"Learn how to configure Organizations on Qovery",sidebar_label:"hidden"},u={id:"using-qovery/configuration/organization",title:"Organization",description:"Learn how to configure Organizations on Qovery",source:"@site/docs/using-qovery/configuration/organization.md",permalink:"/docs/using-qovery/configuration/organization",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Configuration",permalink:"/docs/using-qovery/configuration"},next:{title:"Members and RBAC",permalink:"/docs/using-qovery/configuration/organization/members-rbac"}},g=[{value:"Creating an Organization",id:"creating-an-organization",children:[{value:"When Signing Up",id:"when-signing-up",children:[]},{value:"After Signing Up",id:"after-signing-up",children:[]}]},{value:"Change an Organization",id:"change-an-organization",children:[]},{value:"Delete an Organization",id:"delete-an-organization",children:[]},{value:"Billing",id:"billing",children:[]},{value:"Organization admin settings",id:"organization-admin-settings",children:[{value:"General Information",id:"general-information",children:[]},{value:"Other Settings",id:"other-settings",children:[]}]}],b={rightToc:g};function p(e){var n=e.components,t=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},b,t,{components:n,mdxType:"MDXLayout"}),Object(i.b)(s.a,{name:"documentation",mdxType:"Assumptions"},Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"You have a ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/using-qovery/interface/"}),"created an account"),"."))),Object(i.b)("p",null,"An organization is a shared account where developers can collaborate across many projects at once. Owners and organization administrators\ncan manage every aspect of the organization, from the clusters up to the member access."),Object(i.b)("h2",{id:"creating-an-organization"},"Creating an Organization"),Object(i.b)("h3",{id:"when-signing-up"},"When Signing Up"),Object(i.b)("p",null,"When signing up for Qovery, you need to sign in through your Git provider (GitHub, GitLab or Bitbucket). "),Object(i.b)("p",null,"Once this is done, you can create your first organization and the first project within it. Before completing the creation process, you need to choose one of our 3 plans:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Free"),Object(i.b)("li",{parentName:"ul"},"Team"),Object(i.b)("li",{parentName:"ul"},"Enterprise")),Object(i.b)("p",null,"For more information, see ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/pricing"}),"our pricing page"),"."),Object(i.b)("h3",{id:"after-signing-up"},"After Signing Up"),Object(i.b)("p",null,"Qovery lets you create as many as you want organizations. Each organization is independent of the others.\nTo create a new organization:"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"Click on your profile icon button on the left navbar."),Object(i.b)("li",{parentName:"ol"},"Click on the ",Object(i.b)("inlineCode",{parentName:"li"},"+")," button in the top right corner of the dropdown.")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/organization/create_organization_after_signing_up.png",alt:"Qovery - create organization after signing up"})),Object(i.b)("h2",{id:"change-an-organization"},"Change an Organization"),Object(i.b)("p",null,"As a user, you can have access to one or many organizations. Use the dropdown on the bottom left of the navbar to change your organization."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/organization/change_organization.png",alt:"Qovery - change organization"})),Object(i.b)("h2",{id:"delete-an-organization"},"Delete an Organization"),Object(i.b)(o.a,{type:"danger",mdxType:"Alert"},Object(i.b)("p",null,"This is a non-recoverable operation. By deleting your organization, all your data are deleted.")),Object(i.b)("p",null,"To delete your organization, you need to go into the ",Object(i.b)("strong",{parentName:"p"},"Danger Zone")," within your organization settings."),Object(i.b)("h2",{id:"billing"},"Billing"),Object(i.b)("p",null,"This section allows you to retrieve your invoices and as well manage the credit card used for the payments."),Object(i.b)(o.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"To know more on how much Qovery costs - see our ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.qovery.com/pricing"}),"pricing page"),".")),Object(i.b)("h2",{id:"organization-admin-settings"},"Organization admin settings"),Object(i.b)("p",null,"You can access the organization settings using the ",Object(i.b)("inlineCode",{parentName:"p"},"Wheel")," button on the left nav bar"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/organization/access_settings.png",alt:"How to access your organization settings"})),Object(i.b)("h3",{id:"general-information"},"General Information"),Object(i.b)("p",null,"In the ",Object(i.b)("inlineCode",{parentName:"p"},"General Information")," tab:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Company name"),": enter the name of your company."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Description"),": enter a description of your organization."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Website"),": enter the website of your company."),Object(i.b)("li",{parentName:"ul"},Object(i.b)("strong",{parentName:"li"},"Admin contact emails"),": enter one or several email addresses (separated by commas) on which you want to receive important communications from Qovery.")),Object(i.b)(o.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"We will ",Object(i.b)("strong",{parentName:"p"},"only")," use your admin contact email details to send you communications about infrastructure outages, maintenance updates, and weekly and monthly usage reports.")),Object(i.b)("p",null,"Don't forget to click ",Object(i.b)("inlineCode",{parentName:"p"},"Update")," to save your organization information!"),Object(i.b)("h3",{id:"other-settings"},"Other Settings"),Object(i.b)("p",null,"You can find below a dedicated page for each of the admin settings that can be managed within this section."),Object(i.b)(c.a,{to:"/docs/using-qovery/configuration/organization/api-token/",mdxType:"Jump"},"Api token"),Object(i.b)(c.a,{to:"/docs/using-qovery/configuration/organization/container-registry/",mdxType:"Jump"},"Container registry"),Object(i.b)(c.a,{to:"/docs/using-qovery/configuration/organization/git-repository-access/",mdxType:"Jump"},"Git repository access"),Object(i.b)(c.a,{to:"/docs/using-qovery/configuration/organization/helm-repository/",mdxType:"Jump"},"Helm repository"),Object(i.b)(c.a,{to:"/docs/using-qovery/configuration/organization/members-rbac/",mdxType:"Jump"},"Members rbac"))}p.isMDXComponent=!0},423:function(e,n,t){var a;!function(){"use strict";var t={}.hasOwnProperty;function r(){for(var e=[],n=0;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=r.a.createContext({}),u=function(e){var n=r.a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):c({},n,{},e)),t},g=function(e){var n=u(e.components);return r.a.createElement(l.Provider,{value:n},e.children)},b={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},p=Object(a.forwardRef)((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,o=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),g=u(t),p=a,m=g["".concat(o,".").concat(p)]||g[p]||b[p]||i;return t?r.a.createElement(m,c({ref:n},l,{components:t})):r.a.createElement(m,c({ref:n},l))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=p;var c={};for(var s in n)hasOwnProperty.call(n,s)&&(c[s]=n[s]);c.originalType=e,c.mdxType="string"==typeof e?e:a,o[1]=c;for(var l=2;l1?arguments[1]:void 0,t),s=o>2?arguments[2]:void 0,l=void 0===s?t:r(s,t);l>c;)n[c++]=e;return n}},428:function(e,n,t){var a=t(28).f,r=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in r||t(10)&&a(r,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(e){return""}}})},429:function(e,n,t){"use strict";t(428);var a=t(0),r=t.n(a),i=t(424);n.a=function(e){var n=e.children,t=e.name;return r.a.createElement(i.a,{type:"info",fill:!0,icon:!1,rounded:!0,className:"list--icons list--icons--arrow list--tight list--indent margin-bottom--lg"},r.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",t||"page"," assumes the following:"),n)}},430:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),c=t(432),s=t(20),l=t.n(s);n.a=function(e){var n,t=e.to,s=e.href,u=t||s,g=Object(c.a)(u),b=Object(r.useRef)(!1),p=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&g&&window.docusaurus.prefetch(u),function(){p&&n&&n.disconnect()}}),[u,p,g]),u&&g?i.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){b.current||(window.docusaurus.preload(u),b.current=!0)},innerRef:function(e){var t,a;p&&e&&g&&(t=e,a=function(){window.docusaurus.prefetch(u)},(n=new window.IntersectionObserver((function(e){e.forEach((function(e){t===e.target&&(e.isIntersecting||e.intersectionRatio>0)&&(n.unobserve(t),n.disconnect(),a())}))}))).observe(t))},to:u})):i.a.createElement("a",Object(a.a)({},e,{href:u}))}},431:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(430),o=t(423),c=t.n(o);t(133);n.a=function(e){var n=e.children,t=e.className,a=e.badge,o=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,g=e.to,b=c()("jump-to","jump-to--"+l,t),p=r.a.createElement("div",{className:"jump-to--inner"},r.a.createElement("div",{className:"jump-to--inner-2"},o&&r.a.createElement("div",{className:"jump-to--left"},r.a.createElement("i",{className:"feather icon-"+o})),r.a.createElement("div",{className:"jump-to--main"},a?r.a.createElement("span",{className:"badge badge--primary badge--right"},a):"",n),r.a.createElement("div",{className:"jump-to--right"},r.a.createElement("i",{className:"feather icon-"+(s||"chevron-right")+" arrow"}))));return u?r.a.createElement("a",{href:g,target:u,className:b},p):r.a.createElement(i.a,{to:g,className:b},p)}},432:function(e,n,t){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}t.d(n,"a",(function(){return a}))}}]); \ No newline at end of file diff --git a/ff91a867.1e27550c.js.LICENSE.txt b/ff91a867.1e27550c.js.LICENSE.txt new file mode 100644 index 0000000000..bae6dd8e22 --- /dev/null +++ b/ff91a867.1e27550c.js.LICENSE.txt @@ -0,0 +1,5 @@ +/*! + Copyright (c) 2017 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames +*/ diff --git a/guides/advanced/continuous-integration/index.html b/guides/advanced/continuous-integration/index.html index 5ca6c8ac5a..3eb759ba85 100644 --- a/guides/advanced/continuous-integration/index.html +++ b/guides/advanced/continuous-integration/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              2 min read
                                                                              Updated

                                                                              Qovery integrates with all existing Continuous Integration platforms. We have a guide for the most popular CI platforms. However, even if you don't find your CI platform, you can see here that integrating Qovery into a CI is just a matter of:

                                                                              1. Adding a new step into your CI pipeline
                                                                              2. Installing the Qovery CLI
                                                                              3. Running the qovery <application|container|lifecycle|cronjob> deploy ... commands

                                                                              Resources

                                                                              Here are some resources you can use to integrate Qovery into your CI platform:

                                                                              TitleDescriptionAuthor
                                                                              Step-by-step guide to integrate GitHub ActionsStep-by-step guide to learn how to integrate GitHub Actions with QoveryQovery
                                                                              Integrate GitHub ActionsLearn how to integrate GitHub Actions with QoveryQovery
                                                                              Integrate GitLab CILearn how to integrate GitLab CI with QoveryQovery
                                                                              Integrate Circle CILearn how to integrate Circle CI with QoveryQovery
                                                                              Integrate JenkinsLearn how to integrate Jenkins with QoveryQovery
                                                                              Forum "GitHub Actions"List "GitHub Actions" threads from Qovery community forumCommunity
                                                                              Forum "GitLab CI"List "GitLab CI" threads from Qovery community forumCommunity
                                                                              Forum "Circle CI"List "Circle CI" threads from Qovery community forumCommunity
                                                                              Forum "Jenkins"List "Jenkins" threads from Qovery community forumCommunity

                                                                              Q&A

                                                                              Do you need more examples? Do you have any questions? Feel free to ask on our Community forum.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/advanced/costs-control/index.html b/guides/advanced/costs-control/index.html index 0fc6c759df..9c4a0c37aa 100644 --- a/guides/advanced/costs-control/index.html +++ b/guides/advanced/costs-control/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              1 min read
                                                                              Updated
                                                                              Contents

                                                                              Q&A

                                                                              Do you need more examples? Do you have any questions? Feel free to ask on our Community forum.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/advanced/deploy-api-gateway/index.html b/guides/advanced/deploy-api-gateway/index.html index 2dc70f672d..924bdb7cc2 100644 --- a/guides/advanced/deploy-api-gateway/index.html +++ b/guides/advanced/deploy-api-gateway/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              1 min read
                                                                              Updated

                                                                              An API Gateway is a web service that acts as an interface between consumers and your services. It acts as a single point of entry into a system and is responsible for request routing, composition, and protocol translation. It's essentially a middleman that processes requests from clients to services.

                                                                              Resources

                                                                              Here are some resources you can use to deploy your API Gateway with Qovery

                                                                              TitleDescriptionAuthor
                                                                              NGINX API GatewayDeploy a NGINX API Gateway with QoveryQovery
                                                                              Forum "API Gateway"List "API Gateway" threads from Qovery community forumCommunity

                                                                              Q&A

                                                                              Do you need more examples? Do you have any questions? Feel free to ask on our Community forum.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/advanced/deploy-aws-services/index.html b/guides/advanced/deploy-aws-services/index.html index b78cee1ba7..32bf27cafd 100644 --- a/guides/advanced/deploy-aws-services/index.html +++ b/guides/advanced/deploy-aws-services/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              2 min read
                                                                              Updated
                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/advanced/deploy-external-services/index.html b/guides/advanced/deploy-external-services/index.html index 0378bc0311..02ee3de7cf 100644 --- a/guides/advanced/deploy-external-services/index.html +++ b/guides/advanced/deploy-external-services/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              1 min read
                                                                              Updated
                                                                              Contents

                                                                              Q&A

                                                                              Do you need more examples? Do you have any questions? Feel free to ask on our Community forum.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/advanced/deploy-frontend/index.html b/guides/advanced/deploy-frontend/index.html index f8fb7a2e79..74260e39ff 100644 --- a/guides/advanced/deploy-frontend/index.html +++ b/guides/advanced/deploy-frontend/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -51,21 +51,21 @@ You can change them in your app advanced settings.

                                                                              TitleDescriptionAuthor
                                                                              Deploy SPA containerDeploy your frontend SPA (React) app inside a container with a NGINX web serverQovery
                                                                              Deploy SPA container with CloudfrontDeploy your frontend SPA (React) app inside a container with a NGINX web server and expose it via Cloudfront CDNQovery
                                                                              Use Cloudflare as a CDNUse Cloudflare as a CDN for your frontend SPA (React) appQovery
                                                                              Deploy SSR containerDeploy your frontend SSR (NextJS) app inside a container with a NGINX web serverQovery
                                                                              Deploy SSR on CloudfrontDeploy your frontend SSR (NextJS) app on AWS CloudfrontQovery
                                                                              "React" forum threadsList "React" threads from Qovery community forumCommunity
                                                                              "NextJS" forum threadsList "NextJS" threads from Qovery community forumCommunity
                                                                              "Angular" forum threadsList "Angular" threads from Qovery community forumCommunity

                                                                              Q&A

                                                                              Do you need more examples? Do you have any questions? Feel free to ask on our Community forum.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/advanced/helm-chart/index.html b/guides/advanced/helm-chart/index.html index 7a85e10d0c..9c6e2625d4 100644 --- a/guides/advanced/helm-chart/index.html +++ b/guides/advanced/helm-chart/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              1 min read
                                                                              Updated

                                                                              Qovery runs on top of Kubernetes and allows you to deploy any Helm chart on your cluster. To learn more about Helm, please visit the official website.

                                                                              Resources

                                                                              Here are some resources you can use to deploy your Helm Charts with Qovery.

                                                                              TitleDescriptionOfficial
                                                                              Deploy your Helm ChartsHow to deploy your Helm Charts (example with Kubecost)Yes
                                                                              ForumList "Helm Charts" threads from Qovery community forumno

                                                                              Q&A

                                                                              Do you need more examples? Do you have any questions? Feel free to ask on our Community forum.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/advanced/index.html b/guides/advanced/index.html index 07286c14f9..4421ef1e44 100644 --- a/guides/advanced/index.html +++ b/guides/advanced/index.html @@ -21,54 +21,54 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -77,51 +77,51 @@
                                                                              - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/advanced/microservices/index.html b/guides/advanced/microservices/index.html index 0325578f62..1c0dae699d 100644 --- a/guides/advanced/microservices/index.html +++ b/guides/advanced/microservices/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -56,21 +56,21 @@
                                                                              export default axios.create({
                                                                              baseURL: process.env.apiUrl
                                                                              })

                                                                              After providing the configuration from above, deploy your frontend application.

                                                                              Now our frontend application will be able to consume the API exposed by the publicly exposed APP_A.

                                                                              Summary

                                                                              In this guide, we deployed two microservices that communicate over the internal network. We also deployed a frontend application that makes use of a public API exposed by one of our applications. At the same time, we deployed a database and connected it to the second of our backend microservices.

                                                                              Q&A

                                                                              Do you need more examples? Do you have any questions? Feel free to ask on our Community forum.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/advanced/migration/index.html b/guides/advanced/migration/index.html index 6c0976665b..8e203fbddc 100644 --- a/guides/advanced/migration/index.html +++ b/guides/advanced/migration/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              2 min read
                                                                              Updated

                                                                              You plan to migrate to AWS (Amazon Web Services), GCP (Google Cloud Platform) or Microsoft Azure with Qovery? This guide is for you.

                                                                              Resources

                                                                              Here are some resources you can use to migrate your applications to your favorite cloud provider with Qovery.

                                                                              TitleDescriptionAuthor
                                                                              Migrate from Heroku to AWSComplete guide to migrate from Heroku to AWS with QoveryQovery
                                                                              Migration checklistComprehensive migration checklist to read before migrating your applications with Qovery (coming soon)Qovery
                                                                              ForumList "Migration" threads from Qovery community forumCommunity

                                                                              Migration assistance

                                                                              Qovery provides a migration assistance to help you migrate your applications with Qovery. Contact us via the Qovery Console and ask for migration assistance via the chat.

                                                                              Q&A

                                                                              Do you need more examples? Do you have any questions? Feel free to ask on our Community forum.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/advanced/monitoring/index.html b/guides/advanced/monitoring/index.html index eeb5c8b651..69c6ac8142 100644 --- a/guides/advanced/monitoring/index.html +++ b/guides/advanced/monitoring/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              1 min read
                                                                              Updated
                                                                              Contents
                                                                              • Prometheus & Grafana
                                                                              • Datadog

                                                                              Q&A

                                                                              Do you need more examples? Do you have any questions? Feel free to ask on our Community forum.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/advanced/monorepository/index.html b/guides/advanced/monorepository/index.html index ca77be607b..8cc01ad25b 100644 --- a/guides/advanced/monorepository/index.html +++ b/guides/advanced/monorepository/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -49,21 +49,21 @@ It allows you to run multiple applications using the same source code in different modes.

                                                                              You can set up secret or env variables in your application Environment Variables section:

                                                                              Monorepository

                                                                              Q&A

                                                                              Do you need more examples? Do you have any questions? Feel free to ask on our Community forum.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/advanced/production/index.html b/guides/advanced/production/index.html index dfecd1700d..f5aa98eb02 100644 --- a/guides/advanced/production/index.html +++ b/guides/advanced/production/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              1 min read
                                                                              Updated
                                                                              Contents

                                                                              Q&A

                                                                              Do you need more examples? Do you have any questions? Feel free to ask on our Community forum.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/advanced/seed-database/index.html b/guides/advanced/seed-database/index.html index 2b7a0b49f7..34611db850 100644 --- a/guides/advanced/seed-database/index.html +++ b/guides/advanced/seed-database/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -49,21 +49,21 @@ Qovery provides multiple ways to seed your database.

                                                                              Resources

                                                                              Here are some resources you can use to seed your database with Qovery.

                                                                              TitleDescriptionAuthor
                                                                              Seed your database with a SQL script (simple)Seed your database with a SQL script and a Docker ENTRYPOINT instructionQovery
                                                                              Seed your database with a SQL script (advanced)Seed your database with a SQL script and a Lifecycle JobQovery
                                                                              Seed your database with Replibyte (advanced)Seed your database with Replibyte and a Lifecycle JobQovery
                                                                              Migrate your database schemaMigrate your database schema with a Docker ENTRYPOINT instructionQovery
                                                                              ForumList "Seed Database" threads from Qovery community forumCommunity

                                                                              Q&A

                                                                              Do you need more examples? Do you have any questions? Feel free to ask on our Community forum.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/advanced/terraform/index.html b/guides/advanced/terraform/index.html index 1e4c4bab71..f83c54d248 100644 --- a/guides/advanced/terraform/index.html +++ b/guides/advanced/terraform/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              1 min read
                                                                              Updated
                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/advanced/use-preview-environments/index.html b/guides/advanced/use-preview-environments/index.html index 6d286c4a2d..61b777918b 100644 --- a/guides/advanced/use-preview-environments/index.html +++ b/guides/advanced/use-preview-environments/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -50,21 +50,21 @@ E.g. you may need to run Environments to get early feedback on your application changes before the changes are merged into production. This is what we call Preview Environment.

                                                                              Sometimes Preview Environment is also known as Ephemeral Environment, Temporary Environment, Development Environment, Review App.

                                                                              Recommendations

                                                                              If you are using Qovery to run your Production, we recommend using Preview Environments on a separate cluster. This will ensure that your Production is not impacted by the Preview Environments and vice versa.

                                                                              Resources

                                                                              Here are some resources you can use to use and take advantage of Qovery Preview Environments:

                                                                              TitleDescriptionAuthor
                                                                              Getting Started with Preview EnvironmentLearn how to get started with Qovery Preview EnvironmentsQovery
                                                                              Customize preview URLLearn how to customize your Preview URL with the Qovery CLIQovery
                                                                              Automatically stop unused Preview EnvironmentsLearn how to automatically teardown your Preview Environments on a specific scheduleQovery
                                                                              Build E2E Testing Ephemeral Environments with GitHub Actions and QoveryStep-by-step guide to build e2e testing ephemeral environments with GitHub Actions and QoveryQovery
                                                                              Forum "Preview Environment"List "Preview Environments" threads from Qovery community forumCommunity

                                                                              Q&A

                                                                              Do you need more examples? Do you have any questions? Feel free to ask on our Community forum.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/cloud-provider/guide-amazon-web-services/index.html b/guides/cloud-provider/guide-amazon-web-services/index.html index 928cb17e15..64fa81fa03 100644 --- a/guides/cloud-provider/guide-amazon-web-services/index.html +++ b/guides/cloud-provider/guide-amazon-web-services/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -49,21 +49,21 @@ Click 👉 here 👈 to follow the white rabbit 🐇

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/cloud-provider/guide-google-cloud-platform/index.html b/guides/cloud-provider/guide-google-cloud-platform/index.html index 815145a20d..b825ad9df4 100644 --- a/guides/cloud-provider/guide-google-cloud-platform/index.html +++ b/guides/cloud-provider/guide-google-cloud-platform/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              1 min read
                                                                              Updated

                                                                              Thank you for your interest! You are more and more to request the support of Qovery for Google Cloud Platform (GCP). However, we do not support it yet. You have 2 ways of speed up the support:

                                                                              1. Upvote the support of Google Cloud Platform here.
                                                                              2. We are hiring backend and frontend engineers to build the future of the Cloud. It could be you? 😄 Apply here

                                                                              Today, Qovery supports the following Cloud providers:

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/cloud-provider/guide-microsoft-azure/index.html b/guides/cloud-provider/guide-microsoft-azure/index.html index 575aea518c..5bd21a5712 100644 --- a/guides/cloud-provider/guide-microsoft-azure/index.html +++ b/guides/cloud-provider/guide-microsoft-azure/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              1 min read
                                                                              Updated

                                                                              Thank you for your interest! You are more and more to request the support of Qovery for Azure (Microsoft Azure). However, we do not support it yet. You have 2 ways of speed up the support:

                                                                              1. Upvote the support of Microsoft Azure here.
                                                                              2. We are hiring backend and frontend engineers to build the future of the Cloud. It could be you? 😄 Apply here

                                                                              Today, Qovery supports the following Cloud providers:

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/cloud-provider/guide-scaleway/index.html b/guides/cloud-provider/guide-scaleway/index.html index 7d27a077d3..aaae1b4810 100644 --- a/guides/cloud-provider/guide-scaleway/index.html +++ b/guides/cloud-provider/guide-scaleway/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -49,21 +49,21 @@ In the meantime, you can take a look at our guide section.

                                                                              Deploy your application

                                                                              Once Qovery is installed on your Scaleway account, you have the possibility to deploy your application. Take a look to our guide on how to deploy your first application with Qovery.

                                                                              Deploy your first application
                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/cloud-provider/index.html b/guides/cloud-provider/index.html index 8b3bbd930a..5273c86662 100644 --- a/guides/cloud-provider/index.html +++ b/guides/cloud-provider/index.html @@ -21,32 +21,32 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -55,29 +55,29 @@
                                                                              - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/getting-started/create-a-database/index.html b/guides/getting-started/create-a-database/index.html index 18e4b59ad6..edeb4672eb 100644 --- a/guides/getting-started/create-a-database/index.html +++ b/guides/getting-started/create-a-database/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -53,21 +53,21 @@
                                                                              // your can use your connection pool now ...

                                                                              Nothing more, well done! You can now be able to use your database.

                                                                              Next Steps

                                                                              Congratulations, your application has access to your PostgreSQL database. Now we will see how to add your custom domain to your service.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/getting-started/debugging/index.html b/guides/getting-started/debugging/index.html index f10024c83c..f4e5982ff9 100644 --- a/guides/getting-started/debugging/index.html +++ b/guides/getting-started/debugging/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -50,21 +50,21 @@ Qovery will provide easy integrations in the coming release. Check out our roadmap

                                                                              Do you need any help? Reach us on Discord

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/getting-started/deploy-your-first-application/index.html b/guides/getting-started/deploy-your-first-application/index.html index 3b31113070..be9a174c3e 100644 --- a/guides/getting-started/deploy-your-first-application/index.html +++ b/guides/getting-started/deploy-your-first-application/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              2 min read
                                                                              Updated

                                                                              Qovery is an easy way to deploy a full-stack application. Meaning, you can deploy a backend, frontend and a database seamlessly. In this guide, I'll show you how to deploy a template app.

                                                                              Step-by-step tutorial

                                                                              1. Sign up

                                                                                Sign in to the Qovery web interface.

                                                                                Qovery Sign-up page

                                                                              2. Install Qovery on your AWS account

                                                                                Here is a video showing how to install Qovery on your AWS account. (Check out our written tutorial here)

                                                                              3. Deploy your first application

                                                                                Here is a short video showing how to deploy your app with the Qovery Web interface.

                                                                              Next Steps

                                                                              To deploy your application, it's as simple as that. In the following article, we will see how to add a database. Let's get started!

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/getting-started/index.html b/guides/getting-started/index.html index 645c36060d..3e0993095e 100644 --- a/guides/getting-started/index.html +++ b/guides/getting-started/index.html @@ -21,34 +21,34 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -57,31 +57,31 @@
                                                                              - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/getting-started/managing-environment-variables/index.html b/guides/getting-started/managing-environment-variables/index.html index 8f3bd9fb3b..008017264b 100644 --- a/guides/getting-started/managing-environment-variables/index.html +++ b/guides/getting-started/managing-environment-variables/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -58,21 +58,21 @@ go to our detailed documentation.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/getting-started/setting-custom-domain/index.html b/guides/getting-started/setting-custom-domain/index.html index befb7400a9..b0be2ae438 100644 --- a/guides/getting-started/setting-custom-domain/index.html +++ b/guides/getting-started/setting-custom-domain/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -50,21 +50,21 @@ learn how to set up your domains on Qovery!

                                                                              Tutorial

                                                                              1. Add the domain to your app

                                                                              2. Configure your DNS

                                                                                Configure your DNS by adding a CNAME record pointing to the domain provided by Qovery in the previous step

                                                                                If you have multiple public ports (or you want to have them in the future), make sure you add a CNAME for both yourdomain.com and *.yourdomain.com.

                                                                                In this way:

                                                                                • your application default port will be accessible via the domain yourdomain.com or by a subdomain equal to the port name (portNameA.yourdomain.com).
                                                                                • the other application public port will be accessible via a subdomain equal to the portName (portNameB.yourdomain.com).

                                                                                See the port setup of your application for more information on the port name setup.

                                                                              3. Your domain is ready

                                                                                You need to restart your app to use your custom domain on your application.

                                                                              If you run into any trouble, find us on Discord. Our team and the community will be glad to help out.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/index.html b/guides/index.html index 50a57c62a7..16b2e9da46 100644 --- a/guides/index.html +++ b/guides/index.html @@ -21,156 +21,156 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -179,153 +179,153 @@

                                                                              Qovery Guides

                                                                              Thoughtful guides to help you get the most out of Qovery. Created and curated by the Qovery team.

                                                                              Cloud Provider

                                                                              Install Qovery on your favorite cloud provider.

                                                                              Provider

                                                                              Advanced

                                                                              Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.

                                                                              Tutorial

                                                                              Additional step-by-step resources to leverage even more Qovery
                                                                              tutorial

                                                                              Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS

                                                                              read now
                                                                              tutorial

                                                                              Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery

                                                                              read now
                                                                              tutorial

                                                                              Create a blazingly fast REST API in Rust (Part 1/2)

                                                                              read now
                                                                              tutorial

                                                                              Create a Playground Environment on AWS

                                                                              read now
                                                                              tutorial

                                                                              Create your Staging environment from your Production environment on AWS

                                                                              read now
                                                                              tutorial

                                                                              Creating API clients using OpenAPI Tools

                                                                              read now
                                                                              tutorial

                                                                              Customizing Preview URL with Qovery CLI

                                                                              read now
                                                                              tutorial

                                                                              Deploy Rails with PostgreSQL and Sidekiq

                                                                              read now
                                                                              tutorial

                                                                              Deploy Temporal on Kubernetes

                                                                              read now
                                                                              tutorial

                                                                              Getting Started with Preview Environments on AWS

                                                                              read now
                                                                              tutorial

                                                                              Grafana setup with Qovery

                                                                              read now
                                                                              tutorial

                                                                              How to activate SSO to connect to your EKS cluster

                                                                              read now
                                                                              tutorial

                                                                              How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1

                                                                              read now
                                                                              tutorial

                                                                              How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2

                                                                              read now
                                                                              tutorial

                                                                              How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3

                                                                              read now
                                                                              tutorial

                                                                              How to connect to a managed MongoDB instance on AWS

                                                                              read now
                                                                              tutorial

                                                                              How to connect to your EKS cluster with kubectl

                                                                              read now
                                                                              tutorial

                                                                              How to create an RDS instance through the AWS console

                                                                              read now
                                                                              tutorial

                                                                              How to deploy a Rust REST API application on AWS with ease

                                                                              read now
                                                                              tutorial

                                                                              How to deploy Helm charts

                                                                              read now
                                                                              tutorial

                                                                              How to integrate Qovery with GitHub Actions

                                                                              read now
                                                                              tutorial

                                                                              How to run commands before the application starts

                                                                              read now
                                                                              tutorial

                                                                              How to seed a Postgres database on a dev environment

                                                                              read now
                                                                              tutorial

                                                                              How to use CloudFront with a React frontend application on Qovery

                                                                              read now
                                                                              tutorial

                                                                              How to use Github Organizations with Qovery

                                                                              read now
                                                                              tutorial

                                                                              How To Use Lifecycle Job To Deploy Any Kind Of Resources

                                                                              read now
                                                                              tutorial

                                                                              How to write a Dockerfile

                                                                              read now
                                                                              tutorial

                                                                              Import your environment variables with the Qovery CLI

                                                                              read now
                                                                              tutorial

                                                                              Integrate your application logs to Cloudwatch

                                                                              read now
                                                                              tutorial

                                                                              Kubernetes observability and monitoring with Datadog

                                                                              read now
                                                                              tutorial

                                                                              Managing Environment Variables in React (create-react-app)

                                                                              read now
                                                                              tutorial

                                                                              Migrate your application from Heroku to AWS

                                                                              read now
                                                                              tutorial

                                                                              Setting up Cloudflare and Custom Domain on Qovery

                                                                              read now
                                                                              tutorial

                                                                              Setup VPC peering on AWS with Qovery

                                                                              read now
                                                                              tutorial

                                                                              URL Shortener API with Kotlin (Part 1/2)

                                                                              read now
                                                                              tutorial

                                                                              Use an API gateway in front of multiple services

                                                                              read now
                                                                              tutorial

                                                                              Use AWS IAM roles with Qovery

                                                                              read now
                                                                              tutorial

                                                                              Using Amazon SQS and Lambda on Qovery

                                                                              read now
                                                                              tutorial

                                                                              Working with Git Submodules

                                                                              read now
                                                                              tutorial

                                                                              Zero to Hero - How to deploy your apps on AWS in 30 minutes

                                                                              read now
                                                                              - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/provider/guide-kubernetes/index.html b/guides/provider/guide-kubernetes/index.html index 86e6cd5963..8384e0080b 100644 --- a/guides/provider/guide-kubernetes/index.html +++ b/guides/provider/guide-kubernetes/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              2 min read
                                                                              Updated

                                                                              In this guide, I'll explain step-by-step how to install Qovery on your Kubernetes cluster.

                                                                              Install Qovery

                                                                              helm install qovery

                                                                              Configure

                                                                              To configure Qovery you need to override your Helm values.yaml file. Here is the simple example of the configuration:

                                                                              values.yaml
                                                                              qovery:
                                                                              clusterId: set-by-customer
                                                                              apkKey: set-by-customer
                                                                              jwtToken: set-by-customer
                                                                              qovery-cluster-agent:
                                                                              enabled: true
                                                                              override_chart: qovery-cluster-agent
                                                                              qovery-shell-agent:
                                                                              enabled: true
                                                                              override_chart: qovery-shell-agent
                                                                              qovery-engine:
                                                                              enabled: false
                                                                              override_chart: qovery-engine
                                                                              ingress:
                                                                              ingress-nginx:
                                                                              enabled: false
                                                                              dns:
                                                                              external-dns:
                                                                              enabled: false
                                                                              logging:
                                                                              promtail:
                                                                              enabled: false
                                                                              loki:
                                                                              enabled: false
                                                                              certificates:
                                                                              cert-manager:
                                                                              enabled: false
                                                                              qovery-cert-manager-webhook:
                                                                              enabled: false
                                                                              cert-manager-configs:
                                                                              enabled: false
                                                                              aws:
                                                                              q-storageclass:
                                                                              enabled: false
                                                                              obersavability:
                                                                              metrics-server:
                                                                              enabled: false

                                                                              Qovery

                                                                              TODO

                                                                              Nginx

                                                                              TODO

                                                                              External DNS

                                                                              TODO

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/provider/index.html b/guides/provider/index.html index eff2138237..062800c277 100644 --- a/guides/provider/index.html +++ b/guides/provider/index.html @@ -21,26 +21,26 @@ - + - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@ - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/cloud-provider-aws/index.html b/guides/tags/cloud-provider-aws/index.html index 337b574a49..1c5a57e859 100644 --- a/guides/tags/cloud-provider-aws/index.html +++ b/guides/tags/cloud-provider-aws/index.html @@ -21,50 +21,50 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -73,47 +73,47 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/cloud-provider-azure/index.html b/guides/tags/cloud-provider-azure/index.html index c31c1800fd..47a19ec8b6 100644 --- a/guides/tags/cloud-provider-azure/index.html +++ b/guides/tags/cloud-provider-azure/index.html @@ -21,26 +21,26 @@ - + - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@ - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/cloud-provider-gcp/index.html b/guides/tags/cloud-provider-gcp/index.html index ceea53a813..8a0066b0c6 100644 --- a/guides/tags/cloud-provider-gcp/index.html +++ b/guides/tags/cloud-provider-gcp/index.html @@ -21,26 +21,26 @@ - + - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@ - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/cloud-provider-scaleway/index.html b/guides/tags/cloud-provider-scaleway/index.html index 1f64a311cd..6f40e122dd 100644 --- a/guides/tags/cloud-provider-scaleway/index.html +++ b/guides/tags/cloud-provider-scaleway/index.html @@ -21,26 +21,26 @@ - + - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@ - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/database-postgresql/index.html b/guides/tags/database-postgresql/index.html index c7429fdea2..df4b175f25 100644 --- a/guides/tags/database-postgresql/index.html +++ b/guides/tags/database-postgresql/index.html @@ -21,32 +21,32 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -55,29 +55,29 @@ - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/framework-rails/index.html b/guides/tags/framework-rails/index.html index 359be11eaa..9cc46b433b 100644 --- a/guides/tags/framework-rails/index.html +++ b/guides/tags/framework-rails/index.html @@ -21,26 +21,26 @@ - + - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@ - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/index.html b/guides/tags/index.html index 6f676ff90b..757c9f591f 100644 --- a/guides/tags/index.html +++ b/guides/tags/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -47,21 +47,21 @@ - + - + - + - + - + - + - + - + diff --git a/guides/tags/language-javascript/index.html b/guides/tags/language-javascript/index.html index c15771d9f3..5e5b080906 100644 --- a/guides/tags/language-javascript/index.html +++ b/guides/tags/language-javascript/index.html @@ -21,28 +21,28 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -51,25 +51,25 @@ - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/language-kotlin/index.html b/guides/tags/language-kotlin/index.html index 54e839da52..e2ea910e3f 100644 --- a/guides/tags/language-kotlin/index.html +++ b/guides/tags/language-kotlin/index.html @@ -21,28 +21,28 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -51,25 +51,25 @@ - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/language-ruby/index.html b/guides/tags/language-ruby/index.html index e963a6843c..653cbf2b85 100644 --- a/guides/tags/language-ruby/index.html +++ b/guides/tags/language-ruby/index.html @@ -21,26 +21,26 @@ - + - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@ - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/language-rust/index.html b/guides/tags/language-rust/index.html index addbfb4752..9718934c1f 100644 --- a/guides/tags/language-rust/index.html +++ b/guides/tags/language-rust/index.html @@ -21,30 +21,30 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@ - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/provider-kubernetes/index.html b/guides/tags/provider-kubernetes/index.html index 3bc5445269..96bf1be761 100644 --- a/guides/tags/provider-kubernetes/index.html +++ b/guides/tags/provider-kubernetes/index.html @@ -21,26 +21,26 @@ - + - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@ - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/technology-docker/index.html b/guides/tags/technology-docker/index.html index f55425e266..9e8e463796 100644 --- a/guides/tags/technology-docker/index.html +++ b/guides/tags/technology-docker/index.html @@ -21,26 +21,26 @@ - + - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@

                                                                              1 guide tagged with "technology: docker"

                                                                              - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/technology-github/index.html b/guides/tags/technology-github/index.html index 8e7fbb805f..9e7e4a124a 100644 --- a/guides/tags/technology-github/index.html +++ b/guides/tags/technology-github/index.html @@ -21,26 +21,26 @@ - + - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@ - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/technology-helm/index.html b/guides/tags/technology-helm/index.html index 98770bd69d..2c3333db82 100644 --- a/guides/tags/technology-helm/index.html +++ b/guides/tags/technology-helm/index.html @@ -21,26 +21,26 @@ - + - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@

                                                                              1 guide tagged with "technology: helm"

                                                                              - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/technology-qovery/index.html b/guides/tags/technology-qovery/index.html index f33fb7075f..6fc22c3850 100644 --- a/guides/tags/technology-qovery/index.html +++ b/guides/tags/technology-qovery/index.html @@ -21,104 +21,104 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -127,101 +127,101 @@

                                                                              39 guides tagged with "technology: qovery"

                                                                              getting-started

                                                                              1. Hello World. Deploy your first application.

                                                                              read now
                                                                              getting-started

                                                                              2. Create a database

                                                                              read now
                                                                              getting-started

                                                                              3. Custom domain

                                                                              read now
                                                                              getting-started

                                                                              4. Environment variables

                                                                              read now
                                                                              getting-started

                                                                              5. Debugging

                                                                              read now
                                                                              tutorial

                                                                              Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery

                                                                              read now
                                                                              advanced

                                                                              Continuous Integration

                                                                              read now
                                                                              advanced

                                                                              Costs Control

                                                                              read now
                                                                              tutorial

                                                                              Create a Playground Environment on AWS

                                                                              read now
                                                                              tutorial

                                                                              Create your Staging environment from your Production environment on AWS

                                                                              read now
                                                                              tutorial

                                                                              Creating API clients using OpenAPI Tools

                                                                              read now
                                                                              tutorial

                                                                              Customizing Preview URL with Qovery CLI

                                                                              read now
                                                                              advanced

                                                                              Deploy API Gateway

                                                                              read now
                                                                              advanced

                                                                              Deploy External Services

                                                                              read now
                                                                              tutorial

                                                                              Deploy Temporal on Kubernetes

                                                                              read now
                                                                              tutorial

                                                                              Getting Started with Preview Environments on AWS

                                                                              read now
                                                                              tutorial

                                                                              Grafana setup with Qovery

                                                                              read now
                                                                              tutorial

                                                                              How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1

                                                                              read now
                                                                              tutorial

                                                                              How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2

                                                                              read now
                                                                              tutorial

                                                                              How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3

                                                                              read now
                                                                              tutorial

                                                                              How to deploy Helm charts

                                                                              read now
                                                                              tutorial

                                                                              How to run commands before the application starts

                                                                              read now
                                                                              tutorial

                                                                              How to seed a Postgres database on a dev environment

                                                                              read now
                                                                              tutorial

                                                                              How to use Github Organizations with Qovery

                                                                              read now
                                                                              tutorial

                                                                              How To Use Lifecycle Job To Deploy Any Kind Of Resources

                                                                              read now
                                                                              tutorial

                                                                              Import your environment variables with the Qovery CLI

                                                                              read now
                                                                              tutorial

                                                                              Integrate your application logs to Cloudwatch

                                                                              read now
                                                                              tutorial

                                                                              Kubernetes observability and monitoring with Datadog

                                                                              read now
                                                                              advanced

                                                                              Microservices

                                                                              read now
                                                                              advanced

                                                                              Migration

                                                                              read now
                                                                              advanced

                                                                              Monitoring

                                                                              read now
                                                                              advanced

                                                                              Mono repository

                                                                              read now
                                                                              advanced

                                                                              Preview Environments

                                                                              read now
                                                                              advanced

                                                                              Production

                                                                              read now
                                                                              advanced

                                                                              Seed Database

                                                                              read now
                                                                              tutorial

                                                                              Setting up Cloudflare and Custom Domain on Qovery

                                                                              read now
                                                                              tutorial

                                                                              Use an API gateway in front of multiple services

                                                                              read now
                                                                              tutorial

                                                                              Use AWS IAM roles with Qovery

                                                                              read now
                                                                              tutorial

                                                                              Working with Git Submodules

                                                                              read now
                                                                              - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/technology-terraform/index.html b/guides/tags/technology-terraform/index.html index 0c63c4ffa4..2a98c060fe 100644 --- a/guides/tags/technology-terraform/index.html +++ b/guides/tags/technology-terraform/index.html @@ -21,26 +21,26 @@ - + - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@

                                                                              1 guide tagged with "technology: terraform"

                                                                              - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/type-guide/index.html b/guides/tags/type-guide/index.html index 11eb51cf04..5492285412 100644 --- a/guides/tags/type-guide/index.html +++ b/guides/tags/type-guide/index.html @@ -21,74 +21,74 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -97,71 +97,71 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/type-tutorial/index.html b/guides/tags/type-tutorial/index.html index 3b25ef027c..0cb09cc634 100644 --- a/guides/tags/type-tutorial/index.html +++ b/guides/tags/type-tutorial/index.html @@ -21,106 +21,106 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -129,103 +129,103 @@

                                                                              40 guides tagged with "type: tutorial"

                                                                              tutorial

                                                                              Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS

                                                                              read now
                                                                              tutorial

                                                                              Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery

                                                                              read now
                                                                              tutorial

                                                                              Create a blazingly fast REST API in Rust (Part 1/2)

                                                                              read now
                                                                              tutorial

                                                                              Create a Playground Environment on AWS

                                                                              read now
                                                                              tutorial

                                                                              Create your Staging environment from your Production environment on AWS

                                                                              read now
                                                                              tutorial

                                                                              Creating API clients using OpenAPI Tools

                                                                              read now
                                                                              tutorial

                                                                              Customizing Preview URL with Qovery CLI

                                                                              read now
                                                                              tutorial

                                                                              Deploy Rails with PostgreSQL and Sidekiq

                                                                              read now
                                                                              tutorial

                                                                              Deploy Temporal on Kubernetes

                                                                              read now
                                                                              tutorial

                                                                              Getting Started with Preview Environments on AWS

                                                                              read now
                                                                              tutorial

                                                                              Grafana setup with Qovery

                                                                              read now
                                                                              tutorial

                                                                              How to activate SSO to connect to your EKS cluster

                                                                              read now
                                                                              tutorial

                                                                              How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1

                                                                              read now
                                                                              tutorial

                                                                              How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2

                                                                              read now
                                                                              tutorial

                                                                              How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3

                                                                              read now
                                                                              tutorial

                                                                              How to connect to a managed MongoDB instance on AWS

                                                                              read now
                                                                              tutorial

                                                                              How to connect to your EKS cluster with kubectl

                                                                              read now
                                                                              tutorial

                                                                              How to create an RDS instance through the AWS console

                                                                              read now
                                                                              tutorial

                                                                              How to deploy a Rust REST API application on AWS with ease

                                                                              read now
                                                                              tutorial

                                                                              How to deploy Helm charts

                                                                              read now
                                                                              tutorial

                                                                              How to integrate Qovery with GitHub Actions

                                                                              read now
                                                                              tutorial

                                                                              How to run commands before the application starts

                                                                              read now
                                                                              tutorial

                                                                              How to seed a Postgres database on a dev environment

                                                                              read now
                                                                              tutorial

                                                                              How to use CloudFront with a React frontend application on Qovery

                                                                              read now
                                                                              tutorial

                                                                              How to use Github Organizations with Qovery

                                                                              read now
                                                                              tutorial

                                                                              How To Use Lifecycle Job To Deploy Any Kind Of Resources

                                                                              read now
                                                                              tutorial

                                                                              How to write a Dockerfile

                                                                              read now
                                                                              tutorial

                                                                              Import your environment variables with the Qovery CLI

                                                                              read now
                                                                              tutorial

                                                                              Integrate your application logs to Cloudwatch

                                                                              read now
                                                                              tutorial

                                                                              Kubernetes observability and monitoring with Datadog

                                                                              read now
                                                                              tutorial

                                                                              Managing Environment Variables in React (create-react-app)

                                                                              read now
                                                                              tutorial

                                                                              Migrate your application from Heroku to AWS

                                                                              read now
                                                                              tutorial

                                                                              Setting up Cloudflare and Custom Domain on Qovery

                                                                              read now
                                                                              tutorial

                                                                              Setup VPC peering on AWS with Qovery

                                                                              read now
                                                                              tutorial

                                                                              URL Shortener API with Kotlin (Part 1/2)

                                                                              read now
                                                                              tutorial

                                                                              Use an API gateway in front of multiple services

                                                                              read now
                                                                              tutorial

                                                                              Use AWS IAM roles with Qovery

                                                                              read now
                                                                              tutorial

                                                                              Using Amazon SQS and Lambda on Qovery

                                                                              read now
                                                                              tutorial

                                                                              Working with Git Submodules

                                                                              read now
                                                                              tutorial

                                                                              Zero to Hero - How to deploy your apps on AWS in 30 minutes

                                                                              read now
                                                                              - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/aws-sqs-lambda-with-qovery/index.html b/guides/tutorial/aws-sqs-lambda-with-qovery/index.html index 05fcb65abd..eab41841e2 100644 --- a/guides/tutorial/aws-sqs-lambda-with-qovery/index.html +++ b/guides/tutorial/aws-sqs-lambda-with-qovery/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              client.send(command).then(
                                                                              (data) => {
                                                                              console.log(data);
                                                                              res.end('Success');
                                                                              // process data.
                                                                              },
                                                                              (error) => {
                                                                              console.error(error);
                                                                              res.end('Error');
                                                                              // error handling.
                                                                              }
                                                                              );

                                                                              To deploy the app on Qovery, all you need to do is to fork the repository from above and create a new app adding port 3000:

                                                                              AWS SQS Lambda

                                                                              Afterwards, we need to add two environment variables:

                                                                              • accessKeyId - your AWS access key ID
                                                                              • secretAccessKey - your AWS secret access key

                                                                              You can add them in Environment Variebles Secret section in your application settings:

                                                                              AWS SQS Lambda

                                                                              AWS SQS Lambda

                                                                              After all the setup is all done, click the Deploy button - the application will be shortly deployed.

                                                                              Create Lambda Consumers

                                                                              In AWS Console, open AWS Lambda panel.

                                                                              AWS SQS Lambda

                                                                              For the sake of the guide, we will use a simple hello-world lambda from AWS serverless app repository.

                                                                              Browse the app repository and pick the hello-world function as shown in the screenshot above, and deploy the function

                                                                              AWS SQS Lambda

                                                                              Create Lambda Trigger

                                                                              To make our Lambdas consume messages from SQS, we will need to add a Lambda Trigger in the SQS configuration.

                                                                              AWS SQS Lambda

                                                                              Click on Configure Lambda Function Trigger as shown in the screenshot above and select your lambda function from the dropdown, then save the changes:

                                                                              AWS SQS Lambda

                                                                              Configure Permissions

                                                                              Let's now grant our Lambda functions access to the SQS queue we created before.

                                                                              In our lambda view, click on Configure:

                                                                              AWS SQS Lambda

                                                                              Then, click on a role in Execution role to get redirected to a view where we can alter our Lambda permissions.

                                                                              In the role summary screen, click on Edit policy next to helloWorldrolePolicy

                                                                              AWS SQS Lambda

                                                                              In the SQS section, grant permissions to all Read/Write options in the Actions Access level and accept the changes:

                                                                              AWS SQS Lambda

                                                                              Test Lambda as an SQS Consumer Flow

                                                                              To push messages to our SQS queue from the backend app deployed on Qovery, click on the Open button in the application we deployed in the previous step. It will redirect you to the API endpoint exposed by the backend app - the logic inside the application is made so that it sends messages to the SQS queue.

                                                                              AWS SQS Lambda

                                                                              Now, in the Monitoring section of SQS in AWS Console, we will see messages received on metrics charts:

                                                                              AWS SQS Lambda

                                                                              To validate that our consumer Lambdas processed the messages, navigate to your lambda Monitor panel:

                                                                              AWS SQS Lambda

                                                                              In the Invocations chart, you'll notice that our Lambda was triggered several times by the messages sent over the SQS.

                                                                              Conclusions

                                                                              In this part of the tutorial, we learned how to send messages over from an application deployed on Qovery to SQS and consume them from serverless Lambda functions. In the next part, we will create a scalable group of worker applications deployed by Qovery that consume messages from the same Queue.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/aws-vpc-peering-with-qovery/index.html b/guides/tutorial/aws-vpc-peering-with-qovery/index.html index e190a2e932..718a97f4f4 100644 --- a/guides/tutorial/aws-vpc-peering-with-qovery/index.html +++ b/guides/tutorial/aws-vpc-peering-with-qovery/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -54,21 +54,21 @@ Refer to this guide if you need help deploying an application on Qovery.

                                                                              You can learn more about VPC peering on AWS here: https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws/index.html b/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws/index.html index 41485acdaf..d116a2a6a1 100644 --- a/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws/index.html +++ b/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -57,21 +57,21 @@
                                                                              db.images.insert([
                                                                              {
                                                                              title: 'IMG_4985.HEIC',
                                                                              size: '3.9 MB',
                                                                              source:
                                                                              'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',
                                                                              },
                                                                              {
                                                                              title: 'IMG_4985.HEIC',
                                                                              size: '3.9 MB',
                                                                              source:
                                                                              'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',
                                                                              },
                                                                              {
                                                                              title: 'IMG_4985.HEIC',
                                                                              size: '3.9 MB',
                                                                              source:
                                                                              'https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80',
                                                                              }
                                                                              ])

                                                                              Now, after opening the frontend app in our preview environment, we will see all the images we put in the database! It looks like the feature is working well, so let's merge the PR:

                                                                              AWS Preview Environments

                                                                              What now happens is automatically after the PR merge, the preview environment is automatically cleaned up:

                                                                              AWS Preview Environments

                                                                              Great job! Thanks to Qovery Preview Environments, we managed to develop a new feature in a complete separation from our production, we tested it in a real environment deployed in the cloud, and we didn't have to spend any time preparing our environment for tests at all.

                                                                              Conclusion

                                                                              In the article, we quickly went through the process of creating a full-stack application with frontend, backend, and database. We enabled the Preview Environment feature to develop new features more quickly. We learned what the benefits of Preview Environments are, how to use them, and how to integrate them to day to day development workflow.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/build-e2e-testing-ephemeral-environments/index.html b/guides/tutorial/build-e2e-testing-ephemeral-environments/index.html index f62a36e94e..62b3101619 100644 --- a/guides/tutorial/build-e2e-testing-ephemeral-environments/index.html +++ b/guides/tutorial/build-e2e-testing-ephemeral-environments/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -79,21 +79,21 @@
                                                                              qovery environment delete \
                                                                              --organization "${{ vars.QOVERY_ORGANIZATION_NAME }}" \
                                                                              --project "${{ vars.QOVERY_PROJECT_NAME }}" \
                                                                              --environment "$new_environment_name" \
                                                                              -w

                                                                              The complete file is available here

                                                                              We just use the qovery environment delete command to delete the ephemeral environment. The option -w is used to wait for the deletion to be completed. Qovery will automatically release the resources used by the environment.

                                                                              Wrapping up

                                                                              Congratulations! You've successfully built an automated E2E testing pipeline with GitHub Actions and Qovery. You can now run your tests in a fully isolated environment, provisioned and de-provisioned automatically, and integrated with your GitHub repository.

                                                                              Some resources:

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/cloudwatch-integration/index.html b/guides/tutorial/cloudwatch-integration/index.html index 30ce7c9df0..aab499fa5d 100644 --- a/guides/tutorial/cloudwatch-integration/index.html +++ b/guides/tutorial/cloudwatch-integration/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -52,21 +52,21 @@
                                                                              elasticsearch:
                                                                              enabled: false

                                                                              You can take a look at additional configuration options on the AWS provided chart

                                                                              Then deploy fluent-bit with the following command:

                                                                              helm upgrade --install aws-for-fluent-bit -f values.yaml --namespace fluent-bit --create-namespace eks/aws-for-fluent-bit --version 0.1.21

                                                                              You should start seeing fluent-bit pods. Take a look at the logs to ensure there is no configuration issue.

                                                                              Cloudwatch usage

                                                                              You can now use Cloudwatch to look at your logs. Connect to Cloudwatch, go into the Logs insight section, then you can perform queries:

                                                                              cloudwatch search

                                                                              1. Select the fluent-bit group of logs
                                                                              2. Create a query (syntax examples)
                                                                              3. Run your query
                                                                              4. See the result and expand to filter on other elements
                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1/index.html b/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1/index.html index 6af5e7e530..391810b217 100644 --- a/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1/index.html +++ b/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -67,21 +67,21 @@
                                                                              # delete a tweet
                                                                              curl -X DELETE https://main-gxbuagyvgnkbrp5l-gtw.qovery.io/tweets/<change_with_a_valid_id>

                                                                              What's next

                                                                              In this first part we saw how to create a Rust API with Actix and Diesel. In the second part we will compare its performance with a Go application to see which one is the most performant.

                                                                              Special thanks to Jason and Kokou for your reviews

                                                                              Useful resources

                                                                              Do you want to know more about Rust?

                                                                              Tutorial
                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/create-a-playground-environment-on-aws/index.html b/guides/tutorial/create-a-playground-environment-on-aws/index.html index e6faddabc2..de1d4f8861 100644 --- a/guides/tutorial/create-a-playground-environment-on-aws/index.html +++ b/guides/tutorial/create-a-playground-environment-on-aws/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              3 min read
                                                                              Updated

                                                                              A Playground Environment is an environment where you can do all your testing without impacting an existing environment.

                                                                              Playground environments

                                                                              Here are some use cases where a playground environment is helpful for:

                                                                              • Experimenting: Test your code without the fear to break anything from your original environment.
                                                                              • Benchmarking: You want to stress your application without affecting the original environment.
                                                                              • Debugging: You have a bug in production that you want to reproduce but without impacting the production environment.
                                                                              • Product Demo: Your Sales or Product Manager needs to make an important demo and want to be sure it will work.

                                                                              In this guide, we will create a playground environment on AWS.

                                                                              Create your Playground Environment

                                                                              To create your Playground Environment you simply need to:

                                                                              1. Go into the base environment that you want to clone
                                                                              2. Click on the Actions and Clone button
                                                                              3. Enter a name for your playground environment
                                                                              4. Select the cluster where you want to deploy it
                                                                              5. Set the Environment mode to Development
                                                                              6. Click on the Create button
                                                                              7. Deploy your Playground Environment

                                                                              Once deployed, your applications within this environment will have dedicated URLs to get access to. You can use these URLs to test your application.

                                                                              Then you can check that your playground environment is working by visiting the temporary URL.

                                                                              Delete your Playground Environment

                                                                              To delete your Playground Environment you simply need to:

                                                                              1. Go into the playground environment
                                                                              2. Click on the Actions and Delete button
                                                                              3. Confirm and Delete the environment

                                                                              All the resources will be freed.

                                                                              Optional: Create a Playground Cluster

                                                                              To prevent your playground environment from impacting your production environment, you can create a dedicated cluster. So every playground environments will be on the same cluster and will not disturb your production.

                                                                              Playground environments with 2 clusters

                                                                              Here is how to create a playground cluster.

                                                                              And how to create a playground environment on our playground cluster.

                                                                              Wrapping up

                                                                              In this guide, we have covered everything you need to know to create a secure staging environment from your production. Now, you can take a look at how to seed your Staging database (Guide for Postgres but applicable for most databases).

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws/index.html b/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws/index.html index 49f04cb21f..b77aa42d21 100644 --- a/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws/index.html +++ b/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              4 min read
                                                                              Updated

                                                                              Let's say you have your production environment deployed, and you want to create a staging environment. You have two options:

                                                                              1. Create a staging environment from scratch.
                                                                              2. Clone your production environment and create a staging environment from it.

                                                                              This is where the Environment Clone feature of Qovery is useful. No need to create a new environment, just clone your production environment and create a staging environment from it.

                                                                              In this guide, we will go through the steps to create a staging environment from your production environment. While applying the best practices by isolating the staging and production environments on two separated clusters and VPCs.

                                                                              Complete Production and Staging infrastructure

                                                                              Create a Staging cluster

                                                                              Isolating the staging and production environments on two separate clusters and VPCs is a good practice to avoid any potential issues on your production caused by your staging. This is not a mandatory step, but it is well recommended.

                                                                              To create your staging cluster it's also recommended creating a new AWS IAM access key and secret access key in a dedicated subaccount. Then you are sure that both environment are also isolated at the AWS level:

                                                                              1. Go to your Organization cluster settings
                                                                              2. Add a cluster with a name "staging"
                                                                              3. Deploy your staging cluster

                                                                              Create your Staging environment from your Production environment

                                                                              Now, to create your staging environment from your production environment, you need to:

                                                                              1. Go inside your production environment and click on the "Clone" button.
                                                                              2. Give a name to your staging environment (E.g "staging")
                                                                              3. Set the mode to "Staging"
                                                                              4. Set the cluster to "staging"
                                                                              5. Click on "Create"
                                                                              6. That's it!

                                                                              Your environment has been created, but it's not deployed yet. Before we will make some adjustment to change the branch of our applications.

                                                                              Update your Staging applications

                                                                              Your Staging applications have the same branch as your Production applications. To update your Staging applications branch, you need to:

                                                                              1. Go into the settings of each of your applications.
                                                                              2. Update the branch to your Staging branch.
                                                                              3. Click on "Save"

                                                                              We are almost done, now we need to smartly change our environment variables and secrets to not use the one used in production.

                                                                              Override your environment variables and secrets

                                                                              Let's say you have a production environment with the following environment variables:

                                                                              • NODE_ENV=production
                                                                              • STRIPE_API_KEY=a-secret-production-key

                                                                              You might need to keep the same keys but change the values. That's exactly what Qovery makes you do with the Environment Variable Override feature. You can keep the same keys but change the values.

                                                                              Deploy your Staging environment

                                                                              Finally, your Staging environment has been created and set up correctly. To deploy your Staging environment, you just need to go to your Staging environment and click on the "Deploy" button.

                                                                              Wrapping up

                                                                              In this guide, we have covered everything you need to know to create a secure staging environment from your production. Now, you can take a look at how to seed your Staging database (Guide for Postgres but applicable for most databases).

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/customizing-preview-url-with-qovery-cli/index.html b/guides/tutorial/customizing-preview-url-with-qovery-cli/index.html index 1b93503a23..1767277218 100644 --- a/guides/tutorial/customizing-preview-url-with-qovery-cli/index.html +++ b/guides/tutorial/customizing-preview-url-with-qovery-cli/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -49,21 +49,21 @@
                                                                              # Create a custom domain
                                                                              $ qovery application domain create -n "app name" --domain app-$PR_ID.domain.name

                                                                              Replace app name with the name of your application and app.domain.name with your desired custom domain.

                                                                              User --organization, --project, --environment flags to specify the organization, project, and environment where you want to create the custom domain.

                                                                            • Retrieve the Validation Domain

                                                                              To get the validation domain required for the next step, run the following command:

                                                                              $ qovery application domain list -n "app name" | grep "app-$PR_ID.domain.name" | awk '{print $7}'

                                                                              Replace app name and app.domain.name with the appropriate values. This command will output the validation domain.

                                                                            • Create a CNAME Record in Your DNS Provider

                                                                              Use the validation domain from the previous step to create a CNAME record in your DNS provider. The CNAME record should point to the validation domain.

                                                                              Example with Route53:

                                                                              $ aws cli route53 change-resource-record-sets --hosted-zone-id "hosted zone id" --change-batch '{"Changes":[{"Action":"CREATE","ResourceRecordSet":{"Name":"app-$PR_ID.domain.name","Type":"CNAME","TTL":300,"ResourceRecords":[{"Value":"validation-domain"}]}}]}'

                                                                              Example with Cloudflare:

                                                                              $ curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records" \
                                                                              -H "X-Auth-Email: {email}" \
                                                                              -H "X-Auth-Key: {key}" \
                                                                              -H "Content-Type: application/json" \
                                                                              --data '{"type":"CNAME","name":"app-$PR_ID.domain.name","content":"validation-domain","ttl":1,"proxied":false}'

                                                                              The idea here is to create a CNAME record that points to the validation domain. The validation domain is a temporary domain that is used to validate the ownership of the custom domain.

                                                                            • Redeploy your application

                                                                              Once the DNS changes have propagated, redeploy your application to complete the process.

                                                                              $ qovery application redeploy -n "app name" -w

                                                                              Your application should now be available at app-{PR ID}.domain.name.

                                                                            • Wrapping up

                                                                              Congratulations! You have successfully customized your preview URL using the Qovery CLI. Now, whenever a new environment is created, the custom domain will be automatically configured. If you encounter any issues, please reach out to our support team on the Qovery forum.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/data-seeding-in-postgres/index.html b/guides/tutorial/data-seeding-in-postgres/index.html index f30fc27ec7..802889f9fa 100644 --- a/guides/tutorial/data-seeding-in-postgres/index.html +++ b/guides/tutorial/data-seeding-in-postgres/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -62,21 +62,21 @@
                                                                              exec "$@"

                                                                              Example

                                                                              The following examples will show the application of seeding the data in dev environments after cloning an environment and using the Preview Environment feature.

                                                                              Clone Environment

                                                                              Clone environment feature allows you to make a complete clone of a chosen environment, including its all applications, services, and their configs. In the example we will clone a new environment and have our seed data injected automatically.

                                                                              First, we make a clone of our production environment:

                                                                              Seeding Postgres Database

                                                                              Then, we deploy the new environment:

                                                                              Seeding Postgres Database

                                                                              After navigating to deployment logs, we will notice our seed data inserts logged:

                                                                              Seeding Postgres Database

                                                                              Preview Environment

                                                                              Preview Environment feature allows you to automatically create new development environments to validate new changes before merging them to your production branch.

                                                                              First, we open a pull request:

                                                                              Seeding Postgres Database

                                                                              Then, in list of environments, we get a new environment automatically created for the pull request:

                                                                              Seeding Postgres Database

                                                                              When you open the logs of the deployment, you’ll see the seed data injection logs:

                                                                              Seeding Postgres Database

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq/index.html b/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq/index.html index e173a7aa87..9f533413fd 100644 --- a/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq/index.html +++ b/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -102,21 +102,21 @@ Since Qovery provides us with the secrets corresponding to the two databases we created earlier, we can alias them.

                                                                              First, create an alias to the QOVERY_POSTGRESQL_ZXXXXXXXX_DATABASE_URL_INTERNAL:

                                                                              Qovery console

                                                                              In the form, chose DATABASE_URL for the alias name and set it at the ENVIRONMENT level:

                                                                              Qovery console

                                                                              Click Create then do the same thing with a REDIS_URL alias to the QOVERY_REDIS_ZXXXXXXXX_DATABASE_URL_INTERNAL.

                                                                              You should see your two aliases created:

                                                                              Qovery console

                                                                            • Deploy the environment

                                                                              Go back to the staging environment view and deploy it:

                                                                              Qovery console

                                                                              You should see it switch to the DEPLOYING status. Wait until the status turns to RUNNING.

                                                                              Qovery console

                                                                              Once your environment is RUNNING, open the web application to see if it works. It will open a new tab showing your application.

                                                                              Qovery console

                                                                            • Add the Sidekiq worker

                                                                              The last step is to add your Sidekiq Worker. We'll follow the same steps as in the Add your Rails app section with a few differences:

                                                                              Add a new application:

                                                                              Qovery console

                                                                              The settigs are the same as for the Rails application, except:

                                                                              • We use the Dockerfile.sidekiq Dockerfile this time
                                                                              • We don't declare a port since our worker is not a web service but communicates with our application through Redis.

                                                                              Qovery console

                                                                              Qovery console

                                                                              Click Create.

                                                                              If we check the ENV variables and secrets, we notice that it directly inherited the ones we set at the Environment level. So we don't need to do the configuration again.

                                                                              Qovery console

                                                                              You can now deploy your worker application:

                                                                              Qovery console

                                                                              Wait for it to switch to the RUNNING status.

                                                                            • Conclusion

                                                                              You now have a Rails application with PostgreSQL and Sidekiq running on Qovery.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/deploy-temporal-on-kubernetes/index.html b/guides/tutorial/deploy-temporal-on-kubernetes/index.html index 47a3dd30f7..f7761c0fef 100644 --- a/guides/tutorial/deploy-temporal-on-kubernetes/index.html +++ b/guides/tutorial/deploy-temporal-on-kubernetes/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -53,21 +53,21 @@ Once it is RUNNING, you can open the UI again and check everything is ok.

                                                                              Conclusion

                                                                              We have successfully deployed Temporal on Qovery. It can be useful for Staging or Preview environments but this is a very minimal deployment and we would not advise doing it for production.

                                                                              There is no one-size-fits-all configuration for this type of products.

                                                                              You would probably like to setup authentication on your Web UI as well. We include the config file in the GitHub repository. You can edit it to your needs, following this documentation.

                                                                              For deploying on your Kubernetes cluster, check the documentation and the following article: https://docs.temporal.io/blog/temporal-and-kubernetes. The first video is worth watching.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/generate-qovery-api-client/index.html b/guides/tutorial/generate-qovery-api-client/index.html index 4cf107eb93..e4a11a24c3 100644 --- a/guides/tutorial/generate-qovery-api-client/index.html +++ b/guides/tutorial/generate-qovery-api-client/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -53,21 +53,21 @@
                                                                              organizations, res, err := client.OrganizationMainCallsApi.ListOrganization(auth).Execute()
                                                                              if err != nil {
                                                                              return err
                                                                              }
                                                                              if res.StatusCode >= 400 {
                                                                              return errors.New("Received " + res.Status + " response while listing organizations. ")
                                                                              }

                                                                              Summary

                                                                              Qovery Open API specification allows creating Qovery API stubs extremely quickly. At Qovery, we officially support only Golang Client, but if you use a different language, you can generate your own client in a matter of seconds following the steps of this article.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners/index.html b/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners/index.html index 7f1135a4ae..8f44798e37 100644 --- a/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners/index.html +++ b/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              6 min read
                                                                              Updated

                                                                              It is critical to have testing and staging environments accurately reflect production, but achieving this can be a major operational hassle. Most engineering teams use a single staging environment which makes it hard for developers to test their changes in isolation; the alternative is for DevOps teams to spin up new testing or staging environments manually and tear them down after testing is done.

                                                                              Qovery’s Preview Environments solve this problem by automatically creating a clone of your production environment (including applications, databases and configuration) on every pull request, so you can test your changes with confidence without affecting your production.

                                                                              Flow on how Qovery Preview Environment works

                                                                              Qovery keeps your preview environments up to date on every commit and automatically destroys them when the original pull request is merged or closed. You can also set up an expiry time to automatically clean up preview environments after a period of inactivity.

                                                                              Preview Environments can be helpful in a lot of cases:

                                                                              • Share your changes live in code reviews: no more Git diffs for visual changes!
                                                                              • Get shareable links for upcoming features and collaborate more effectively with internal and external stakeholders.
                                                                              • Run CI tests against a high fidelity copy of your production environment before merging.

                                                                              In this step-by-step guide you will learn how to get started using the Preview Environments on AWS with Qovery.

                                                                              Please contact us via our forum if you have any questions concerning the Preview Environments

                                                                              Steps

                                                                              1. Create a "Blueprint" environment
                                                                              2. Enable Preview Environment feature
                                                                              3. Create a Preview Environment
                                                                              4. Delete a Preview Environment
                                                                              5. Seed your database
                                                                              6. Auto stop and start your Preview Environments
                                                                              7. Integrate your CI (Continuous Deployment) platform

                                                                              Create your Blueprint Environment

                                                                              Even if not required, we recommend creating an environment that will serve as a root to create your Preview Environments. The idea is to keep this environment as a template of a fully working environment. This environment should not be directly used. This is what we call "blueprint environment".

                                                                              I assume you already have a working environment, so to create a blueprint environment you need to:

                                                                              1. Go to your working environment
                                                                              2. Click on "Actions" > "Clone"
                                                                              3. Name your environment "blueprint"
                                                                              4. Click on "Create"

                                                                              Enable Preview Environment

                                                                              Now, you can go to turn on Preview Environments by:

                                                                              1. Click on your Blueprint environment "Settings".
                                                                              2. Click on the Preview Env. tab
                                                                              3. Turn on Preview Environment feature for all your applications by clicking on Activate preview environment for all apps.

                                                                              Change your base branch

                                                                              Now that you have turned on the Preview Environment feature, you need to change the base branch from your applications inside your Blueprint Environment. Let's say, every new feature branch you create are coming from staging. Then you will need to change all your applications to target the staging branch.

                                                                              Here is a flow example showing what happen when you create a new Pull Request from a feat/xxx branch that has been created from the base branch staging.

                                                                              Flow on how Qovery Preview Environment Branching works

                                                                              1. A developer creates a git branch feat/xxx is created from staging.
                                                                              2. A developer creates a Pull Request for feat/xxx.
                                                                              3. Qovery creates a Preview Environment feat/xxx from the blueprint environment. The frontend, backend, PostgreSQL and Redis instances are cloned!
                                                                              4. The frontend app from the environment feat/xxx is accessible via a dedicated URL.

                                                                              Validate your Blueprint Environment

                                                                              Before creating a Preview Environment, validate that your Blueprint environment works.

                                                                              Once done, you need to:

                                                                              1. Stop your Blueprint environment by clicking on "Actions" > "Stop".
                                                                              2. Turn off "auto-deploy" by clicking on "Settings" > "Deployment" > "Auto-deploy off" > "Save".

                                                                              We are now ready to try out our Preview Environment configuration.

                                                                              Create a Preview Environment

                                                                              To create a Preview Environment, here are the steps:

                                                                              1. Checkout your staging branch.
                                                                              2. Create a branch test_qovery_preview_environment and push it.
                                                                              3. Create a Pull Request/Merge Request.

                                                                              You must see a new environment appearing in your environment list on Qovery. Wait until it is fully deployed, then you will be able to connect to it. This environment is fully isolated from your base environment.

                                                                              Delete a Preview Environment

                                                                              To delete you need to merge test_qovery_preview_environment into staging. You also have the ability to delete it manually on Qovery.

                                                                              Advanced

                                                                              Eager to know how to go integrate Qovery Preview Environments with your CI and much more? Check out our the following guides:

                                                                              Wrapping up

                                                                              Congrats! You have set up your Preview Environments features. Feel free to check out our forum and open a thread if you have any question. In the next guide, we will go deeper configuration to integrate the Preview Environment with your existing products and workflow.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/github-organization-repository-access/index.html b/guides/tutorial/github-organization-repository-access/index.html index f90e2d7b3c..0661ccdce9 100644 --- a/guides/tutorial/github-organization-repository-access/index.html +++ b/guides/tutorial/github-organization-repository-access/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -49,21 +49,21 @@ in order to run deployments.

                                                                              Github Organization

                                                                              If Organization repositories are missing in the repository selector, you will need to grant Qovery access to your organization.

                                                                              1. Navigate to Qovery Github Application

                                                                              2. Make sure Qovery has access to the organization you want to use (grant permissions if necessary)

                                                                                Github Organization

                                                                              After following the steps from above, you should be able to select your organization repositories in Qovery Console while creating an application.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/grafana-install/index.html b/guides/tutorial/grafana-install/index.html index 9bc144eb50..4b07ad0c9b 100644 --- a/guides/tutorial/grafana-install/index.html +++ b/guides/tutorial/grafana-install/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -49,21 +49,21 @@ The currently used database is stored on the volume, so data will be lost on an application deletion. Qovery is going to implement configuration files for Docker in the coming weeks

                                                                              Create a Grafana application

                                                                              Connect to the console and add a new application:

                                                                              create gafana app

                                                                              1. Set an application name
                                                                              2. Select the application source type: Container registry
                                                                              3. Select DockerHub Public (or the one you have. If you do not have one, create a registry pointing to DockerHub)
                                                                              4. Set the image name: grafana/grafana
                                                                              5. Take a look at the latest Grafana tags and set the tag you want to use (do not use latest one to avoid later issues)

                                                                              Then set the resources to 1 instance and let other default values (Grafana doesn't consume a lot of resources):

                                                                              set resources

                                                                              Add a port mapping to the application, and set it to 3000:

                                                                              set port

                                                                              Finally, click on the Create button:

                                                                              create app

                                                                              Configure database storage

                                                                              We're now going to create a volume that will contain Grafana default database:

                                                                              create app

                                                                              Go into Settings > Storage > Add Storage. Set the Path to /var/lib/grafana and the Size to 4Gi. Click on Create.

                                                                              Usage

                                                                              Now you can deploy Grafana :). On the top right, you have the Open links button which will help you to get quick access. Then connect with those credentials:

                                                                              • Login: admin
                                                                              • Password: admin

                                                                              Cloudwatch Datasource

                                                                              You can add several data sources to Grafana. One we recommend at Qovery for full-text search is Cloudwatch. First of all, you have to follow this guide to ensure all your logs are sent to Cloudwatch. Then, you can add a new data source in Grafana:

                                                                              grafana cloudwatch

                                                                              We advise you to use assume role or use a dedicated service account in read-only to access your logs. In this case, those permissions will be required:

                                                                              {
                                                                              "Version": "2012-10-17",
                                                                              "Statement": [
                                                                              {
                                                                              "Sid": "AllowReadingLogsFromCloudWatch",
                                                                              "Effect": "Allow",
                                                                              "Action": [
                                                                              "logs:DescribeLogGroups",
                                                                              "logs:GetLogGroupFields",
                                                                              "logs:StartQuery",
                                                                              "logs:StopQuery",
                                                                              "logs:GetQueryResults",
                                                                              "logs:GetLogEvents"
                                                                              ],
                                                                              "Resource": "*"
                                                                              },
                                                                              {
                                                                              "Sid": "AllowReadingTagsInstancesRegionsFromEC2",
                                                                              "Effect": "Allow",
                                                                              "Action": ["ec2:DescribeTags", "ec2:DescribeInstances", "ec2:DescribeRegions"],
                                                                              "Resource": "*"
                                                                              },
                                                                              {
                                                                              "Sid": "AllowReadingResourcesForTags",
                                                                              "Effect": "Allow",
                                                                              "Action": "tag:GetResources",
                                                                              "Resource": "*"
                                                                              }
                                                                              ]
                                                                              }

                                                                              More info: https://grafana.com/docs/grafana/latest/datasources/aws-cloudwatch/

                                                                              Once done, you're able to create dashboards using Cloudwatch datasource and perform queries to your logs.

                                                                              Links

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster/index.html b/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster/index.html index 5cea993125..79dcbb7388 100644 --- a/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster/index.html +++ b/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -53,21 +53,21 @@
                                                                              FHTG-****

                                                                              You will be redirected to your browser, validate the form.

                                                                              Then you will be prompted to select your AWS account.

                                                                              There are 1 AWS account available to you.
                                                                              > qovery, q@qovery.com (283389****)

                                                                              Then you will be prompted for default region (eu-west-3 in my case), output format (json in my case) and profile name (bchastanier_sso in my case, but feel free to pick whatever you want).

                                                                              Using the account ID 283389****
                                                                              The only role available to you is: AdministratorAccess
                                                                              Using the role name "AdministratorAccess"
                                                                              CLI default client Region [None]: eu-west-3
                                                                              CLI default output format [None]: json
                                                                              CLI profile name: bchastanier_sso
                                                                            • Get SSO role ARN

                                                                              Go to AWS console > IAM > Roles.

                                                                              AWS console - go to aws iam roles

                                                                              Look for a role named AWSReservedSSO_xx and select it (name can varies based on what you have configured / how you named your Admins user group, but it should start with AWSReservedSSO_).

                                                                              AWS console - look for SSO role

                                                                              Copy its ARN and keep it somewhere, you will need it in next step.

                                                                              AWS console - copy SSO role ARN

                                                                            • Enable SSO on your cluster

                                                                              Go to your clusters in Qovery console and click on cluster you want to activate SSO on settings.

                                                                              AWS console - go to qovery cluster settings

                                                                              Then go to advanced settings, and set:

                                                                              • aws.iam.enable_sso to true
                                                                              • aws.iam.sso_role_arn to the SSO role ARN string you copy from previous step.

                                                                              AWS console - set qovery cluster advanced settings to enable SSO

                                                                              Redeploy your cluster once advanced settings are saved.

                                                                            • Download the Kubeconfig file

                                                                              To connect to your EKS cluster you will need to set a context to kubectl. This is done with a Kubeconfig file.

                                                                              When installing a new cluster, Qovery stores it in an S3 bucket on your account.

                                                                              Go to S3, find the Qovery bucket, and download the file. The bucket should be named something like qovery-kubeconfigs-<cluster ID>.yaml.

                                                                              Set the context for kubectl, run the following command:

                                                                              export KUBECONFIG=<path to the kubeconfig file you downloaded>

                                                                              AWS console - get Kubeconfig

                                                                            • Connect to your cluster

                                                                              Connect via the CLI running this command:

                                                                              aws sso login --profile <your-sso-profile-you-set-before>

                                                                              This will open your browser and prompt you to connect, validate the form.

                                                                              AWS console - validate SSO connection in browser

                                                                              Now you should be able to access your cluster without anything else, let's try to get aws-auth configmap showing users and roles allowed to connect to the cluster:

                                                                              AWS_PROFILE=<your-sso-profile-you-set-before> kubectl describe -n kube-system configmap/aws-auth

                                                                              This should give you the config map content. If not, something is not properly configured.

                                                                            • Conclusion

                                                                              You can access your Qovery clusters via your SSO directly.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1/index.html b/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1/index.html index 43551be5f7..85e2a89bc7 100644 --- a/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1/index.html +++ b/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              11 min read
                                                                              Updated

                                                                              As a developer, I am super impressed by the number of great open-source projects popping around. I think of Supabase (an open-source alternative to Firebase), Strapi (open-source headless CMS), Meilisearch (open-source search engine), Posthog (open-source product analytics tool), and so many others. For me, these are the tools that most developers will use in the future. One common method to make those products financially sustainable is to provide a managed version. Meaning, you can enjoy using their product without the hassle of managing the product updates, the backups, the security, and the scaling. It is exactly what Hasura did with its cloud version - and it is pretty convenient to use their product in production. However, building a cloud version takes months (sometimes years). What takes time? Hiring platform engineers, building the infrastructure, testing it, monitoring it... All of that takes a considerable amount of time and effort. Luckily, at Qovery, we provide the infrastructure stack that every open-source project needs to build 90% of their cloud-managed version. The remaining 10% are the UI and the business model logic. In this 6-part article series, I will attempt to explain how to build a cloud-managed version of AppWrite. Let’s go!

                                                                              Articles:

                                                                              • Part 1: Introduction and architecture
                                                                              • Part 2: Build our AppWrite cloud backend and integrate it with the Qovery API
                                                                              • Part 3: Build our AppWrite cloud frontend and combine it with our cloud backend
                                                                              • Part 4: Monitor our AppWrite cloud version
                                                                              • Part 5: Integrate the payment system with Stripe (optional)
                                                                              • Part 6: Integrate email notification with Courier (optional)
                                                                              • Part 7: Give your customer a production, staging, and dev environment (optional)

                                                                              Before getting started

                                                                              Motivation

                                                                              Since I launched Qovery in 2019, I have talked to dozens of founders from great open-source software companies. Most of them were looking to build their cloud-managed service at some point. Some of them even asked me for feedback on building one and asked me to use Qovery as a white-label technology when they discovered it was a full-time job. Qovery is a product simplifying app deployment and infrastructure management on AWS. Time flies, and as Qovery evolves, it is now possible for any open-source project to use Qovery as a white-label technology to provide a cloud version of an open-source project. No hidden cost. Just pick the plan that fits you best and build your cloud version in days instead of months. My team will be proud to help you in your success.

                                                                              Why AppWrite

                                                                              AppWrite is quite representative of a “modern web open-source project”. In this guide, AppWrite is used as a demo project to demonstrate the concept of building a cloud-managed version for an open-source web project. AppWrite is written in PHP for the backend and JS for the frontend. It provides a user-friendly web interface connected to a web API, and it stores the data in MariaDB and Redis databases. The idea is: if it works for AppWrite, then it is good to work for any other web open-source project with a similar technical stack. Feel free to contact me if you have any concerns.

                                                                              Technologies

                                                                              AppWrite is a Backend as a Service open-source software. It is similar to Supabase and Firebase to create a backend in a few minutes.

                                                                              Our goal is to provide a fully managed cloud version of AppWrite. Meaning we need to deliver to our customers a way to order their AppWrite instance and use it, while the maintenance is handled by us. It is the most common managed version out there - think MongoDB Atlas. To achieve this, we will use the following technologies:

                                                                              • AppWrite: We will use AppWrite Docker container image to run the latest version of AppWrite.
                                                                              • MariaDB: AppWrite is using a MariaDB server for managing persistent database data.
                                                                              • Redis: AppWrite uses a Redis server for managing cache, queues, and scheduled tasks.
                                                                              • AWS: We will host AppWrite on AWS EKS (Kubernetes), Redis (in-memory database), and MariaDB (AWS RDS) for each customer on AWS.
                                                                              • Qovery: Qovery will create an environment composed of AppWrite, Redis, and MariaDB for each customer on our AWS account.
                                                                              • Hasura: Low-code GraphQL backend to manage our customers’ data.
                                                                              • GatsbyJS: JS frontend framework to provide a web interface to our customers.
                                                                              • PostgreSQL: database to store our customers’ data
                                                                              • Auth0: To manage the auth of our customers.
                                                                              • Stripe: To charge our customers.
                                                                              • Courier: To send an email and Slack notifications to our customers.

                                                                              This bunch of technologies combined enable us to build a cloud version for AppWrite. Let’s take a deeper look at how all of them are interconnected.

                                                                              Architecture

                                                                              architecture schema

                                                                              This schema represents the different layers composing the cloud version of AppWrite. From top to bottom, we will give the details of each layer.

                                                                              User flow 1: Customer request an AppWrite instance

                                                                              customer request an appwrite instance - behind the scene

                                                                              Here is what happens when the customer requests a cloud AppWrite instance:

                                                                              1. The customer connects on cloud.appwrite.com (fake domain to represent “AppWrite cloud frontend”).
                                                                              2. The customer requests a new AppWrite instance.
                                                                              3. The AppWrite cloud backend calls the Qovery API to create an Environment.
                                                                              4. The AppWrite cloud backend calls the Qovery API to create a MariaDB database.
                                                                              5. The AppWrite cloud backend calls the Qovery API to create a Redis database.
                                                                              6. The AppWrite cloud backend calls the Qovery API to create an AppWrite application.
                                                                              7. The AppWrite cloud backend calls the Qovery API to bind the AppWrite application to the MariaDB and Redis databases.
                                                                              8. The AppWrite cloud backend calls the Qovery API to start the Environment.
                                                                              9. The Qovery API returns the temporary URL to the AppWrite cloud backend.
                                                                              10. The customer receives the URL of his instance via the AppWrite cloud frontend.
                                                                              11. The customer can use his AppWrite instance.

                                                                              User flow 2: customer deletes an AppWrite instance

                                                                              customer deletes an appwrite instance - behind the scene

                                                                              Let’s say our customer now wants to delete his cloud AppWrite instance; this is what happens:

                                                                              1. The customer connects on cloud.appwrite.com (fake domain to represent “AppWrite cloud frontend”).
                                                                              2. The customer removes his AppWrite instance.
                                                                              3. The AppWrite cloud backend calls the Qovery API to delete the customer Environment.
                                                                              4. Qovery deletes the AppWrite application, MariaDB, and Redis databases.

                                                                              We can add other steps like payment (part 5), notifications (part 6), and everything you want - they are not required to make our cloud version functional. Let’s now take a deeper look at the infrastructure.

                                                                              AppWrite cloud frontend and backend (control plane)

                                                                              The AppWrite cloud frontend and backend are the two components that we have to build from scratch. It includes our business logic and customer management system. We will use Hasura for the backend and GatsbyJS for the frontend. We will connect the frontend to the backend via a GraphQL API. The advantage of using Hasura instead of coding our web backend is that we have access to many features (Auth0, Stripe support...) right away. Saving days of work.

                                                                              The goal here is to provide to the customers a web interface to:

                                                                              • Create, update, stop, restart, delete AppWrite instances.
                                                                              • Configure their custom domain.
                                                                              • Charge our customers and let them pay for their subscriptions

                                                                              Qovery and AWS

                                                                              Qovery is the simplest way to deploy apps and manage your infrastructure on AWS. We will use Qovery as an Infrastructure as Code (IaC) API.

                                                                              Qovery provides a production-ready infrastructure on our AWS account in 30 minutes that we will use to host our customers’ instances. The Qovery API provides a high-level abstraction to create for each customer an isolated Environment including:

                                                                              1. An AppWrite app instance with the possibility to scale it horizontally.
                                                                              2. A MariaDB database.
                                                                              3. A Redis database.
                                                                              4. An HTTPS endpoint.
                                                                              5. The option to bind a custom domain with TLS.
                                                                              6. A secure API to manage Environment variables and Secrets.

                                                                              Each Environment is isolated and will be accessible for only one customer. And as admin, Qovery provides a web interface to manage all our customers’ instances and troubleshoot any of their issues.

                                                                              Curious to know more about how Qovery works? Take a look at this page.

                                                                              Qovery and other cloud providers

                                                                              Qovery supports AWS, Digital Ocean, and Scaleway. In this guide, we will focus on AWS to make it simpler. But keep in mind that you can use another supported cloud provider. You can even imagine a feature where your customers can choose the cloud provider of their choice. This is exactly what “MongoDB Atlas” and “Hasura Cloud” do.

                                                                              Side note: Qovery will support Google Cloud Platform and Microsoft Azure for S1 2022.

                                                                              MariaDB - Data persistence and backup

                                                                              Our customers expect us to provide a reliable service and manage the database backups by using a cloud version. For AppWrite, MariaDB is the persistent database and needs to be backed up. Four options with pros and cons do exist:

                                                                              1st option: single-tenant MariaDB container

                                                                              Pros:

                                                                              • Cheap
                                                                              • Fast to spawn
                                                                              • Physical isolation per customer
                                                                              • Decent performance

                                                                              Cons:

                                                                              • You have to manage the backups

                                                                              2nd option: multi-tenant MariaDB container

                                                                              Pros:

                                                                              • The cheapest option (1 container divided by the number of customers means higher margins)
                                                                              • Fast to spawn

                                                                              Cons:

                                                                              • You have to manage the backups
                                                                              • No physical isolation per customer
                                                                              • The more you have customers, the poorest the performance is.
                                                                              • Potential security breaches as many customers are using the same database instance.

                                                                              3rd option: single-tenant managed MariaDB database (AWS RDS MariaDB)

                                                                              Pros:

                                                                              • Backup managed by AWS (point-in-time recovery included)
                                                                              • Physical isolation per customer (security++)
                                                                              • The most performant
                                                                              • Scalable (managed by AWS)

                                                                              Cons:

                                                                              • The most expensive option (~$11 per instance for the cheapest one on AWS US-EAST-2)

                                                                              4th option: multi-tenant managed MariaDB database (AWS RDS MariaDB)

                                                                              Pros:

                                                                              • Backup managed by AWS (point-in-time recovery included)
                                                                              • Higher performance than container version
                                                                              • Scalable (managed by AWS)
                                                                              • Expensive for a few customers, but the more customers you have, the cheaper it is.

                                                                              Cons:

                                                                              • The most expensive option (~$11 per instance for the cheapest one on AWS us-east-2)
                                                                              • Potential security breaches as many customers are using the same database instance.

                                                                              We will pick the third option (single-tenant with managed MariaDB database) to create a state-of-the-art cloud version, but you are free to choose the one you want for your customer. Do not forget your customer expects you to take care of their business.

                                                                              Side note: AppWrite uses Redis as a caching system. Then, we will use a Redis container instance which is the cheapest.

                                                                              Contributors

                                                                              Here is the list of contributors to this first part:

                                                                              • Ricardo Sueiras - Principal Advocate in OSS at AWS
                                                                              • Raman Sharma - VP Product Marketing at DigitalOcean
                                                                              • Anton Babenko - AWS Community Hero and Hashicorp Ambassador
                                                                              • Javier Viola Villanueva - Simulation Network Lead at Parity
                                                                              • Ziad Ghalleb - Product Marketing Manager at Gitguardian
                                                                              • Oliver Juhl - CTO and co-founder at Medusa
                                                                              • Yann Irbah - SRE at Fewlines
                                                                              • Laurent Doguin - ex VP Developer Relation at Clever Cloud
                                                                              • Qovery Team and our community ambassadors (Aggis, Stun3r, Kartik)

                                                                              Thank you to our contributors for their review and suggestions.

                                                                              What’s next

                                                                              Thank you all for taking the time to read until the end. We will build our AppWrite cloud backend and integrate it into the Qovery API in the next part.

                                                                              Tutorial
                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2/index.html b/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2/index.html index 3efb1213c5..122e2cd0a6 100644 --- a/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2/index.html +++ b/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -51,21 +51,21 @@
                                                                              return response, nil
                                                                              }

                                                                              You can see the whole code in your forked repository on Github.

                                                                              Testing AppWrite Cloud Backend

                                                                              Signup

                                                                              After a few minutes of deployment, the first version of our managed cloud solution should be ready. Let's use the Hasura GraphQL API to create a new user.

                                                                              To do so, open your Hasura by clicking the Open button in your Hasura application. Then, run the following mutation in the GraphQL explorer:

                                                                              mutation {
                                                                              Signup(input: {email: "pjeziorowski@qovery.com", password: "mysecret"}) {
                                                                              accessToken
                                                                              }
                                                                              }

                                                                              You'll end up with a response like this:

                                                                              {
                                                                              "data": {
                                                                              "Signup": {
                                                                              "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLXVzZXItaWQiOiIyIiwieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoiYWRtaW4iLCJ4LWhhc3VyYS1hbGxvd2VkLXJvbGVzIjpbImFkbWluIl19LCJleHAiOjE2Mzc0ODAxNDR9.aNv72YwjWXkKItDPxQOe5bB7LPo8ZCZ0Gqb3mR6_KQI"
                                                                              }
                                                                              }
                                                                              }

                                                                              Great! We have just created our first user and received a token to interact with AppWrite Cloud API.

                                                                              Create Project

                                                                              Now, let's create our first managed AppWrite instance. In headers, include Authorization header with the Bearer token received when signing up:

                                                                              mutation {
                                                                              CreateProject(input: {name: "myproject"}) {
                                                                              id
                                                                              name
                                                                              url
                                                                              }
                                                                              }

                                                                              You should see a response similar to this one:

                                                                              {
                                                                              "data": {
                                                                              "CreateProject": {
                                                                              "id": 10,
                                                                              "name": "myproject",
                                                                              "url": "<https://zf3f05b5a-zab0fb2f8-gtw.oom.sh>"
                                                                              }
                                                                              }
                                                                              }

                                                                              Great! In the response, we have received the URL we can use to access our managed AppWrite instance.

                                                                              When we peek into Qovery UI, we see the created project for our managed AppWrite:

                                                                              AppWrite Qovery Case Study

                                                                              Start / Stop Project

                                                                              It's the time to start our project. To do so, run the following mutation:

                                                                              mutation {
                                                                              StartProject(input: {id: 10}) {
                                                                              ok
                                                                              }
                                                                              }

                                                                              We should get this response:

                                                                              {
                                                                              "data": {
                                                                              "StartProject": {
                                                                              "ok": true
                                                                              }
                                                                              }
                                                                              }

                                                                              And looking into Qovery, we'll see our environment is starting:

                                                                              AppWrite Qovery Case Study

                                                                              After a few minutes, our AppWrite instance should be available up and running using the URL from the previous response. We can also list our projects to get all projects' URLs:

                                                                              {
                                                                              project(where: {user: {id: {_eq: 1}}}) {
                                                                              id
                                                                              name
                                                                              url
                                                                              }
                                                                              }

                                                                              Response:

                                                                              {
                                                                              "data": {
                                                                              "project": [
                                                                              {
                                                                              "id": 9,
                                                                              "name": "appwrite1",
                                                                              "url": "https://zd3da7904-z24aae066-gtw.oom.sh"
                                                                              },
                                                                              {
                                                                              "id": 10,
                                                                              "name": "myproject",
                                                                              "url": "https://zf3f05b5a-zab0fb2f8-gtw.oom.sh"
                                                                              }
                                                                              ]
                                                                              }
                                                                              }

                                                                              AppWrite Cloud API domain

                                                                              Now, as the last step of this part of tutorial, let's set up a custom domain for our AppWrite Cloud.

                                                                              To do so, all we need to do is to follow a few simple steps:

                                                                              1. Navigate to the Hasura GraphQL API application in Qovery Console
                                                                              2. Click Add button and select Custom Domain

                                                                              AppWrite Qovery Case Study

                                                                              1. Type the name of desired domain, click Add and copy the Value displayed in the box below

                                                                              AppWrite Qovery Case Study

                                                                              1. Add a CNAME record with value copied in the previous step in your domain provider DNS management settings

                                                                              AppWrite Qovery Case Study

                                                                              1. Restart Hasura application

                                                                              Congratulations, your AppWrite Cloud API will be exposed using your custom domain shortly.

                                                                              Conclusion

                                                                              In this tutorial, we have managed to bootstrap the backend for our AppWrite Cloud solution. Users can register, log in, create and deploy managed AppWrite projects. In the following steps, we will add more functionalities to our AppWrite Cloud offering, set up a nice to use web User Interface and continue adding new features to AppWrite Cloud on top of Qovery.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3/index.html b/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3/index.html index 93062231ec..d481349e8f 100644 --- a/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3/index.html +++ b/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -65,21 +65,21 @@
                                                                              const Signup = (email, password) => {
                                                                              const mutation = useMutation((event) => {
                                                                              event.preventDefault();
                                                                              return axios({
                                                                              url: graphqlApiEndpoint,
                                                                              method: 'post',
                                                                              headers: { 'Authorization': 'Bearer ' + anonymous },
                                                                              data: {
                                                                              query: `
                                                                              query Signup {
                                                                              Signup(email: "${email}", password: "${password}") {
                                                                              accessToken
                                                                              }
                                                                              }
                                                                              `,
                                                                              },
                                                                              })
                                                                              });
                                                                              return <button onClick={(event) => mutation.mutate(event)}>Signup</button>;
                                                                              };

                                                                              This makes the skeleton of our UI:

                                                                              AppWrite Qovery Case Study

                                                                              Clicking on the signup will send a test signup request to our backend - click Signup and see the response with an access token in the network tab of your browser:

                                                                              AppWrite Qovery Case Study

                                                                              To send the request, we use the following piece of code:

                                                                              axios({
                                                                              url: graphqlApiEndpoint,
                                                                              method: 'post',
                                                                              headers: { Authorization: 'Bearer ' + anonymous },
                                                                              data: {
                                                                              query: `
                                                                              mutation {
                                                                              Signup(input: {email: "${email}", password: "${password}"}) {
                                                                              accessToken
                                                                              }
                                                                              }
                                                                              `,
                                                                              },
                                                                              }

                                                                              We use axios HTTP library to send a POST request to our graphqlApiEndpoint (that uses the value of the environment variable we set previously) to run a GraphQL mutation that creates a new user with a given email and password in our AppWrite Cloud backend. In the response, we receive an access token that we can use in the name of the user to interact with the API.

                                                                              The anonymous token sent in the request is a way to interact with unauthenticated endpoints in the Hasura backend.

                                                                              In the next step let’s take care of the list of user projects:

                                                                              const { isLoading, error, data } = useQuery('projects', () => {
                                                                              return axios({
                                                                              url: graphqlApiEndpoint,
                                                                              method: 'POST',
                                                                              headers: { Authorization: 'Bearer ' + token },
                                                                              data: {
                                                                              query: `query Projects {
                                                                              project {
                                                                              id
                                                                              name
                                                                              url
                                                                              }
                                                                              }
                                                                              `,
                                                                              },
                                                                              });
                                                                              });

                                                                              In the snippet above, we use ReactQuery to manage the server state (store the info about the project client-side) and axios for performing the HTTP request. In the headers, we send users’ accessToken, and the payload allows us to specify data that we are interested in about projects we have access to.

                                                                              The response from the query contains info we can use to render the list of AppWrite projects managed by AppWriteCloud:

                                                                              AppWrite Qovery Case Study

                                                                              Now, to display it, add the following piece of code into our dashboard component:

                                                                              {appwriteProjects.map((project) => (
                                                                              <div
                                                                              key={project.id}
                                                                              className="relative rounded-lg border border-gray-300 bg-white px-6 py-5 shadow-sm flex items-center space-x-3 hover:border-gray-400 focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-indigo-500"
                                                                              >
                                                                              <div className="flex-1 min-w-0">
                                                                              <a href="#" className="focus:outline-none">
                                                                              <span
                                                                              className="absolute inset-0"
                                                                              aria-hidden="true"
                                                                              />
                                                                              <p className="text-sm font-medium text-gray-900">
                                                                              {project.name}
                                                                              </p>
                                                                              <a
                                                                              href={project.url}
                                                                              className="text-sm text-gray-500 truncate hover:text-lg"
                                                                              >
                                                                              {project.url}
                                                                              </a>
                                                                              </a>
                                                                              </div>
                                                                              </div>
                                                                              ))}

                                                                              This should allow us to display a list of user’s projects in the dashboard like this:

                                                                              AppWrite Qovery Case Study

                                                                              After improving the sign in form (see the whole code repository here, the whole flow should now look like this:

                                                                              AppWrite Qovery Case Study

                                                                              Conclusion

                                                                              In this article, we bootstrapped a frontend application and added it to our app write cloud. We created the first version of our frontend that makes use of React, Next.js, ReactQuery and Tailwind. The UI is integrated with our backend GraphQL API that is deployed on Qovery and allows us to manage AppWrite projects deployed on AWS for AppWrite Cloud clients.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws/index.html b/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws/index.html index b70a66842a..45539f96da 100644 --- a/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws/index.html +++ b/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -51,21 +51,21 @@ The credentials are available on the Qovery console.

                                                                              mongosh --host 127.0.0.1 \
                                                                              --port ${LOCAL_PORT} \
                                                                              --username <username> \
                                                                              --tls --tlsCAFile <path to downloaded PEM>/rds-combined-ca-bundle.pem \
                                                                              --tlsAllowInvalidCertificates
                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/index.html b/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/index.html index e880e1ac14..31ee388a2c 100644 --- a/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/index.html +++ b/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -51,21 +51,21 @@ would translate to the following namespace: ze0aabc0d-zb91d2eb8.

                                                                            • Identify the right application pod(s)

                                                                              To list the pods running in your environment namespace, run the following command:

                                                                              kubectl get pods --namespace <your namespace>

                                                                              The output should be similar to this one:

                                                                              NAME READY STATUS RESTARTS AGE
                                                                              app-z2fc29b74-5db6745975-nrw8v 1/1 Running 0 29h
                                                                              app-zabbcf976-74f969f848-kzp87 1/1 Running 0 29h

                                                                              The same principle goes for finding the right application pod. Go to the application page on the Qovery console.

                                                                              You'll get an URL looking like this:

                                                                              https://console.qovery.com/platform/organization/<organisation ID>/projects/<project ID>/environments/<environment ID>/applications/abbcf976-27a1-4531-9cdd-e4d15d7b2c27/summary

                                                                              Get the short ID of our application, in our case abbcf976 which means the application pod name will start with app-zabbcf976.

                                                                              In case you setup your app to run multiple replicas, it is possible that you see several pods begining with the same string. You can pick any of them.

                                                                              In our case the right pod corresponding to our application would be app-zabbcf976-74f969f848-kzp87.

                                                                            • Shell into the container

                                                                              To get a shell access to the container running inside the application pod, all you have to do is:

                                                                              kubectl exec -ti --namespace <your namespace> <your pod name> -- sh

                                                                              This will open a shell inside of your application container. You can now execute any command you need.

                                                                            • Conclusion

                                                                              Qovery helps you manage your Kubernetes cluster and deploy your applications on it while still giving you the power of a full access to your cluster.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/how-to-create-an-rds-instance-through-aws-console/index.html b/guides/tutorial/how-to-create-an-rds-instance-through-aws-console/index.html index 887be50457..06503b2273 100644 --- a/guides/tutorial/how-to-create-an-rds-instance-through-aws-console/index.html +++ b/guides/tutorial/how-to-create-an-rds-instance-through-aws-console/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -50,21 +50,21 @@ Chose the allocated storage that fits the needs of your application. We also advise you to Enable storage autoscaling in case you need more storage over time.

                                                                              AWS RDS console

                                                                            • Availability & durability

                                                                              For a production setup you should Create a standby instance. For non-production usecase you can avoid it to reduce costs.

                                                                              AWS RDS console

                                                                            • Connectivity

                                                                              • Since we want the database to live in it's own VPC, make sure to select the Create new VPC option.
                                                                              • Also select Create new DB Subnet Group.
                                                                              • We advise you to disable Public access for security reason. We'll setup VPC peering in the next guide to allow access from your Qovery clusters through private networking.
                                                                              • Finally chose Create new security group and give it a name.

                                                                              AWS RDS console

                                                                            • Database authentication and estimated costs

                                                                              Chose Password authentication.

                                                                              AWS RDS console

                                                                              You can then click on Create database

                                                                            • Database creation

                                                                              You should see your new RDS instance in the list of databases, with the Creating status.

                                                                              AWS RDS console

                                                                            • Name your RDS VPC

                                                                              The VPC created for the new RDS database will be named -. For convenience you should rename it.

                                                                              Click on your database in the list, then on the VPC id.

                                                                              AWS RDS console

                                                                              You will be redirected to the VPCs list, filtered on the VPC id. Click on the edit icon in the Name column, and give it a meaningful name.

                                                                              AWS RDS console

                                                                              AWS RDS console

                                                                            • Conclusion

                                                                              Your RDS database is ready. Now in order to access it from your Qovery cluster, we will need to setup VPC peering. You can find the procedure in this tutorial

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease/index.html b/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease/index.html index d500a16d24..9e296466c0 100644 --- a/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease/index.html +++ b/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -73,21 +73,21 @@
                                                                              CMD ["/app/rust-prime-number-api"]

                                                                              Deploy our Rust REST API app on AWS

                                                                              To deploy our Rust app on AWS we are going to use Qovery. Qovery is the simplest way to deploy any app on AWS. It is the perfect candidate to deploy our Rust REST API in a few steps.

                                                                              Sign up into Qovery

                                                                              First, you need to sign up or sign in on Qovery.

                                                                            • Sign in to the Qovery web interface.

                                                                              Qovery Sign-up page

                                                                            • Connect your AWS account

                                                                              To connect your AWS account check out this guide.

                                                                              Deploy our Rust REST API app

                                                                              Once your AWS account is set-up, you can deploy your Rust app by..

                                                                              Creating a project prime number.

                                                                              Create a project

                                                                              Creating an environment prod.

                                                                              Create an environment

                                                                              Creating an app by selecting your Rust app repository, build mode > Dockerfile, and the port 8000.

                                                                              Create an app

                                                                              And deploy! That's it 🔥... nothing more. Our Rust REST API app is ready

                                                                              Our app is deployed

                                                                              Check out this video to see how I quickly deploy my Rust REST API with Qovery.

                                                                              Watch this video showing the final result 👇

                                                                              Wrapping up

                                                                              Rust combined to Rocket web framework turns building REST API super easy. Deploying your Rust app on AWS with Qovery is as simple as selecting your GitHub repository. Nothing more. Hope you liked it.

                                                                              Useful resources

                                                                              Tutorial
                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/how-to-deploy-helm-charts/index.html b/guides/tutorial/how-to-deploy-helm-charts/index.html index b16feea25f..c91a3001f5 100644 --- a/guides/tutorial/how-to-deploy-helm-charts/index.html +++ b/guides/tutorial/how-to-deploy-helm-charts/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -52,21 +52,21 @@
                                                                              destinations:
                                                                              - name: default
                                                                              path: ./charts

                                                                              Running helm-freeze sync will download the chart cost-analyzer into the charts folder. You can then use this simple Dockerfile which will add all the content of this git repository inside a container:

                                                                              FROM qoveryrd/helm:1.0
                                                                              ADD . /helm
                                                                              ENTRYPOINT ["/helm/run.sh"]

                                                                              Finally, add the run.sh file from the Qovery Helm image inside your repository. Commit now everything. To summarize, in your Git repository you should have:

                                                                              • charts: a folder containing all the charts (here cost-analyzer chart)
                                                                              • Dockerfile: helping you to deploy helm chart and containing all your charts
                                                                              • helm-freeze.yaml: configuration file for helm-freeze
                                                                              • run.sh: the container start script

                                                                              We are now ready to create a Lifecycle job and select your repository:

                                                                              create lifecycle job

                                                                              Then select the Start event, and add ["install"] in the command arguments. In the Delete event, add ["uninstall"]. And configure them to run the install during the Start

                                                                              lifecycle event

                                                                              Set the environment variables to point to the chart to deploy with the release name and other required information:

                                                                              VariableValueSecret
                                                                              HELM_REPO_PATH/helm/charts/cost-analyzerno
                                                                              HELM_RELEASE_NAMEkubecostno
                                                                              HELM_KUBERNETES_NAMESPACEkubecostno

                                                                              Additionally, you can set the Kubecost token if you have a license with additional Helm args like:

                                                                              VariableValueSecret
                                                                              HELM_ADDITIONAL_PARAMS--set kubecostToken="xxx"yes

                                                                              Lifecycle Job and Timeout management

                                                                              The default Helm timeout set by Qovery is 3 minutes. Qovery enables Helm options:

                                                                              • --wait: to wait for all resources to be in a ready state before marking the release as successful
                                                                              • --atomic: to roll back the release if the deployment fails

                                                                              Because of the atomic check, the rollback can take more than 5 minutes. By default, Qovery set the default Lifecycle timeout to 3 minutes, to avoid falling into this issue, but there is no guarantee, it depends on what resources are deployed:

                                                                              Qovery strongly recommends leveraging the default Qovery Lifecycle Job timeout or reducing the default Helm timeout to ensure the rollback will occur properly in case of failure.

                                                                              Conclusion

                                                                              As you can see, deploying Helm charts with Qovery is straightforward. Qovery Lifecycle jobs and its Qovery Helm image should help you a lot if you familiarize yourself with it and its options.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes/index.html b/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes/index.html index 097a49451a..1d585b375d 100644 --- a/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes/index.html +++ b/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -51,21 +51,21 @@ Connect to your cluster and edit the aws-auth configmap in order to add the following code in the mapRoles section:

                                                                              - rolearn: arn:aws:iam::<iam_id>:role/AWSReservedSSO_AdministratorAccess_<the_role_id>
                                                                              username: "{{SessionName}}"
                                                                              groups:
                                                                              - system:masters

                                                                              Deploy your application

                                                                              Once Qovery is installed on your AWS account, you have the possibility to deploy your application. Take a look to our guide on how to deploy your first application with Qovery.

                                                                              Deploy your first application
                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/how-to-integrate-qovery-with-github-actions/index.html b/guides/tutorial/how-to-integrate-qovery-with-github-actions/index.html index a787e9972f..1268855bdd 100644 --- a/guides/tutorial/how-to-integrate-qovery-with-github-actions/index.html +++ b/guides/tutorial/how-to-integrate-qovery-with-github-actions/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -54,21 +54,21 @@ or anything else you need, without sacrificing the simplicity of deployment Qovery brings you.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/how-to-run-commands-at-application-startup/index.html b/guides/tutorial/how-to-run-commands-at-application-startup/index.html index fb8cbbad74..5dadee27a9 100644 --- a/guides/tutorial/how-to-run-commands-at-application-startup/index.html +++ b/guides/tutorial/how-to-run-commands-at-application-startup/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -57,21 +57,21 @@
                                                                              CMD ["rails", "server", "-p", "3000", "-b", "0.0.0.0"]

                                                                              You can learn more about Docker entrypoints here: https://docs.docker.com/engine/reference/builder/#entrypoint

                                                                            • Deploy your application

                                                                              You can now commit and push your changes to your Git repository. The instructions you specified in the entrypoint.sh file will be executed before the application starts.

                                                                            • - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/index.html b/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/index.html index 72692df7cc..426d355b46 100644 --- a/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/index.html +++ b/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -50,21 +50,21 @@
                                                                              location / {
                                                                              root /usr/share/nginx/html/;
                                                                              include /etc/nginx/mime.types;
                                                                              try_files $uri $uri/ /index.html;
                                                                              }
                                                                              }

                                                                              Deployment

                                                                              Now, to deploy the app, create a new application on Qovery with the following configuration:

                                                                              • Port - 80
                                                                              • Build Mode - Docker
                                                                              • Keep other options in default settings

                                                                              After the app is created and configured as above, you can safely run the app deployment. After a few minutes when the app is running, click on the Open button:

                                                                              CloudFront

                                                                              CloudFront

                                                                              To set up CloudFront as a CDN, first, navigate to CloudFront service in AWS console and click on the new distribution button:

                                                                              CloudFront

                                                                              In settings, choose an origin (URL to your frontend app hosted on Qovery):

                                                                              CloudFront

                                                                              You can also tweak other settings or leave them in their defaults:

                                                                              CloudFront

                                                                              Additionally, you can assign an alternate domain to your application in Alternate domain name:

                                                                              CloudFront

                                                                              Adding an alternate domain requires it having a certificate - click on the Request certificate button, type your alternate domain name and use DNS for validation method:

                                                                              CloudFront

                                                                              Request the certificate. In the end, you will see a screen with settings you need to set up in your domain name provider:

                                                                              CloudFront

                                                                              Copy them and save them in your DNS provider settings:

                                                                              CloudFront

                                                                              After it's done, you should be granted a certificate - go back to CloudFront Distribution settings, and pick the certificate for your alternate domain name from the list:

                                                                              CloudFront

                                                                              In the end, you should end up with a CloudFront set up with your app on Qovery and using an alternate domain name. Now it's time for you to tweak the CloudFront settings to meet your needs.

                                                                              CloudFront

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/index.html b/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/index.html index dee3094a8e..1c71887bc4 100644 --- a/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/index.html +++ b/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -49,21 +49,21 @@ We also want to make sure that our MySQL RDS instance is destroyed when our Environment is deleted. So we select the Deleted Event.

                                                                              If you look at our Dockerfile in the repository, you will see that we are using the official Terraform image. I have also inserted by default the ENTRYPOINT ["/bin/sh"] to simplify the Qovery Lifecycle Job configuration.

                                                                              For the Start Event, we want to run the terraform apply -no-color -auto-approve command. We don't need to run the terraform init command since it is already done in the Dockerfile.

                                                                              You will also notice that we are also using && terraform output -json > /qovery-output/qovery-output.json to create a /qovery-output/qovery-output.json file. This file will be used by Qovery to inject the database credentials into our Environment Variables. We will cover this part later.

                                                                              For the Deleted Event, we want to run the terraform destroy -no-color -auto-approve command.

                                                                              So for the Start Event, we have: ["-c","terraform apply -no-color -auto-approve && terraform output -json > /qovery-output/qovery-output.json"] and for the Deleted Event, we have: ["-c","terraform destroy -no-color -auto-approve"]. Feel free to copy/paste these commands.

                                                                            • I recommend setting the Timeout to 1800 seconds (30 minutes). It is the maximum time your Lifecycle Job can run. If your Lifecycle Job takes more than 30 minutes to run it will be stopped by Qovery. In our case, it should take less than 10 minutes to create the AWS RDS MySQL instance. But let's be safe.

                                                                              Click Continue.

                                                                            • Now we need to set the vCPU and RAM required to run our Job. We can allocate 0.5 CPU and 256 MB of RAM. It's more than enough.

                                                                            • We need to set the Environment Variables required by our Lifecycle Job. In our case, we need to set the AWS credentials and some other environment variables. If you look at our Dockerfile, you will find the declaration of all those environment variables. You can copy/paste them.

                                                                              Dockerfile
                                                                              ...
                                                                              ARG TF_VAR_terraform_backend_bucket
                                                                              ARG TF_VAR_aws_region
                                                                              ARG TF_VAR_aws_access_key_id
                                                                              ARG TF_VAR_aws_secret_access_key
                                                                              ARG TF_VAR_qovery_environment_id
                                                                              ...

                                                                              Those are the ones that we need to set.

                                                                              Click on Continue.

                                                                            • Then click on Create (and not Create and Deploy).

                                                                            • Congrats, your Lifecycle Job is created. Now we just need to add the TF_VAR_qovery_environment_id environment variable before launching it.

                                                                              Make your Terraform deployment multi-environments ready

                                                                              To support multiple environments, we need to make sure that the name of the S3 object key where Terraform will store the state of your infrastructure is unique. To do that, we will use the TF_VAR_qovery_environment_id environment variable. This environment variable is automatically created by Qovery and contains the ID of your Environment. We just need to create an environment variable alias.

                                                                              1. Go inside your MySQL RDS service, click on the Variables tab.

                                                                              2. Search for QOVERY_ENVIRONMENT_ID built-in environment variable. Then click on Creat alias

                                                                              3. Set the name of the environment variable to TF_VAR_qovery_environment_id with a service scope and click on Confirm.

                                                                              Deploy AWS RDS MySQL instance

                                                                              1. Now you are ready to deploy your Lifecycle Job and see what happened.

                                                                                The job execution will take approximately 3 to 10 minutes.

                                                                              2. Follow the logs of the job execution by clicking on the Logs button.

                                                                                From the Deployment logs tab you can see that your Lifecycle Job is built and that the terraform init command is executed.

                                                                                From the MySQL RDS tab you can see that the terraform apply -no-color -auto-approve command is executed. The creation of the AWS RDS MySQL instance is in progress.

                                                                              3. Once the deployment is done, you should see that the AWS RDS MySQL instance is green and completed.

                                                                              Get the MySQL RDS credentials from the Lifecycle Job

                                                                              Now that the AWS RDS MySQL instance is created, we need to get the credentials to connect to it. We have use the terraform output -json > /qovery-output/qovery-output.json command to get the credentials. If you go back to the Variables tab of your MySQL RDS service, you will see that the QOVERY_OUTPUT_** environment variables are created.

                                                                              By using terraform output -json > /qovery-output/qovery-output.json Qovery automatically create those environment variables for you. You can use them in your application to connect to the AWS RDS MySQL instance. Learn more on how Lifecycle Job output...

                                                                              FAQ

                                                                              What happen if I delete my environment with your example?

                                                                              If you delete your environment, the AWS RDS MySQL instance will be deleted too. You can see that in the MySQL RDS service logs. You will see that the terraform destroy -no-color -auto-approve command is executed.

                                                                              Can I use the Lifecycle Job to deploy my application?

                                                                              Some users ask us if they can use the Lifecycle Job to deploy their application. The answer is yes!. The Lifecycle Job is designed to deploy all type of resources. However, we recommend using the official Qovery way to deploy applications. Learn more on how to deploy your application...

                                                                              What happen if I clone my Environment with the Lifecycle Job?

                                                                              If you clone an Environment with the Lifecycle Job, the Lifecycle Job will be cloned too. In our example we have set the TF_VAR_qovery_environment_id environment variable to the QOVERY_ENVIRONMENT_ID built-in environment variable. So when you clone your Environment, the QOVERY_ENVIRONMENT_ID built-in environment variable will be different. That's why you need to create a new alias environment variable for the QOVERY_ENVIRONMENT_ID built-in environment variable. Learn more on how to clone an Environment...

                                                                              What happen if I modify my Lifecycle Job after my Environment is deployed?

                                                                              If you modify your Lifecycle Job after your Environment is deployed, the Lifecycle Job will be redeployed. In our example, since the state of our AWS RDS MySQL instance is stored in the S3 bucket, the AWS RDS MySQL instance will not be recreated. However, if you modify the main.tf file, the AWS RDS MySQL instance will be updated.

                                                                              Wrapping up

                                                                              In this guide, we have seen how to use the Lifecycle Job to create an AWS RDS MySQL instance with Terraform. We have also seen how to get the credentials of the AWS RDS MySQL instance to connect to it from our application. To learn more about the Lifecycle Job, you can read the Lifecycle Job documentation. To get more examples, check out the Qovery Lifecycle Examples repository.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/how-to-write-a-dockerfile/index.html b/guides/tutorial/how-to-write-a-dockerfile/index.html index 1cee5b3a9f..6bb0f0e014 100644 --- a/guides/tutorial/how-to-write-a-dockerfile/index.html +++ b/guides/tutorial/how-to-write-a-dockerfile/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -47,21 +47,21 @@

                                                                              How to write a Dockerfile

                                                                              How to write your first Dockerfile in order to deploy your application with Qovery

                                                                              With Qovery, there are two ways to build and deploy your application:

                                                                              1. Without a Dockerfile in your repository: your application is built with Buildpacks
                                                                              2. With a Dockerfile: sometimes Buildpacks won't fit your specific setup, and you'll have to write your Dockerfile.

                                                                              In this article, we'll see, step by step, how to quickly write a proper Dockerfile for any application you would like to deploy.


                                                                              My Sweet Dockerfile

                                                                              If you read this, you probably don't know why Docker is used and what is the purpose of a Dockerfile.

                                                                              Docker is a container engine, building and using images to deploy applications in containers. It looks like virtualization, and each container could be compared to a virtual machine with the minimal setup to run an application.

                                                                              The Dockerfile is your image builder recipe. When Docker uses it, it will follow all instructions to build your application and run it.

                                                                              The first step is to create a file named Dockerfile at your project root level so Qovery would be able to find and use it.

                                                                              Also, to avoid unwanted files from your repository (images, .idea, DS_Store etc.), you need to add a .dockerignore. It will prevent heavy copy tasks of useless files, mostly your project dependencies and libraries you'll get back to with your package manager.

                                                                              The .dockerignore file works like the .gitignore, so add all the path of the useless files and folders in it.

                                                                              FROM

                                                                              The first line you'll add in your Dockerfile is FROM.

                                                                              It will pull an already existing image from Docker Hub. You should most of the time use an image that fits your application language (Node, Python, Java, etc.), but you can go a step backward and begin with a simple Linux image.

                                                                              Your Dockerfile's first line should look like this:

                                                                              FROM <image_name>:<image_version>

                                                                              For example, with python:

                                                                              FROM python:3

                                                                              WORKDIR

                                                                              Since most of the images are Linux-based, a good practice is to set up a directory you'll work in. That's the purpose of the WORKDIR line. It defines a directory and moves you in:

                                                                              FROM <image_name>:<image_version>
                                                                              WORKDIR /app

                                                                              If you now work with a relative path (./), it will be in the app directory.

                                                                              COPY

                                                                              Now you have defined your base image and your working directory, it's time to add your code in. COPY works like cp linux command. First argument is the source and second one is the destination.

                                                                              It's time to copy your source code in the image.

                                                                              FROM <image_name>:<image_version>
                                                                              WORKDIR /app
                                                                              COPY . .

                                                                              Here, the elements of your root folder from your current directory will be added inside the /app folder.

                                                                              RUN

                                                                              One does not simply get source code to run an application.

                                                                              Most of the time, you have some stuff to do before an application execution like downloading/installing peer dependencies and build your application.

                                                                              That's the purpose of RUN lines; it will execute a command and wait to finish the task to go forward.

                                                                              FROM <image_name>:<image_version>
                                                                              WORKDIR /app
                                                                              COPY . .
                                                                              RUN echo "Installing or doing stuff."
                                                                              RUN <my_command>

                                                                              You can set as many RUN lines as you need.

                                                                              EXPOSE

                                                                              If your app needs to be reached from outside the container, you have to open its listening port. EXPOSE is made for this.

                                                                              FROM <image_name>:<image_version>
                                                                              WORKDIR /app
                                                                              COPY . .
                                                                              RUN echo "Installing or doing stuff"
                                                                              RUN <my_command>
                                                                              EXPOSE <app_port>

                                                                              CMD

                                                                              Your application is now ready to run.

                                                                              The last thing to do is to specify how to execute it. Add the CMD line with the same command with all the arguments you use locally to launch your application.

                                                                              FROM <image_name>:<image_version>
                                                                              WORKDIR /app
                                                                              COPY . .
                                                                              RUN echo "Installing or doing stuff"
                                                                              RUN <my_command>
                                                                              EXPOSE <app_port>
                                                                              CMD [ "<command>", "<argument_1>", "<argument_2>" ]

                                                                              Like a local usage, you can set as many arguments as needed.

                                                                              Build your image

                                                                              When Qovery uses your Dockerfile, it first builds it before running it.

                                                                              If the build fails, Qovery won't be able to launch our application. To simplify debugging, you can build your image locally if you have Docker installed on your computer.

                                                                              Open a terminal and set the path at the Dockerfile location, and use the command:

                                                                              cd ~/my/folder/where/my/code/is
                                                                              docker build .

                                                                              It will build your image based on your Dockerfile. You'll see all the logs related to all lines you've added in the Dockerfile.

                                                                              If something goes wrong, it will be printed onto the terminal, and you'll be able to debug it.

                                                                              Test your image

                                                                              If your image builds properly, you can now check how it will be handle by Qovery with the command:

                                                                              qovery run

                                                                              What's next?

                                                                              If you follow this tutorial and everything works perfectly, it's time to deploy your app on Qovery. You will find all the things you need to know here.

                                                                              Tutorial
                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/import-your-environment-variables-with-the-qovery-cli/index.html b/guides/tutorial/import-your-environment-variables-with-the-qovery-cli/index.html index c7c1209c00..1bdf332d3c 100644 --- a/guides/tutorial/import-your-environment-variables-with-the-qovery-cli/index.html +++ b/guides/tutorial/import-your-environment-variables-with-the-qovery-cli/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -52,21 +52,21 @@
                                                                              Qovery: dot env file to import: '.env.development'
                                                                              ? Do you want to import Environment Variables or Secrets? Secrets
                                                                              ? What environment variables do you want to import? [Use arrows to move, space to select, <right> to all, <left> to none, type to filter]
                                                                              [ ] COLOR_BACKGROUND=fff
                                                                              [x] AUTH0_API_KEY_SECRET=0xb33f
                                                                              [ ] API_URL=https://api.mytld.com
                                                                              > [x] STRAPI_API_KEY=x.xxyyyzzz

                                                                              Once validated you will see the following import validation:

                                                                              ? What environment variables do you want to import? STRAPI_API_KEY=x.xxyyyzzz, AUTH0_API_KEY_SECRET=0xb33
                                                                              Qovery: ✅ Secrets successfully imported!

                                                                              Check

                                                                              Open your environment variables console to check that everything has been set correctly.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/index.html b/guides/tutorial/index.html index f25c6a6f1f..2e06332b09 100644 --- a/guides/tutorial/index.html +++ b/guides/tutorial/index.html @@ -21,106 +21,106 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -129,103 +129,103 @@

                                                                              Tutorial Guides

                                                                              Additional step-by-step resources to leverage even more Qovery
                                                                              tutorial

                                                                              Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS

                                                                              read now
                                                                              tutorial

                                                                              Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery

                                                                              read now
                                                                              tutorial

                                                                              Create a blazingly fast REST API in Rust (Part 1/2)

                                                                              read now
                                                                              tutorial

                                                                              Create a Playground Environment on AWS

                                                                              read now
                                                                              tutorial

                                                                              Create your Staging environment from your Production environment on AWS

                                                                              read now
                                                                              tutorial

                                                                              Creating API clients using OpenAPI Tools

                                                                              read now
                                                                              tutorial

                                                                              Customizing Preview URL with Qovery CLI

                                                                              read now
                                                                              tutorial

                                                                              Deploy Rails with PostgreSQL and Sidekiq

                                                                              read now
                                                                              tutorial

                                                                              Deploy Temporal on Kubernetes

                                                                              read now
                                                                              tutorial

                                                                              Getting Started with Preview Environments on AWS

                                                                              read now
                                                                              tutorial

                                                                              Grafana setup with Qovery

                                                                              read now
                                                                              tutorial

                                                                              How to activate SSO to connect to your EKS cluster

                                                                              read now
                                                                              tutorial

                                                                              How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1

                                                                              read now
                                                                              tutorial

                                                                              How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2

                                                                              read now
                                                                              tutorial

                                                                              How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3

                                                                              read now
                                                                              tutorial

                                                                              How to connect to a managed MongoDB instance on AWS

                                                                              read now
                                                                              tutorial

                                                                              How to connect to your EKS cluster with kubectl

                                                                              read now
                                                                              tutorial

                                                                              How to create an RDS instance through the AWS console

                                                                              read now
                                                                              tutorial

                                                                              How to deploy a Rust REST API application on AWS with ease

                                                                              read now
                                                                              tutorial

                                                                              How to deploy Helm charts

                                                                              read now
                                                                              tutorial

                                                                              How to integrate Qovery with GitHub Actions

                                                                              read now
                                                                              tutorial

                                                                              How to run commands before the application starts

                                                                              read now
                                                                              tutorial

                                                                              How to seed a Postgres database on a dev environment

                                                                              read now
                                                                              tutorial

                                                                              How to use CloudFront with a React frontend application on Qovery

                                                                              read now
                                                                              tutorial

                                                                              How to use Github Organizations with Qovery

                                                                              read now
                                                                              tutorial

                                                                              How To Use Lifecycle Job To Deploy Any Kind Of Resources

                                                                              read now
                                                                              tutorial

                                                                              How to write a Dockerfile

                                                                              read now
                                                                              tutorial

                                                                              Import your environment variables with the Qovery CLI

                                                                              read now
                                                                              tutorial

                                                                              Integrate your application logs to Cloudwatch

                                                                              read now
                                                                              tutorial

                                                                              Kubernetes observability and monitoring with Datadog

                                                                              read now
                                                                              tutorial

                                                                              Managing Environment Variables in React (create-react-app)

                                                                              read now
                                                                              tutorial

                                                                              Migrate your application from Heroku to AWS

                                                                              read now
                                                                              tutorial

                                                                              Setting up Cloudflare and Custom Domain on Qovery

                                                                              read now
                                                                              tutorial

                                                                              Setup VPC peering on AWS with Qovery

                                                                              read now
                                                                              tutorial

                                                                              URL Shortener API with Kotlin (Part 1/2)

                                                                              read now
                                                                              tutorial

                                                                              Use an API gateway in front of multiple services

                                                                              read now
                                                                              tutorial

                                                                              Use AWS IAM roles with Qovery

                                                                              read now
                                                                              tutorial

                                                                              Using Amazon SQS and Lambda on Qovery

                                                                              read now
                                                                              tutorial

                                                                              Working with Git Submodules

                                                                              read now
                                                                              tutorial

                                                                              Zero to Hero - How to deploy your apps on AWS in 30 minutes

                                                                              read now
                                                                              - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/index.html b/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/index.html index 50704f904b..59c4609a8e 100644 --- a/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/index.html +++ b/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -55,21 +55,21 @@ We'll install it uning Helm.

                                                                              First add the datadog Helm repository and update your local list:

                                                                              helm repo add datadog https://helm.datadoghq.com
                                                                              helm repo update

                                                                              Then we will install the agent in the datadog namespace:

                                                                              helm install datadog-agent \
                                                                              -n datadog --create-namespace \
                                                                              -f <PATH TO datadog-values.yaml> \
                                                                              --set datadog.apiKey='<API KEY>' \
                                                                              datadog/datadog
                                                                              • Edit the path to the datadog-values.yaml file you created
                                                                              • Replace <API KEY> with your actual API KEY. You can find it under 1 > With Helm V3 > --set datadog.apiKey=<API KEY>
                                                                            • Check the agent is running properly

                                                                              Wait for a minute then run the following command:

                                                                              kubectl get pods -n datadog

                                                                              If the installation was successful, you should see an output similar to this one:

                                                                              NAME READY STATUS RESTARTS AGE
                                                                              datadog-agent-2xhsv 3/3 Running 0 1m
                                                                              datadog-agent-cluster-agent-7f8bddd44-pwjnl 1/1 Running 0 1m
                                                                              datadog-agent-kube-state-metrics-577fcf6778-kc2gk 1/1 Running 0 1m
                                                                              datadog-agent-qfsl2 3/3 Running 0 1m
                                                                              datadog-agent-s5r5r 3/3 Running 0 1m
                                                                            • Finish Setup

                                                                              Once Datadog receives your data, you should be able to click Next on the wizard. You might need to refresh the page in some cases. It can take a couple minutes before your data is ready.

                                                                              You will then arrive on Step 4

                                                                              Datadog - Console

                                                                              You can skip this part if you're not interested in monitoring your cloud account.

                                                                              Finally, restart your applications if you are using APM.

                                                                            • Conclusion

                                                                              You now have Datadog agent running on your Qovery cluster. You can check their Getting Started guide to familiarize yourself with the product: https://docs.datadoghq.com/fr/getting_started.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/managing-env-variables-in-create-react-app/index.html b/guides/tutorial/managing-env-variables-in-create-react-app/index.html index 6cd5befced..f6d2170f17 100644 --- a/guides/tutorial/managing-env-variables-in-create-react-app/index.html +++ b/guides/tutorial/managing-env-variables-in-create-react-app/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -57,21 +57,21 @@
                                                                              location / {
                                                                              root /usr/share/nginx/html/;
                                                                              include /etc/nginx/mime.types;
                                                                              try_files $uri $uri/ /index.html;
                                                                              }
                                                                              }

                                                                              Now, commit and push your changes - your create-react-app is handling env vars properly and is optimized for production usage.

                                                                              Conclusion

                                                                              In the guide, we went through managing environment variables in react / create-react-apps without resorting to using any bash scripts and host it on Qovery using Ngnix server.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/migrate-your-application-from-heroku-to-aws/index.html b/guides/tutorial/migrate-your-application-from-heroku-to-aws/index.html index 5e99a13e6b..211219b4cc 100644 --- a/guides/tutorial/migrate-your-application-from-heroku-to-aws/index.html +++ b/guides/tutorial/migrate-your-application-from-heroku-to-aws/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -53,21 +53,21 @@
                                                                              Qovery: ✅ Environment Variables successfully imported!

                                                                              Connect your frontend app to your backend app

                                                                              To connect your frontend app your backend app we will create an environment variable alias.

                                                                              Here is how to create a frontend app:

                                                                              And now how to connect your frontend app with your backend app:

                                                                              You can also take a look at this forum reply to learn how to do it.

                                                                              Connect your backend app to your database

                                                                              Same as connecting your frontend app to your backend app, you can create an environment variable alias DATABASE_URL for the built-in secret finishing with _DATABASE_URL_INTERNAL.

                                                                              4. Copy data from your Heroku databases to your AWS databases

                                                                              Coming soon with Replibyte

                                                                              5. Deploy your apps!

                                                                              We are finally ready to deploy my applications on AWS!

                                                                              Watch the final result 😎

                                                                              FAQ by Heroku users

                                                                              How to create a custom domain?

                                                                              Check out the documentation on how to configure your custom domain.

                                                                              How to monitor my apps?

                                                                              We do recommend using Datadog or any other monitoring products for monitoring your apps deployed by Qovery. Check out our tutorial on how to install Datadog.

                                                                              Do you have Heroku "Review App" equivalent?

                                                                              Yes, it's what we call Preview Environment

                                                                              How to rollback?

                                                                              Check out the app rollback documentation

                                                                              How auto-scaling works?

                                                                              Check out the app auto-scaling documentation

                                                                              How to manage database migration?

                                                                              Check out our forum reply

                                                                              Is it possible to get a shell / connect to my app?

                                                                              Yes, with the Qovery CLI and the command qovery shell. Check out the documentation.

                                                                              Can I use Terraform and Infrastructure as Code?

                                                                              Absolutely, we have a Qovery Terraform provider available.

                                                                              How can I connect my app to MongoDB Atlas?

                                                                              If you use MongoDB Atlas check out our tutorial about VPC peering and how to securely connect to your existing MongoDB Atlas database.

                                                                              How can I connect my app to an AWS service not managed by Qovery?

                                                                              If you want to connect your app to an AWS service not managed by Qovery, check out our tutorial about VPC peering and how to securely connect to this AWS service.


                                                                              If you have a common question about Qovery, we have a more general FAQ section available.

                                                                              Wrapping up

                                                                              Congrats! You have migrated from Heroku to AWS. Feel free to check out our forum and open a thread if you have any question.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery/index.html b/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery/index.html index 0ea2551901..c6a801ed33 100644 --- a/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery/index.html +++ b/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -49,21 +49,21 @@ By creating and deploying the following service, using the Cloudflared image:

                                                                              Cloudflare

                                                                              Once your tunnel is created and connected, you have to set the public hostname and the related service settings.

                                                                              Cloudflare

                                                                              To get the service name of your application deployed by Qovery, you can get it in your application variables:

                                                                              Cloudflare

                                                                              Conclusion

                                                                              After following the steps from above, our application should be accessible using the custom domain we selected:

                                                                              Cloudflare

                                                                              In the guide we went through all the necessary steps to configure Cloudflare and Qovery to make use of your custom domain.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/url-shortener-api-with-kotlin/index.html b/guides/tutorial/url-shortener-api-with-kotlin/index.html index 7bc6e8c7d7..06bdc1a0f4 100644 --- a/guides/tutorial/url-shortener-api-with-kotlin/index.html +++ b/guides/tutorial/url-shortener-api-with-kotlin/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -80,21 +80,21 @@
                                                                              transaction {
                                                                              // create tables if they do not exist
                                                                              SchemaUtils.createMissingTablesAndColumns(RequestTable, ClickOverTimeTable)
                                                                              }
                                                                              }

                                                                              Deploy

                                                                              To deploy your application and database, click Action and Deploy button in your environments list view:

                                                                              Kotlin URL Shortener

                                                                              To get public URL to the application, open application details and click on Action Open.

                                                                              Kotlin URL Shortener

                                                                              Kotlin URL Shortener

                                                                              Conclusion

                                                                              We have seen that creating an URL shortener API with Ktor and Kotlin is extremely simple. Connecting the application to PostgreSQL is very easy with the Exposed library. In just a few lines of code, the service is fully functional and can be deployed in production very quickly with the help of Qovery. In the next part, we will see how to create a web interface connecting to this API to convert our URLs without using the curl command.

                                                                              Part 2: bind a web interface to the API - [link coming soon]

                                                                              Tutorial
                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services/index.html b/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services/index.html index 12be0acea8..21690ca188 100644 --- a/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services/index.html +++ b/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -53,21 +53,21 @@
                                                                              location ~* ^/?(.*)$ {
                                                                              proxy_pass http://$CORE_BACKEND$request_uri;
                                                                              }

                                                                              Here are the explanation of those rules:

                                                                              1. All the traffic matching the path /api/billing/* is redirect to the BILLING backend.
                                                                              2. All the traffic matching the path /api/messaging/* is redirect to the MESSAGING backend.
                                                                              3. All the traffic matching the path /api/* is redirect to the CORE backend.
                                                                              4. All the traffic by default is redirected to the CORE backend.

                                                                              Notes:

                                                                              1. The rule definition order is from the first to the last to apply. If there is a conflicting rule, then the first matched applies.
                                                                              2. The internal network is in HTTP, that is why the value of the proxy_pass directive starts with http://.
                                                                              3. The connections on api.foo.bar are in HTTPS.
                                                                              4. You can make complex rules like the one below:
                                                                              more complex rule
                                                                              location ~* ^/api/v1/user/(.*)/app/(.*)/index/(.*)/search/?(.*)$ {
                                                                              proxy_pass http://$CORE_BACKEND/api/v1/user/$1/app/$2/index/$3/search/$4$is_args$args;
                                                                              }

                                                                              Create API Gateway app

                                                                              Commit and push your changes. Then go to the Qovery web console, and add your API gateway inside the same environment of your applications.

                                                                              • Build mode: Dockerfile
                                                                              • Port: 80

                                                                              Add environment variables

                                                                              For our gateway, we need to create 3 environment variable aliases corresponding to the internal network names of our applications.

                                                                              • XXX_HOST_INTERNAL -> ALIAS -> BILLING_BACKEND with scope ENVIRONMENT
                                                                              • YYY_HOST_INTERNAL -> ALIAS -> MESSAGING_BACKEND with scope ENVIRONMENT
                                                                              • ZZZ_HOST_INTERNAL -> ALIAS -> CORE_BACKEND with scope ENVIRONMENT

                                                                              How to find the correct environment variable

                                                                              When you have multiple applications within the same environment, it is difficult to find the appropriate environment variable. A workaround is to:

                                                                              1. Go to one of your application
                                                                              2. Find the ID of your application in your URL https://console.qovery.com/platform/organization/xxx/projects/yyy/environments/zzz/applications/082e36c4-7fbb-42b2-9046-37ccce21616a/variables
                                                                              3. Truncate your application ID and take the first segment. For 082e36c4-7fbb-42b2-9046-37ccce21616a it is 082e36c4
                                                                              4. Add the letter z in front of id Z082e36c4.
                                                                              5. All the environment variables containing Z082e36c4 are attached to the corresponding app.

                                                                              Set up custom domain

                                                                              Add a custom domain to expose your API gateway with the domain of your choice. Check out this documentation to set up your domain.

                                                                              Deploy API Gateway

                                                                              Once everything is set up, you can deploy your application.

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/use-aws-iam-roles-with-qovery/index.html b/guides/tutorial/use-aws-iam-roles-with-qovery/index.html index dbebebb913..1af8868d22 100644 --- a/guides/tutorial/use-aws-iam-roles-with-qovery/index.html +++ b/guides/tutorial/use-aws-iam-roles-with-qovery/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                                              Stats
                                                                              8 min read
                                                                              Updated

                                                                              AWS IAM (Identity & Access Management) service allows AWS services to interact with each other by using roles. Those roles can easily be used to give permissions to your Qovery application, container or job.

                                                                              It is a secure way to give your application permissions without having to manage credentials. More than that, it rotates the token automatically.

                                                                              This tutorial will show you how to add AWS IAM roles to your Qovery application, container or job.

                                                                              Application requiring S3 permissions

                                                                              In this first step, we will create a simple application that needs AWS permissions to access s3 buckets.

                                                                              Create an application

                                                                              We are going to will create a simple container, but you can use an existing one if you want (or an application or job).

                                                                              Here is a simple Debian container example:

                                                                              debian app

                                                                              Set only 1 instance and 128MB of memory is enough for this example. Then continue until you have the Create button, there is nothing more to setup.

                                                                              Get Kubernetes namespace name

                                                                              Then in this container (or any application in this environment) Variables, search for the variable called QOVERY_KUBERNETES_NAMESPACE_NAME and copy its value somewhere.

                                                                              debian app

                                                                              It is the Kubernetes namespace name where the container is located.

                                                                              Configure OIDC provider

                                                                              Get your Cluster OIDC provider URL

                                                                              On your AWS console, go to your EKS cluster and Overview section. Copy the OpenID Connect provider URL:

                                                                              EKS OIDC

                                                                              Create an Identity provider

                                                                              On your AWS console, go to IAM service, then Identity providers section, and Add provider button:

                                                                              1. Select the OpenID Connect provider type
                                                                              2. Paste the OpenID Connect provider URL previously copied to Provider URL
                                                                              3. Click on Get thumbprint button, once done the button will change to Edit URL
                                                                              4. Add sts.amazonaws.com as Audience
                                                                              5. Click on Add provider button

                                                                              OIDC Connect

                                                                              Configure AWS IAM roles

                                                                              Create a role

                                                                              Now we can create a role. In the IAM service, go to Roles section, and click on Create role button.

                                                                              You have to select the Trusted entity type. For this tutorial, we are going to use the Web identity type.

                                                                              Set the Identity provider to the one you just created, and the Audience to sts.amazonaws.com. Then click on the Next button.

                                                                              Role create step 1

                                                                              Role permissions

                                                                              Select the policy of your choice. For this example, the policy AmazonS3ReadOnlyAccess will be used to list S3 buckets. Then click on the Next button.

                                                                              To finish, set the role name and description of your choice and click on Create role button.

                                                                              Configure trusted entities

                                                                              Qovery environment scoped role

                                                                              Once created, select your freshly created role, go to the Trust relationships tab, and click on Edit trust policy button.

                                                                              role trusted default

                                                                              Update the policy line regarding the OIDC condition from:

                                                                              "oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:aud": "sts.amazonaws.com"

                                                                              to:

                                                                              "oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:sub": "system:serviceaccount:kubernetes_namespace:service_account_name"

                                                                              Replace:

                                                                              • kubernetes_namespace: with the namespace name, corresponding to the Qovery environment (previously copied in step 1)
                                                                              • service_account_name: define a service account name which will be re-use later (ex: my-s3-role)

                                                                              Once done, click on the Update policy button.

                                                                              Last element to copy and save somewhere: is the role ARN.

                                                                              In the end, you should have something like:

                                                                              {
                                                                              "Version": "2012-10-17",
                                                                              "Statement": [
                                                                              {
                                                                              "Effect": "Allow",
                                                                              "Principal": {
                                                                              "Federated": "arn:aws:iam::yyyyyyy:oidc-provider/oidc.eks.us-east-2.amazonaws.com/id/xxxxxxx"
                                                                              },
                                                                              "Action": "sts:AssumeRoleWithWebIdentity",
                                                                              "Condition": {
                                                                              "StringEquals": {
                                                                              "oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:sub": "system:serviceaccount:kubernetes_namespace:service_account_name"
                                                                              }
                                                                              }
                                                                              }
                                                                              ]
                                                                              }

                                                                              Cluster scoped role

                                                                              If you want to be able to keep the Role and permissions with the "On-demand environment" and "Clone" features, then you have to scope the role "cluster side" instead of the "Kubernetes namespace" side.

                                                                              To do so, update the Condition with StringLike instead of StringEquals, and use a wildcard instead of the namespace name:

                                                                              "Condition": {
                                                                              "StringLike": {
                                                                              "oidc.eks.eu-west-3.amazonaws.com/id/xxxxxxx:sub": "system:serviceaccount:z*:service_account_name"
                                                                              }
                                                                              }

                                                                              Replace:

                                                                              • service_account_name: define a service account name which will be re-use later (ex: my-s3-role)
                                                                              • z*: the wildcard to use to match all namespaces deployed with Qovery

                                                                              Create a service account

                                                                              This step will help you on deploying a service account on your Kubernetes cluster. In case you want to do it manually on the cluster with kubectl, you just have to push a service account like:

                                                                              apiVersion: v1
                                                                              kind: ServiceAccount
                                                                              metadata:
                                                                              name: $SERVICE_ACCOUNT_NAME
                                                                              namespace: $QOVERY_KUBERNETES_NAMESPACE_NAME
                                                                              annotations:
                                                                              eks.amazonaws.com/role-arn: $AWS_ROLE_ARN

                                                                              Kubernetes authentication

                                                                              On AWS, there are several ways to authenticate to Kubernetes. To make it simple, we are going to use a dedicated IAM user, but you can select the best method for your need.

                                                                              From your AWS Console, create an IAM user account, get Access key ID and Secret access key and save them somewhere.

                                                                              Qovery helps IAM users to get quick access to the Kubernetes cluster. Simply add this user to the Admins group.

                                                                              Create a Lifecycle job

                                                                              In the same environment than your application, create a Lifecycle job which will be used to deploy a service account on the Kubernetes cluster:

                                                                              Lifecycle creation

                                                                              Here a container qoveryrd/create-sa:1.0 available on DockerHub made by Qovery is used, but you can fork this repository and update to your needs if you prefer.

                                                                              Click on the Continue button and select the Start event because we want to deploy the service account at the environment start and Delete to delete it if we decide to remove it. Set parameters as well with the according action:

                                                                              Lifecycle creation

                                                                              Then click on the Continue button, set the resources (128Mb is enough) and click on the Continue button.

                                                                              Then add the following environment variables to the job scope:

                                                                              • KUBERNETES_VERSION: the version of your Kubernetes cluster which will be used to download kubectl (ex: 1.23.0)
                                                                              • SERVICE_ACCOUNT_NAME: the name of the service account in Kubernetes (the same name you have declared for the role in the Trusted entities policy section)
                                                                              • AWS_ROLE_ARN: the AWS ARN role you have just created
                                                                              • AWS_ACCESS_KEY_ID: the AWS access key ID of the IAM user you have created (if you decided to use this authentication method)
                                                                              • AWS_SECRET_ACCESS_KEY: the AWS secret access key of the IAM user you have created (if you decided to use this authentication method)

                                                                              Lifecycle creation

                                                                              Then Create the Lifecycle job. Go into the Variables tab and create a Variable Alias on QOVERY_CLOUD_PROVIDER_REGION, name it AWS_DEFAULT_REGION and scope it to the job.

                                                                              Lifecycle creation

                                                                              You can now run your job by clicking on the Deploy now button. You should see the following output in your job logs:

                                                                              -> Ensuring required environment variables are present
                                                                              -> Downloading kubectl version 1.23.0
                                                                              -> Generated service account:
                                                                              apiVersion: v1
                                                                              kind: ServiceAccount
                                                                              metadata:
                                                                              name: my-s3-role
                                                                              namespace: xxxxxx
                                                                              annotations:
                                                                              eks.amazonaws.com/role-arn: arn:aws:iam::xxxxxx:role/my-s3-role
                                                                              -> Getting kubeconfig
                                                                              Added new context arn:aws:eks:region:id:cluster/cluster-name to /root/.kube/config
                                                                              -> Deploying service account
                                                                              serviceaccount/aws-permissions created

                                                                              Set application service account

                                                                              Set service account

                                                                              The final step is to set this service account (pointing to the AWS role) to your application. Go into your application Advanced settings and set the Service account to the one you have just created:

                                                                              Lifecycle creation

                                                                              Deploy your application with the Deploy now button.

                                                                              At this stage, the job should have been executed and the service account should be deployed on your Kubernetes cluster, and the Debian container, running.

                                                                              Validate access

                                                                              To validate the AWS role has correctly been deployed, we can connect to the pod, and see if we have the AWS token. We will use the Qovery CLI to connect to our pod:

                                                                              $ qovery shell
                                                                              Qovery: Select organization
                                                                              Organization:
                                                                              ✔ Qovery
                                                                              Qovery: Select project
                                                                              Project:
                                                                              ✔ AWS roles tutorial
                                                                              Qovery: Select environment
                                                                              Environment:
                                                                              ✔ aws-role
                                                                              Qovery: Select service
                                                                              Services:
                                                                              ✔ debian

                                                                              Now we are connected to the pod, we can check the AWS token:

                                                                              $ env | grep AWS
                                                                              AWS_DEFAULT_REGION=us-east-2
                                                                              AWS_REGION=us-east-2
                                                                              AWS_ROLE_ARN=arn:aws:iam::xxxxxx:role/my-s3-role
                                                                              AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token
                                                                              AWS_STS_REGIONAL_ENDPOINTS=regional

                                                                              Token is here! Let's install the AWS CLI and validate the role access. We should be able to list S3 buckets:

                                                                              $ apt-get update && apt-get -y install awscli
                                                                              $ aws s3 ls
                                                                              2022-09-23 06:56:38 aws-cloudtrail-logs-qovery
                                                                              ...

                                                                              It works! We have access to S3 buckets using the AWS role.

                                                                              Conclusion

                                                                              The first setup phase can be time-consuming. However, once done, applying roles to your applications is very easy and fast. You can now use roles to access any AWS service!

                                                                              - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/working-with-git-submodules/index.html b/guides/tutorial/working-with-git-submodules/index.html index 3fbe1abc1c..620a571561 100644 --- a/guides/tutorial/working-with-git-submodules/index.html +++ b/guides/tutorial/working-with-git-submodules/index.html @@ -21,24 +21,24 @@ - + - + - + - + - + - + - + - + - + @@ -51,21 +51,21 @@ (where xxx can be replaced by anything), containing a private SSH key with access to your Git repository.

                                                                              SSH:

                                                                              [submodule "path/to/module"]
                                                                              url = ssh://user/repo

                                                                              Git:

                                                                              [submodule "path/to/module"]
                                                                              url = git://github.com/torvalds/linux.git
                                                                              - + - + - + - + - + - + - + - + diff --git a/img/configuration/helm/helm_creation_port.png b/img/configuration/helm/helm_creation_port.png new file mode 100644 index 0000000000..3cda53553d Binary files /dev/null and b/img/configuration/helm/helm_creation_port.png differ diff --git a/img/configuration/helm/helm_creation_recap.png b/img/configuration/helm/helm_creation_recap.png new file mode 100644 index 0000000000..d84fdff9e3 Binary files /dev/null and b/img/configuration/helm/helm_creation_recap.png differ diff --git a/img/configuration/organization/helm_repository_1.png b/img/configuration/organization/helm_repository_1.png new file mode 100644 index 0000000000..ae27c34044 Binary files /dev/null and b/img/configuration/organization/helm_repository_1.png differ diff --git a/img/configuration/organization/helm_repository_creation.png b/img/configuration/organization/helm_repository_creation.png new file mode 100644 index 0000000000..89e2463d4b Binary files /dev/null and b/img/configuration/organization/helm_repository_creation.png differ diff --git a/img/configuration/organization/helm_repository_edit.png b/img/configuration/organization/helm_repository_edit.png new file mode 100644 index 0000000000..2af4bc07bf Binary files /dev/null and b/img/configuration/organization/helm_repository_edit.png differ diff --git a/index.html b/index.html index 9b84e64bd0..56aecd0fd0 100644 --- a/index.html +++ b/index.html @@ -21,22 +21,22 @@ - + - + - + - + - + - + - + - + @@ -45,19 +45,19 @@ - + - + - + - + - + - + - + diff --git a/mailing_list/index.html b/mailing_list/index.html index 1902a1c174..ea8aa9b1fe 100644 --- a/mailing_list/index.html +++ b/mailing_list/index.html @@ -17,16 +17,16 @@ - + - + - + - + - + @@ -35,13 +35,13 @@ - + - + - + - + diff --git a/main.18a8c5c9.js b/main.18a8c5c9.js deleted file mode 100644 index 264a6d3549..0000000000 --- a/main.18a8c5c9.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see main.18a8c5c9.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[264],[function(e,t,n){"use strict";e.exports=n(98)},function(e,t,n){"use strict";function o(){return(o=Object.assign||function(e){for(var t=1;t=0;p--){var f=a[p];"."===f?i(a,p):".."===f?(i(a,p),d++):d&&(i(a,p),d--)}if(!s)for(;d--;d)a.unshift("..");!s||""===a[0]||a[0]&&r(a[0])||a.unshift("");var g=a.join("/");return n&&"/"!==g.substr(-1)&&(g+="/"),g};function u(e){return e.valueOf?e.valueOf():Object.prototype.valueOf.call(e)}var l=function e(t,n){if(t===n)return!0;if(null==t||null==n)return!1;if(Array.isArray(t))return Array.isArray(n)&&t.length===n.length&&t.every((function(t,o){return e(t,n[o])}));if("object"==typeof t||"object"==typeof n){var o=u(t),r=u(n);return o!==t||r!==n?e(o,r):Object.keys(Object.assign({},t,n)).every((function(o){return e(t[o],n[o])}))}return!1},s=n(4);function c(e){return"/"===e.charAt(0)?e:"/"+e}function d(e){return"/"===e.charAt(0)?e.substr(1):e}function p(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function f(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function g(e){var t=e.pathname,n=e.search,o=e.hash,r=t||"/";return n&&"?"!==n&&(r+="?"===n.charAt(0)?n:"?"+n),o&&"#"!==o&&(r+="#"===o.charAt(0)?o:"#"+o),r}function m(e,t,n,r){var i;"string"==typeof e?(i=function(e){var t=e||"/",n="",o="",r=t.indexOf("#");-1!==r&&(o=t.substr(r),t=t.substr(0,r));var i=t.indexOf("?");return-1!==i&&(n=t.substr(i),t=t.substr(0,i)),{pathname:t,search:"?"===n?"":n,hash:"#"===o?"":o}}(e)).state=t:(void 0===(i=Object(o.a)({},e)).pathname&&(i.pathname=""),i.search?"?"!==i.search.charAt(0)&&(i.search="?"+i.search):i.search="",i.hash?"#"!==i.hash.charAt(0)&&(i.hash="#"+i.hash):i.hash="",void 0!==t&&void 0===i.state&&(i.state=t));try{i.pathname=decodeURI(i.pathname)}catch(u){throw u instanceof URIError?new URIError('Pathname "'+i.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):u}return n&&(i.key=n),r?i.pathname?"/"!==i.pathname.charAt(0)&&(i.pathname=a(i.pathname,r.pathname)):i.pathname=r.pathname:i.pathname||(i.pathname="/"),i}function h(e,t){return e.pathname===t.pathname&&e.search===t.search&&e.hash===t.hash&&e.key===t.key&&l(e.state,t.state)}function b(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,o,r){if(null!=e){var i="function"==typeof e?e(t,n):e;"string"==typeof i?"function"==typeof o?o(i,r):r(!0):r(!1!==i)}else r(!0)},appendListener:function(e){var n=!0;function o(){n&&e.apply(void 0,arguments)}return t.push(o),function(){n=!1,t=t.filter((function(e){return e!==o}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),o=0;ot?n.splice(t,n.length-t,o):n.push(o),d({action:"PUSH",location:o,index:t,entries:n})}}))},replace:function(e,t){var o=m(e,t,p(),w.location);c.confirmTransitionTo(o,"REPLACE",n,(function(e){e&&(w.entries[w.index]=o,d({action:"REPLACE",location:o}))}))},go:y,goBack:function(){y(-1)},goForward:function(){y(1)},canGo:function(e){var t=w.index+e;return t>=0&&t=0||(r[n]=e[n]);return r}n.d(t,"a",(function(){return o}))},function(e,t,n){e.exports=!n(14)((function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a}))},function(e,t,n){var o=n(28),r=n(57);e.exports=n(10)?function(e,t,n){return o.f(e,t,r(1,n))}:function(e,t,n){return e[t]=n,e}},function(e,t,n){var o=n(5),r=n(17),i=n(11),a=n(16),u=n(30),l=function(e,t,n){var s,c,d,p,f=e&l.F,g=e&l.G,m=e&l.S,h=e&l.P,b=e&l.B,v=g?o:m?o[t]||(o[t]={}):(o[t]||{}).prototype,y=g?r:r[t]||(r[t]={}),w=y.prototype||(y.prototype={});for(s in g&&(n=t),n)d=((c=!f&&v&&void 0!==v[s])?v:n)[s],p=b&&c?u(d,o):h&&"function"==typeof d?u(Function.call,d):d,v&&a(v,s,d,e&l.U),y[s]!=d&&i(y,s,p),h&&w[s]!=d&&(w[s]=d)};o.core=r,l.F=1,l.G=2,l.S=4,l.P=8,l.B=16,l.W=32,l.U=64,l.R=128,e.exports=l},function(e,t){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,t){e.exports=function(e){try{return!!e()}catch(t){return!0}}},function(e,t,n){e.exports=n(110)()},function(e,t,n){var o=n(5),r=n(11),i=n(31),a=n(40)("src"),u=n(104),l=(""+u).split("toString");n(17).inspectSource=function(e){return u.call(e)},(e.exports=function(e,t,n,u){var s="function"==typeof n;s&&(i(n,"name")||r(n,"name",t)),e[t]!==n&&(s&&(i(n,a)||r(n,a,e[t]?""+e[t]:l.join(String(t)))),e===o?e[t]=n:u?e[t]?e[t]=n:r(e,t,n):(delete e[t],r(e,t,n)))})(Function.prototype,"toString",(function(){return"function"==typeof this&&this[a]||u.call(this)}))},function(e,t){var n=e.exports={version:"2.6.11"};"number"==typeof __e&&(__e=n)},function(e,t,n){"use strict";t.a={plugins:["plugin-image-zoom","posthog-docusaurus",["@docusaurus/plugin-content-docs",{sidebarPath:"/home/runner/work/documentation/documentation/website/sidebars.js"}],["@docusaurus/plugin-content-blog",{feedOptions:{type:"all",copyright:"Copyright \xa9 2023 Qovery, Inc.",baseUrl:""}}],"/home/runner/work/documentation/documentation/website/plugins/guides",["@docusaurus/plugin-content-pages",{}],["/home/runner/work/documentation/documentation/website/plugins/sitemap",{}]],themes:[["@docusaurus/theme-classic",{customCss:"/home/runner/work/documentation/documentation/website/src/css/custom.css"}],"@docusaurus/theme-search-algolia"],customFields:{metadata:{cloud_providers:[{dark_logo_path:"/img/logos/aws_white.svg",logo_path:"/img/logos/aws.svg",name:"aws"},{dark_logo_path:"/img/logos/digitalocean_white.svg",logo_path:"/img/logos/digitalocean.svg",name:"digital_ocean"},{dark_logo_path:"/img/logos/scaleway_white.svg",logo_path:"/img/logos/scaleway.svg",name:"scaleway"},{dark_logo_path:"/img/logos/gcp_white.svg",logo_path:"/img/logos/gcp.svg",name:"gcp"},{dark_logo_path:"/img/logos/azure_white.svg",logo_path:"/img/logos/azure.svg",name:"azure"}],databases:[{dark_logo_path:"/img/logos/docker.svg",logo_path:"/img/logos/docker.svg",name:"mysql"},{dark_logo_path:"/img/logos/docker.svg",logo_path:"/img/logos/docker.svg",name:"postgresql"},{dark_logo_path:"/img/logos/docker.svg",logo_path:"/img/logos/docker.svg",name:"mongodb"}],event_types:[],frameworks:[{dark_logo_path:"/img/logos/hasura_white.svg",logo_path:"/img/logos/hasura.svg",name:"hasura"},{dark_logo_path:"/img/logos/laravel.svg",logo_path:"/img/logos/laravel.svg",name:"laravel"},{dark_logo_path:"/img/logos/springboot.svg",logo_path:"/img/logos/springboot.svg",name:"springboot"},{dark_logo_path:"/img/logos/nodejs.svg",logo_path:"/img/logos/nodejs.svg",name:"nodejs"},{dark_logo_path:"/img/logos/flask_white.svg",logo_path:"/img/logos/flask.svg",name:"flask"},{dark_logo_path:"/img/logos/jhipster.svg",logo_path:"/img/logos/jhipster.svg",name:"jhipster"},{dark_logo_path:"/img/logos/gin.svg",logo_path:"/img/logos/gin.svg",name:"gin"},{dark_logo_path:"/img/logos/rails.svg",logo_path:"/img/logos/rails.svg",name:"rails"},{dark_logo_path:"/img/logos/django.svg",logo_path:"/img/logos/django.svg",name:"django"},{dark_logo_path:"/img/logos/deno.svg",logo_path:"/img/logos/deno.svg",name:"deno"},{dark_logo_path:"/img/logos/strapi.svg",logo_path:"/img/logos/strapi.svg",name:"strapi"},{dark_logo_path:"/img/logos/nuxtjs.svg",logo_path:"/img/logos/nuxtjs.svg",name:"nuxtjs"},{dark_logo_path:"/img/logos/discordpy.svg",logo_path:"/img/logos/discordpy.svg",name:"discordpy"},{dark_logo_path:"/img/logos/sinatra.svg",logo_path:"/img/logos/sinatra.svg",name:"sinatra"},{dark_logo_path:"/img/logos/meilisearch.svg",logo_path:"/img/logos/meilisearch.svg",name:"meilisearch"}],guides:{"getting-started":{children:{},description:"Take Qovery from zero to production in less than 10 minutes.",guides:[{author_github:"https://github.com/evoxmusic",description:null,id:"/getting-started/create-a-database",last_modified_on:null,path:"website/guides/getting-started/create-a-database.md",series_position:null,title:"Create a database"},{author_github:"https://github.com/evoxmusic",description:null,id:"/getting-started/setting-custom-domain",last_modified_on:null,path:"website/guides/getting-started/setting-custom-domain.md",series_position:null,title:"Custom domain"},{author_github:"https://github.com/evoxmusic",description:null,id:"/getting-started/debugging",last_modified_on:null,path:"website/guides/getting-started/debugging.md",series_position:null,title:"Debugging"},{author_github:"https://github.com/evoxmusic",description:null,id:"/getting-started/managing-environment-variables",last_modified_on:null,path:"website/guides/getting-started/managing-environment-variables.md",series_position:null,title:"Environment variables"},{author_github:"https://github.com/evoxmusic",description:null,id:"/getting-started/deploy-your-first-application",last_modified_on:null,path:"website/guides/getting-started/deploy-your-first-application.md",series_position:null,title:"Hello World. Deploy your first application."}],name:"getting-started",series:!0,title:"Getting Started"},"cloud-provider":{children:{},description:"Install Qovery on your favorite cloud provider.",guides:[{author_github:"https://github.com/evoxmusic",description:null,id:"/cloud-provider/guide-amazon-web-services",last_modified_on:null,path:"website/guides/cloud-provider/guide-amazon-web-services.md",series_position:null,title:"Install Qovery on your Amazon Web Services account"},{author_github:"https://github.com/evoxmusic",description:null,id:"/cloud-provider/guide-microsoft-azure",last_modified_on:null,path:"website/guides/cloud-provider/guide-microsoft-azure.md",series_position:null,title:"Install Qovery on your Microsoft Azure account"},{author_github:"https://github.com/evoxmusic",description:null,id:"/cloud-provider/guide-scaleway",last_modified_on:null,path:"website/guides/cloud-provider/guide-scaleway.md",series_position:null,title:"Install Qovery on your Scaleway account"},{author_github:"https://github.com/evoxmusic",description:null,id:"/cloud-provider/guide-google-cloud-platform",last_modified_on:null,path:"website/guides/cloud-provider/guide-google-cloud-platform.md",series_position:null,title:"Install Qovery your Google Cloud Platform account"}],name:"cloud-provider",series:!1,title:"Cloud Providers"},provider:{children:{},description:"Install Qovery on one of our supported providers.",guides:[{author_github:"https://github.com/evoxmusic",description:null,id:"/provider/guide-kubernetes",last_modified_on:null,path:"website/guides/provider/guide-kubernetes.md",series_position:null,title:"Install Qovery on your Kubernetes cluster"}],name:"provider",series:!1,title:"Providers"},advanced:{children:{},description:"Go beyond the basics, become a Qovery pro, and extract the full potential of Qovery.",guides:[{author_github:"https://github.com/evoxmusic",description:null,id:"/advanced/continuous-integration",last_modified_on:null,path:"website/guides/advanced/continuous-integration.md",series_position:null,title:"Continuous Integration"},{author_github:"https://github.com/evoxmusic",description:null,id:"/advanced/costs-control",last_modified_on:null,path:"website/guides/advanced/costs-control.md",series_position:null,title:"Costs Control"},{author_github:"https://github.com/evoxmusic",description:null,id:"/advanced/deploy-api-gateway",last_modified_on:null,path:"website/guides/advanced/deploy-api-gateway.md",series_position:null,title:"Deploy API Gateway"},{author_github:"https://github.com/evoxmusic",description:null,id:"/advanced/deploy-aws-services",last_modified_on:null,path:"website/guides/advanced/deploy-aws-services.md",series_position:null,title:"Deploy AWS Services"},{author_github:"https://github.com/evoxmusic",description:null,id:"/advanced/deploy-external-services",last_modified_on:null,path:"website/guides/advanced/deploy-external-services.md",series_position:null,title:"Deploy External Services"},{author_github:"https://github.com/evoxmusic",description:null,id:"/advanced/deploy-frontend",last_modified_on:null,path:"website/guides/advanced/deploy-frontend.md",series_position:null,title:"Deploy Frontend App"},{author_github:"https://github.com/evoxmusic",description:null,id:"/advanced/helm-chart",last_modified_on:null,path:"website/guides/advanced/helm-chart.md",series_position:null,title:"Helm Charts"},{author_github:"https://github.com/pjeziorowski",description:null,id:"/advanced/microservices",last_modified_on:null,path:"website/guides/advanced/microservices.md",series_position:null,title:"Microservices"},{author_github:"https://github.com/evoxmusic",description:null,id:"/advanced/migration",last_modified_on:null,path:"website/guides/advanced/migration.md",series_position:null,title:"Migration"},{author_github:"https://github.com/evoxmusic",description:null,id:"/advanced/monitoring",last_modified_on:null,path:"website/guides/advanced/monitoring.md",series_position:null,title:"Monitoring"},{author_github:"https://github.com/pjeziorowski",description:null,id:"/advanced/monorepository",last_modified_on:null,path:"website/guides/advanced/monorepository.md",series_position:null,title:"Mono repository"},{author_github:"https://github.com/evoxmusic",description:null,id:"/advanced/use-preview-environments",last_modified_on:null,path:"website/guides/advanced/use-preview-environments.md",series_position:null,title:"Preview Environments"},{author_github:"https://github.com/evoxmusic",description:null,id:"/advanced/production",last_modified_on:null,path:"website/guides/advanced/production.md",series_position:null,title:"Production"},{author_github:"https://github.com/evoxmusic",description:null,id:"/advanced/seed-database",last_modified_on:null,path:"website/guides/advanced/seed-database.md",series_position:null,title:"Seed Database"},{author_github:"https://github.com/evoxmusic",description:null,id:"/advanced/terraform",last_modified_on:null,path:"website/guides/advanced/terraform.md",series_position:null,title:"Terraform"}],name:"advanced",series:!1,title:"Advanced"},tutorial:{children:{},description:"Additional step-by-step resources to leverage even more Qovery. ",guides:[{author_github:"https://github.com/pjeziorowski",description:null,id:"/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws",last_modified_on:null,path:"website/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws.md",series_position:null,title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS"},{author_github:"https://github.com/evoxmusic",description:null,id:"/tutorial/build-e2e-testing-ephemeral-environments",last_modified_on:null,path:"website/guides/tutorial/build-e2e-testing-ephemeral-environments.md",series_position:null,title:"Build E2E Testing Ephemeral Environments with GitHub Actions and Qovery"},{author_github:"https://github.com/evoxmusic",description:null,id:"/tutorial/create-a-playground-environment-on-aws",last_modified_on:null,path:"website/guides/tutorial/create-a-playground-environment-on-aws.md",series_position:null,title:"Create a Playground Environment on AWS"},{author_github:"https://github.com/evoxmusic",description:null,id:"/tutorial/create-a-blazingly-fast-api-in-rust-part-1",last_modified_on:null,path:"website/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1.md",series_position:null,title:"Create a blazingly fast REST API in Rust (Part 1/2)"},{author_github:"https://github.com/evoxmusic",description:null,id:"/tutorial/create-your-staging-environment-from-your-production-environment-on-aws",last_modified_on:null,path:"website/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws.md",series_position:null,title:"Create your Staging environment from your Production environment on AWS"},{author_github:"https://github.com/pjeziorowski",description:null,id:"/tutorial/generate-qovery-api-client",last_modified_on:null,path:"website/guides/tutorial/generate-qovery-api-client.md",series_position:null,title:"Creating API clients using OpenAPI Tools"},{author_github:"https://github.com/evoxmusic",description:null,id:"/tutorial/customizing-preview-url-with-qovery-cli",last_modified_on:null,path:"website/guides/tutorial/customizing-preview-url-with-qovery-cli.md",series_position:null,title:"Customizing Preview URL with Qovery CLI"},{author_github:"https://github.com/l0ck3",description:null,id:"/tutorial/deploy-rails-with-postgresql-and-sidekiq",last_modified_on:null,path:"website/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq.md",series_position:null,title:"Deploy Rails with PostgreSQL and Sidekiq"},{author_github:"https://github.com/l0ck3",description:null,id:"/tutorial/deploy-temporal-on-kubernetes",last_modified_on:null,path:"website/guides/tutorial/deploy-temporal-on-kubernetes.md",series_position:null,title:"Deploy Temporal on Kubernetes"},{author_github:"https://github.com/evoxmusic",description:null,id:"/tutorial/getting-started-with-preview-environments-on-aws-for-beginners",last_modified_on:null,path:"website/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners.md",series_position:null,title:"Getting Started with Preview Environments on AWS"},{author_github:"https://github.com/deimosfr",description:null,id:"/tutorial/grafana-install",last_modified_on:null,path:"website/guides/tutorial/grafana-install.md",series_position:null,title:"Grafana setup with Qovery"},{author_github:"https://github.com/evoxmusic",description:null,id:"/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources",last_modified_on:null,path:"website/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources.md",series_position:null,title:"How To Use Lifecycle Job To Deploy Any Kind Of Resources"},{author_github:"https://github.com/evoxmusic",description:null,id:"/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1",last_modified_on:null,path:"website/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1.md",series_position:null,title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 1"},{author_github:"https://github.com/pjeziorowski",description:null,id:"/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2",last_modified_on:null,path:"website/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2.md",series_position:null,title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 2"},{author_github:"https://github.com/pjeziorowski",description:null,id:"/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3",last_modified_on:null,path:"website/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3.md",series_position:null,title:"How to Build a Cloud Version of Your Open Source Software - A Case Study with AppWrite - Part 3"},{author_github:"https://github.com/benjaminch",description:null,id:"/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster",last_modified_on:null,path:"website/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster.md",series_position:null,title:"How to activate SSO to connect to your EKS cluster"},{author_github:"https://github.com/l0ck3",description:null,id:"/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws",last_modified_on:null,path:"website/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws.md",series_position:null,title:"How to connect to a managed MongoDB instance on AWS"},{author_github:"https://github.com/l0ck3",description:null,id:"/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl",last_modified_on:null,path:"website/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl.md",series_position:null,title:"How to connect to your EKS cluster with kubectl"},{author_github:"https://github.com/l0ck3",description:null,id:"/tutorial/how-to-create-an-rds-instance-through-aws-console",last_modified_on:null,path:"website/guides/tutorial/how-to-create-an-rds-instance-through-aws-console.md",series_position:null,title:"How to create an RDS instance through the AWS console"},{author_github:"https://github.com/deimosfr",description:null,id:"/tutorial/how-to-deploy-helm-charts",last_modified_on:null,path:"website/guides/tutorial/how-to-deploy-helm-charts.md",series_position:null,title:"How to deploy Helm charts"},{author_github:"https://github.com/evoxmusic",description:null,id:"/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease",last_modified_on:null,path:"website/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease.md",series_position:null,title:"How to deploy a Rust REST API application on AWS with ease"},{author_github:"https://github.com/l0ck3",description:null,id:"/tutorial/how-to-integrate-qovery-with-github-actions",last_modified_on:null,path:"website/guides/tutorial/how-to-integrate-qovery-with-github-actions.md",series_position:null,title:"How to integrate Qovery with GitHub Actions"},{author_github:"https://github.com/l0ck3",description:null,id:"/tutorial/how-to-run-commands-at-application-startup",last_modified_on:null,path:"website/guides/tutorial/how-to-run-commands-at-application-startup.md",series_position:null,title:"How to run commands before the application starts"},{author_github:"https://github.com/pjeziorowski",description:null,id:"/tutorial/data-seeding-in-postgres",last_modified_on:null,path:"website/guides/tutorial/data-seeding-in-postgres.md",series_position:null,title:"How to seed a Postgres database on a dev environment"},{author_github:"https://github.com/pjeziorowski",description:null,id:"/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery",last_modified_on:null,path:"website/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery.md",series_position:null,title:"How to use CloudFront with a React frontend application on Qovery"},{author_github:"https://github.com/pjeziorowski",description:null,id:"/tutorial/github-organization-repository-access",last_modified_on:null,path:"website/guides/tutorial/github-organization-repository-access.md",series_position:null,title:"How to use Github Organizations with Qovery"},{author_github:"https://github.com/MacLikorne",description:null,id:"/tutorial/how-to-write-a-dockerfile",last_modified_on:null,path:"website/guides/tutorial/how-to-write-a-dockerfile.md",series_position:null,title:"How to write a Dockerfile"},{author_github:"https://github.com/evoxmusic",description:null,id:"/tutorial/import-your-environment-variables-with-the-qovery-cli",last_modified_on:null,path:"website/guides/tutorial/import-your-environment-variables-with-the-qovery-cli.md",series_position:null,title:"Import your environment variables with the Qovery CLI"},{author_github:"https://github.com/deimosfr",description:null,id:"/tutorial/cloudwatch-integration",last_modified_on:null,path:"website/guides/tutorial/cloudwatch-integration.md",series_position:null,title:"Integrate your application logs to Cloudwatch"},{author_github:"https://github.com/l0ck3",description:null,id:"/tutorial/kubernetes-observability-and-monitoring-with-datadog",last_modified_on:null,path:"website/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog.md",series_position:null,title:"Kubernetes observability and monitoring with Datadog"},{author_github:"https://github.com/pjeziorowski",description:null,id:"/tutorial/managing-env-variables-in-create-react-app",last_modified_on:null,path:"website/guides/tutorial/managing-env-variables-in-create-react-app.md",series_position:null,title:"Managing Environment Variables in React (create-react-app)"},{author_github:"https://github.com/evoxmusic",description:null,id:"/tutorial/migrate-your-application-from-heroku-to-aws",last_modified_on:null,path:"website/guides/tutorial/migrate-your-application-from-heroku-to-aws.md",series_position:null,title:"Migrate your application from Heroku to AWS"},{author_github:"https://github.com/jul-dan",description:null,id:"/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery",last_modified_on:null,path:"website/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery.md",series_position:null,title:"Setting up Cloudflare and Custom Domain on Qovery"},{author_github:"https://github.com/l0ck3",description:null,id:"/tutorial/aws-vpc-peering-with-qovery",last_modified_on:null,path:"website/guides/tutorial/aws-vpc-peering-with-qovery.md",series_position:null,title:"Setup VPC peering on AWS with Qovery"},{author_github:"https://github.com/evoxmusic",description:null,id:"/tutorial/url-shortener-api-with-kotlin",last_modified_on:null,path:"website/guides/tutorial/url-shortener-api-with-kotlin.md",series_position:null,title:"URL Shortener API with Kotlin (Part 1/2)"},{author_github:"https://github.com/deimosfr",description:null,id:"/tutorial/use-aws-iam-roles-with-qovery",last_modified_on:null,path:"website/guides/tutorial/use-aws-iam-roles-with-qovery.md",series_position:null,title:"Use AWS IAM roles with Qovery"},{author_github:"https://github.com/evoxmusic",description:null,id:"/tutorial/use-an-api-gateway-in-front-of-multiple-services",last_modified_on:null,path:"website/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services.md",series_position:null,title:"Use an API gateway in front of multiple services"},{author_github:"https://github.com/pjeziorowski",description:null,id:"/tutorial/aws-sqs-lambda-with-qovery",last_modified_on:null,path:"website/guides/tutorial/aws-sqs-lambda-with-qovery.md",series_position:null,title:"Using Amazon SQS and Lambda on Qovery"},{author_github:"https://github.com/pjeziorowski",description:null,id:"/tutorial/working-with-git-submodules",last_modified_on:null,path:"website/guides/tutorial/working-with-git-submodules.md",series_position:null,title:"Working with Git Submodules"},{author_github:"https://github.com/evoxmusic",description:null,id:"/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes",last_modified_on:null,path:"website/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes.md",series_position:null,title:"Zero to Hero - How to deploy your apps on AWS in 30 minutes"}],name:"tutorial",series:!1,title:"Tutorial"},engineering:{children:{},description:"We share our engineering learning with all of you. ",guides:[],name:"engineering",series:!1,title:"Engineering"}},highlights:[],installation:{},languages:[{dark_logo_path:"/img/logos/php.svg",logo_path:"/img/logos/php.svg",name:"php"},{dark_logo_path:"/img/logos/kotlin.svg",logo_path:"/img/logos/kotlin.svg",name:"kotlin"},{dark_logo_path:"/img/logos/java.svg",logo_path:"/img/logos/java.svg",name:"java"},{dark_logo_path:"/img/logos/javascript.svg",logo_path:"/img/logos/javascript.svg",name:"javascript"},{dark_logo_path:"/img/logos/python.svg",logo_path:"/img/logos/python.svg",name:"python"},{dark_logo_path:"/img/logos/rust_white.svg",logo_path:"/img/logos/rust.svg",name:"rust"},{dark_logo_path:"/img/logos/go.svg",logo_path:"/img/logos/go.svg",name:"go"},{dark_logo_path:"/img/logos/ruby.svg",logo_path:"/img/logos/ruby.svg",name:"ruby"},{dark_logo_path:"/img/logos/scala.svg",logo_path:"/img/logos/scala.svg",name:"scala"}],latest_highlight:{},latest_post:{},latest_release:{},post_tags:[],posts:[],providers:[{dark_logo_path:"/img/logos/kubernetes_white.svg",logo_path:"/img/logos/kubernetes.svg",name:"kubernetes"}],releases:{},sinks:{},sources:{},team:[{avatar:"https://github.com/evoxmusic.png",bio:'Romaric is a Software Engineer, and CEO at Qovery. He has 10+ years of experience in R&D. From the Ad-Tech to the financial industry, he has deep expertise in highly-reliable and performant systems.\n',github:"https://github.com/evoxmusic",id:"romaric",keybase:"https://keybase.io/evoxmusic",name:"Romaric P."},{avatar:"https://github.com/deimosfr.png",bio:'Pierre is an SRE, and CTO of Qovery. He has 15+ years of experience in R&D. From the financial to the Ad-Tech industry, he has a strong knowledge in distributed and highly-reliable systems. He\'s also the MariaDB High Performance book author.\n',github:"https://github.com/deimosfr",id:"pierre",keybase:"https://keybase.io/pierre",name:"Pierre M."},{avatar:"https://github.com/pjeziorowski.png",bio:'Patryk is an experienced Software Engineer, and a Backend Developer at Qovery. ',github:"https://github.com/pjeziorowski",id:"patryk",keybase:"https://keybase.io/patryk",name:"Patryk J."},{avatar:"https://github.com/maclikorne.png",bio:'Enzo is a Backend Developer at Qovery. ',github:"https://github.com/MacLikorne",id:"enzo",keybase:"https://keybase.io/enzo",name:"Enzo R."},{avatar:"https://github.com/l0ck3.png",bio:'Yann is a Developer Experience Engineer at Qovery. He has 15+ years of experience in development and SRE.\n',github:"https://github.com/l0ck3",id:"yann",keybase:"https://keybase.io/l0ck3",name:"Yann I."},{avatar:"https://github.com/sileht.png",bio:'Mehdi is Senior DevOps Engineer at Qovery, with 15+ years of software development and managing infrastructures, Co-founder of Mergify, active member of non-profit Tetaneutral.net ISP and Hosting provider, and he also likes to dance on crazy swing rhythm.\n',github:"https://github.com/sileht",id:"mehdi",keybase:"https://keybase.io/mehdi",name:"Mehdi A."},{avatar:"https://github.com/Stun3R.png",bio:'Thibaut is an experienced developer, CTO of Shelt.in and active Qovery contributor. ',github:"https://github.com/Stun3R",id:"thibaut_david",keybase:"https://keybase.io/Stun3R",name:"Thibaut David"},{avatar:"https://github.com/Aggis15.png",bio:"Angelos is a self-taught programmer using Python, Qovery ambassador and contributor. ",github:"https://github.com/Aggis15",id:"Aggis15",keybase:"https://keybase.io/Aggis15",name:"Angelos Rinas"},{avatar:"https://github.com/ilmiont.png",bio:"James Walker is the founder of Heron Web, a UK-based digital agency providing bespoke software development services to SMEs. He has experience managing complete end-to-end web development workflows with DevOps, CI/CD, Docker, and Kubernetes.\n",github:"https://github.com/ilmiont",id:"james_walker",keybase:"https://keybase.io/ilmiont",name:"James Walker"},{avatar:"https://github.com/Qovery.png",bio:"Dhiraj Kumar has 10+ years of experience in Python and Machine learning. I specialize in Data analytics and Machine learning using python. My Primary Expertise includes Python, Flask, Django, Pandas, NumPy, SciKit-Learn, NLP, Docker, Machine Learning, Deep Learning, Chatbot, NLP, Spark, AWS, C#, and Azure\n",github:"https://github.com/dhiraj_kumar",id:"dhiraj_kumar",keybase:"https://keybase.io/dhiraj_kumar",name:"Dhiraj Kumar"},{avatar:"https://github.com/Qovery.png",bio:"Shingai Zivuku is a softwage engineer passionated by the cloud.\n",github:"https://github.com/shingai_zivuku",id:"shingai_zivuku",keybase:"https://keybase.io/shingai_zivuku",name:"Shingai Zivuku"},{avatar:"https://github.com/benjaminch.png",bio:'Benjamin is a senior Backend Developer at Qovery.',github:"https://github.com/benjaminch",id:"benjaminch",keybase:"https://keybase.io/benjaminch",name:"Benjamin Chastanier"},{avatar:"https://github.com/jul-dan.png",bio:'Julien is a Technical Product Manager at Qovery.',github:"https://github.com/jul-dan",id:"jul-dan",keybase:"https://keybase.io/jul-dan",name:"Julien Dan"}],technologies:[{dark_logo_path:"/img/logos/kubernetes_white.svg",logo_path:"/img/logos/kubernetes.svg",name:"kubernetes"},{dark_logo_path:"/img/logos/helm_white.svg",logo_path:"/img/logos/helm.svg",name:"helm"},{dark_logo_path:"/img/logos/docker.svg",logo_path:"/img/logos/docker.svg",name:"docker"},{dark_logo_path:"/img/logos/kotlin.svg",logo_path:"/img/logos/kotlin.svg",name:"kotlin"},{dark_logo_path:"/img/logos/qovery.svg",logo_path:"/img/logos/qovery.svg",name:"qovery"},{dark_logo_path:"/img/logos/posthog.svg",logo_path:"/img/logos/posthog.svg",name:"posthog"},{dark_logo_path:"/img/logos/terraform.svg",logo_path:"/img/logos/terraform.svg",name:"terraform"},{dark_logo_path:"/img/logos/github.svg",logo_path:"/img/logos/github.png",name:"github"}],transforms:{}}},themeConfig:{disableDarkMode:!1,navbar:{hideOnScroll:!0,logo:{alt:"Qovery",src:"img/logo-light.svg",srcDark:"img/logo-dark.svg",url:"https://www.qovery.com"},links:[{to:"guides/",label:"Guides",position:"left"},{to:"docs/",label:"Docs",position:"left"},{to:"guides/tutorial",label:"Tutorials",position:"left"},{href:"https://discuss.qovery.com",label:"Forum",position:"left"},{href:"https://start.qovery.com",label:"Web Console",position:"right"},{href:"https://www.qovery.com",label:"Home",position:"right"},{href:"https://github.com/Qovery",label:"GitHub",position:"right"}]},image:"img/open-graph.png",prism:{theme:{plain:{color:"#393A34",backgroundColor:"#f6f8fa"},styles:[{types:["comment","prolog","doctype","cdata"],style:{color:"#999988",fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}},{types:["string","attr-value"],style:{color:"#e3116c"}},{types:["punctuation","operator"],style:{color:"#393A34"}},{types:["entity","url","symbol","number","boolean","variable","constant","property","regex","inserted"],style:{color:"#36acaa"}},{types:["atrule","keyword","attr-name","selector"],style:{color:"#00a4db"}},{types:["function","deleted","tag"],style:{color:"#d73a49"}},{types:["function-variable"],style:{color:"#6f42c1"}},{types:["tag","selector","keyword"],style:{color:"#00009f"}}]},darkTheme:{plain:{color:"#F8F8F2",backgroundColor:"#282A36"},styles:[{types:["prolog","constant","builtin"],style:{color:"rgb(189, 147, 249)"}},{types:["inserted","function"],style:{color:"rgb(80, 250, 123)"}},{types:["deleted"],style:{color:"rgb(255, 85, 85)"}},{types:["changed"],style:{color:"rgb(255, 184, 108)"}},{types:["punctuation","symbol"],style:{color:"rgb(248, 248, 242)"}},{types:["string","char","tag","selector"],style:{color:"rgb(255, 121, 198)"}},{types:["keyword","variable"],style:{color:"rgb(189, 147, 249)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(98, 114, 164)"}},{types:["attr-name"],style:{color:"rgb(241, 250, 140)"}}]},additionalLanguages:["hcl","rust"]},footer:{links:[{title:"Resources",items:[{label:"Documentation",to:"docs"},{label:"Guides",to:"guides"},{label:"Tutorials",to:"guides/tutorial"},{label:"Engineering",to:"guides/engineering"},{label:"Pricing",to:"https://www.qovery.com/pricing"},{label:"Enterprise",to:"https://www.qovery.com/enterprise"},{label:"API",to:"https://api-doc.qovery.com"},{label:"Github",to:"https://github.com/Qovery"}]},{title:"Community",items:[{label:"Discord",to:"https://discord.qovery.com"},{label:"Forum",to:"https://community.qovery.com"},{label:"Community call",to:"https://www.qovery.com/community-call"},{label:"Goodies",to:"https://shop.qovery.com"},{label:"Roadmap",to:"https://roadmap.qovery.com"},{label:"Replibyte",to:"https://github.com/Qovery/replibyte"}]},{title:"Company",items:[{label:"Blog",to:"https://www.qovery.com/blog"},{label:"Jobs",to:"https://jobs.qovery.com"},{label:"Team",to:"https://www.qovery.com/team"},{label:"Investors",to:"https://www.qovery.com/investors"},{label:"Contact",to:"https://www.qovery.com/contact"}]}],copyright:"\xa9 2023 DESIGNED BY QOVERY | PROUD SILVER MEMBER OF CNCF AND LINUX FOUNDATION | QOVERY BY BIRDSIGHT - ALL RIGHTS RESERVED"},algolia:{appId:"FT65SBJ2DA",apiKey:"02604e8b2e0918e90edd1d9eb8e30f5e",indexName:"qovery",algoliaOptions:{}},googleAnalytics:{trackingId:"UA-129773960-5"},posthog:{apiKey:"phc_IgdG1K2GveDUte1gJ6hlwNbFHCv9nViWETUyLMU7ciq",appUrl:"https://phprox.qovery.com",enableInDevelopment:!1},imageZoom:{selector:"img"}},title:"Qovery",tagline:"Deploy On-demand Environments on AWS, Remarkably Fast",url:"https://hub.qovery.com",baseUrl:"/",favicon:"img/logo-square.svg",organizationName:"Qovery",projectName:"documentation",presets:[],scripts:["/js/intercom.js",{src:"https://www.googletagmanager.com/gtag/js?id=UA-129773960-5",async:!0},"/js/ga.js"],stylesheets:["https://fonts.googleapis.com/css?family=Ubuntu|Roboto|Source+Code+Pro","https://at-ui.github.io/feather-font/css/iconfont.css"]}},function(e,t,n){"use strict";n.d(t,"a",(function(){return u})),n.d(t,"b",(function(){return l}));var o=n(3),r=n(1),i=n(0),a=n.n(i);function u(e,t,n){return void 0===n&&(n=[]),e.some((function(e){var r=e.path?Object(o.f)(t,e):n.length?n[n.length-1].match:o.c.computeRootMatch(t);return r&&(n.push({route:e,match:r}),e.routes&&u(e.routes,t,n)),r})),n}function l(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),e?a.a.createElement(o.d,n,e.map((function(e,n){return a.a.createElement(o.b,{key:e.key||n,path:e.path,exact:e.exact,strict:e.strict,render:function(n){return e.render?e.render(Object(r.a)({},n,{},t,{route:e})):a.a.createElement(e.component,Object(r.a)({},n,t,{route:e}))}})}))):null}},function(e,t){var n=!("undefined"==typeof window||!window.document||!window.document.createElement),o={canUseDOM:n,canUseEventListeners:n&&!(!window.addEventListener&&!window.attachEvent),canUseIntersectionObserver:n&&"IntersectionObserver"in window,canUseViewport:n&&!!window.screen};e.exports=o},function(e,t,n){"use strict";var o=n(36),r={};r[n(2)("toStringTag")]="z",r+""!="[object z]"&&n(16)(Object.prototype,"toString",(function(){return"[object "+o(this)+"]"}),!0)},function(e,t,n){"use strict";var o=n(74),r=n(88),i=n(24),a=n(33);e.exports=n(61)(Array,"Array",(function(e,t){this._t=a(e),this._i=0,this._k=t}),(function(){var e=this._t,t=this._k,n=this._i++;return!e||n>=e.length?(this._t=void 0,r(1)):r(0,"keys"==t?n:"values"==t?e[n]:[n,e[n]])}),"values"),i.Arguments=i.Array,o("keys"),o("values"),o("entries")},function(e,t){var n={}.toString;e.exports=function(e){return n.call(e).slice(8,-1)}},function(e,t){e.exports={}},function(e,t,n){var o=n(107),r=n(65);e.exports=Object.keys||function(e){return o(e,r)}},function(e,t,n){var o=n(35),r=Math.min;e.exports=function(e){return e>0?r(o(e),9007199254740991):0}},function(e,t,n){var o=n(34);e.exports=function(e){return Object(o(e))}},function(e,t,n){var o=n(8),r=n(86),i=n(87),a=Object.defineProperty;t.f=n(10)?Object.defineProperty:function(e,t,n){if(o(e),t=i(t,!0),o(n),r)try{return a(e,t,n)}catch(u){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(e[t]=n.value),e}},function(e,t,n){for(var o=n(22),r=n(25),i=n(16),a=n(5),u=n(11),l=n(24),s=n(2),c=s("iterator"),d=s("toStringTag"),p=l.Array,f={CSSRuleList:!0,CSSStyleDeclaration:!1,CSSValueList:!1,ClientRectList:!1,DOMRectList:!1,DOMStringList:!1,DOMTokenList:!0,DataTransferItemList:!1,FileList:!1,HTMLAllCollection:!1,HTMLCollection:!1,HTMLFormElement:!1,HTMLSelectElement:!1,MediaList:!0,MimeTypeArray:!1,NamedNodeMap:!1,NodeList:!0,PaintRequestList:!1,Plugin:!1,PluginArray:!1,SVGLengthList:!1,SVGNumberList:!1,SVGPathSegList:!1,SVGPointList:!1,SVGStringList:!1,SVGTransformList:!1,SourceBufferList:!1,StyleSheetList:!0,TextTrackCueList:!1,TextTrackList:!1,TouchList:!1},g=r(f),m=0;m0?o:n)(e)}},function(e,t,n){var o=n(23),r=n(2)("toStringTag"),i="Arguments"==o(function(){return arguments}());e.exports=function(e){var t,n,a;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=function(e,t){try{return e[t]}catch(n){}}(t=Object(e),r))?n:i?o(t):"Object"==(a=o(t))&&"function"==typeof t.callee?"Arguments":a}},function(e){e.exports=JSON.parse('{"/":{"component":"c4f5d8e4"},"/community":{"component":"672ba3d6"},"/components":{"component":"54e7632e"},"/contact":{"component":"83e9e333"},"/docs":{"component":"25b7c3f2"},"/guides":{"component":"c6d06197","items":[{"content":"d2397242"},{"content":"44b423be"},{"content":"e4310ee0"},{"content":"0578cd49"},{"content":"48764d63"},{"content":"a156f6a6"},{"content":"56c0a343"},{"content":"1a39f24c"},{"content":"da253275"},{"content":"89caf623"},{"content":"967beaa8"},{"content":"1a6d3985"},{"content":"ff0cde69"},{"content":"cbcbf0e3"},{"content":"5e5fefd2"},{"content":"3e6b1f84"},{"content":"36676680"},{"content":"498daee8"},{"content":"50bab564"},{"content":"2cb76395"},{"content":"3088ad98"},{"content":"df1c18d8"},{"content":"8f02216a"},{"content":"1b633bfd"},{"content":"bc592dc7"},{"content":"acaf40e9"},{"content":"5b95bed2"},{"content":"3986a7a9"},{"content":"de0a75d9"},{"content":"bdd6d8c6"},{"content":"b565c464"},{"content":"a960914c"},{"content":"40ec3bc1"},{"content":"fb1d0a83"},{"content":"9107e302"},{"content":"a1fea8fb"},{"content":"e06f2af5"},{"content":"8d146bfd"},{"content":"bbfbe73c"},{"content":"60296d59"},{"content":"5751c945"},{"content":"228c86a3"},{"content":"d64bf575"},{"content":"3036b36b"},{"content":"280c5e92"},{"content":"e1becc8e"},{"content":"b5eab6bb"},{"content":"072d4c63"},{"content":"dea3d534"},{"content":"6ce627d6"},{"content":"e5b9b0aa"},{"content":"9ecfa6fe"},{"content":"16c36934"},{"content":"16976906"},{"content":"68c0e7f9"},{"content":"e8b0321f"},{"content":"ba43933d"},{"content":"c8223350"},{"content":"05049f86"},{"content":"f7098925"},{"content":"7952d159"},{"content":"c0ab55e0"},{"content":"cbb976f4"},{"content":"f3d8c143"},{"content":"0c18cf89"}],"metadata":"49d2885e"},"/guides/advanced":{"component":"d9deea5f","items":[{"content":"1a39f24c"},{"content":"da253275"},{"content":"5e5fefd2"},{"content":"3e6b1f84"},{"content":"36676680"},{"content":"498daee8"},{"content":"8f02216a"},{"content":"dea3d534"},{"content":"e5b9b0aa"},{"content":"9ecfa6fe"},{"content":"16c36934"},{"content":"16976906"},{"content":"68c0e7f9"},{"content":"e8b0321f"},{"content":"05049f86"}],"metadata":"3e1d77c1"},"/guides/advanced/continuous-integration":{"component":"1c13b173","content":"03d003d1"},"/guides/advanced/costs-control":{"component":"1c13b173","content":"a8a9c166"},"/guides/advanced/deploy-api-gateway":{"component":"1c13b173","content":"b7d53051"},"/guides/advanced/deploy-aws-services":{"component":"1c13b173","content":"5385e737"},"/guides/advanced/deploy-external-services":{"component":"1c13b173","content":"e7d0ec68"},"/guides/advanced/deploy-frontend":{"component":"1c13b173","content":"1dd2c233"},"/guides/advanced/helm-chart":{"component":"1c13b173","content":"c24a85bb"},"/guides/advanced/microservices":{"component":"1c13b173","content":"66bbed7b"},"/guides/advanced/migration":{"component":"1c13b173","content":"10c2e3e6"},"/guides/advanced/monitoring":{"component":"1c13b173","content":"18415bef"},"/guides/advanced/monorepository":{"component":"1c13b173","content":"f756422c"},"/guides/advanced/production":{"component":"1c13b173","content":"93701b40"},"/guides/advanced/seed-database":{"component":"1c13b173","content":"2309a9c8"},"/guides/advanced/terraform":{"component":"1c13b173","content":"9c8ed74f"},"/guides/advanced/use-preview-environments":{"component":"1c13b173","content":"8bfd1931"},"/guides/cloud-provider":{"component":"d9deea5f","items":[{"content":"5751c945"},{"content":"d64bf575"},{"content":"3036b36b"},{"content":"280c5e92"}],"metadata":"4ac9ee63"},"/guides/cloud-provider/guide-amazon-web-services":{"component":"1c13b173","content":"454f50a3"},"/guides/cloud-provider/guide-google-cloud-platform":{"component":"1c13b173","content":"fe264ce1"},"/guides/cloud-provider/guide-microsoft-azure":{"component":"1c13b173","content":"d0db1526"},"/guides/cloud-provider/guide-scaleway":{"component":"1c13b173","content":"ff053ed0"},"/guides/getting-started":{"component":"d9deea5f","items":[{"content":"d2397242"},{"content":"44b423be"},{"content":"e4310ee0"},{"content":"0578cd49"},{"content":"48764d63"}],"metadata":"0e2fb061"},"/guides/getting-started/create-a-database":{"component":"1c13b173","content":"24e60f8a"},"/guides/getting-started/debugging":{"component":"1c13b173","content":"6504a542"},"/guides/getting-started/deploy-your-first-application":{"component":"1c13b173","content":"cc9be38a"},"/guides/getting-started/managing-environment-variables":{"component":"1c13b173","content":"b7280cb5"},"/guides/getting-started/setting-custom-domain":{"component":"1c13b173","content":"c0594016"},"/guides/provider":{"component":"d9deea5f","items":[{"content":"228c86a3"}],"metadata":"998e75d2"},"/guides/provider/guide-kubernetes":{"component":"1c13b173","content":"41961c76"},"/guides/tags":{"component":"3116c1fa","tags":"a81fb19d"},"/guides/tags/cloud-provider-aws":{"component":"004ec9e5","items":[{"content":"a156f6a6"},{"content":"3e6b1f84"},{"content":"1b633bfd"},{"content":"3986a7a9"},{"content":"de0a75d9"},{"content":"bdd6d8c6"},{"content":"a1fea8fb"},{"content":"5751c945"},{"content":"6ce627d6"},{"content":"c8223350"},{"content":"cbb976f4"},{"content":"0c18cf89"}],"metadata":"b795af1c"},"/guides/tags/cloud-provider-azure":{"component":"004ec9e5","items":[{"content":"d64bf575"}],"metadata":"4505e7dd"},"/guides/tags/cloud-provider-gcp":{"component":"004ec9e5","items":[{"content":"280c5e92"}],"metadata":"d24a1a4d"},"/guides/tags/cloud-provider-scaleway":{"component":"004ec9e5","items":[{"content":"3036b36b"}],"metadata":"83c60db1"},"/guides/tags/database-postgresql":{"component":"004ec9e5","items":[{"content":"50bab564"},{"content":"2cb76395"},{"content":"f7098925"}],"metadata":"4a111132"},"/guides/tags/framework-rails":{"component":"004ec9e5","items":[{"content":"50bab564"}],"metadata":"a264e41a"},"/guides/tags/language-javascript":{"component":"004ec9e5","items":[{"content":"498daee8"},{"content":"072d4c63"}],"metadata":"cb05c8fa"},"/guides/tags/language-kotlin":{"component":"004ec9e5","items":[{"content":"f7098925"}],"metadata":"dbe0f891"},"/guides/tags/language-ruby":{"component":"004ec9e5","items":[{"content":"50bab564"}],"metadata":"f7aa8e39"},"/guides/tags/language-rust":{"component":"004ec9e5","items":[{"content":"89caf623"},{"content":"b565c464"}],"metadata":"2e212509"},"/guides/tags/provider-kubernetes":{"component":"004ec9e5","items":[{"content":"228c86a3"}],"metadata":"0c52d983"},"/guides/tags/technology-docker":{"component":"004ec9e5","items":[{"content":"bbfbe73c"}],"metadata":"d4b6ce89"},"/guides/tags/technology-github":{"component":"004ec9e5","items":[{"content":"40ec3bc1"}],"metadata":"60ad046d"},"/guides/tags/technology-helm":{"component":"004ec9e5","items":[{"content":"8f02216a"}],"metadata":"49dea187"},"/guides/tags/technology-qovery":{"component":"004ec9e5","items":[{"content":"d2397242"},{"content":"44b423be"},{"content":"e4310ee0"},{"content":"0578cd49"},{"content":"48764d63"},{"content":"56c0a343"},{"content":"1a39f24c"},{"content":"da253275"},{"content":"967beaa8"},{"content":"1a6d3985"},{"content":"ff0cde69"},{"content":"cbcbf0e3"},{"content":"5e5fefd2"},{"content":"36676680"},{"content":"2cb76395"},{"content":"3088ad98"},{"content":"df1c18d8"},{"content":"bc592dc7"},{"content":"acaf40e9"},{"content":"5b95bed2"},{"content":"a960914c"},{"content":"fb1d0a83"},{"content":"9107e302"},{"content":"e06f2af5"},{"content":"8d146bfd"},{"content":"60296d59"},{"content":"e1becc8e"},{"content":"b5eab6bb"},{"content":"dea3d534"},{"content":"e5b9b0aa"},{"content":"9ecfa6fe"},{"content":"16c36934"},{"content":"16976906"},{"content":"68c0e7f9"},{"content":"e8b0321f"},{"content":"ba43933d"},{"content":"7952d159"},{"content":"c0ab55e0"},{"content":"f3d8c143"}],"metadata":"4c0b3d74"},"/guides/tags/technology-terraform":{"component":"004ec9e5","items":[{"content":"05049f86"}],"metadata":"63ea0c72"},"/guides/tags/type-guide":{"component":"004ec9e5","items":[{"content":"d2397242"},{"content":"44b423be"},{"content":"e4310ee0"},{"content":"0578cd49"},{"content":"48764d63"},{"content":"1a39f24c"},{"content":"da253275"},{"content":"5e5fefd2"},{"content":"3e6b1f84"},{"content":"36676680"},{"content":"498daee8"},{"content":"8f02216a"},{"content":"5751c945"},{"content":"228c86a3"},{"content":"d64bf575"},{"content":"3036b36b"},{"content":"280c5e92"},{"content":"dea3d534"},{"content":"e5b9b0aa"},{"content":"9ecfa6fe"},{"content":"16c36934"},{"content":"16976906"},{"content":"68c0e7f9"},{"content":"e8b0321f"},{"content":"05049f86"}],"metadata":"f11e9a8e"},"/guides/tags/type-tutorial":{"component":"004ec9e5","items":[{"content":"a156f6a6"},{"content":"56c0a343"},{"content":"89caf623"},{"content":"967beaa8"},{"content":"1a6d3985"},{"content":"ff0cde69"},{"content":"cbcbf0e3"},{"content":"50bab564"},{"content":"2cb76395"},{"content":"3088ad98"},{"content":"df1c18d8"},{"content":"1b633bfd"},{"content":"bc592dc7"},{"content":"acaf40e9"},{"content":"5b95bed2"},{"content":"3986a7a9"},{"content":"de0a75d9"},{"content":"bdd6d8c6"},{"content":"b565c464"},{"content":"a960914c"},{"content":"40ec3bc1"},{"content":"fb1d0a83"},{"content":"9107e302"},{"content":"a1fea8fb"},{"content":"e06f2af5"},{"content":"8d146bfd"},{"content":"bbfbe73c"},{"content":"60296d59"},{"content":"e1becc8e"},{"content":"b5eab6bb"},{"content":"072d4c63"},{"content":"6ce627d6"},{"content":"ba43933d"},{"content":"c8223350"},{"content":"f7098925"},{"content":"7952d159"},{"content":"c0ab55e0"},{"content":"cbb976f4"},{"content":"f3d8c143"},{"content":"0c18cf89"}],"metadata":"bf22200e"},"/guides/tutorial":{"component":"d9deea5f","items":[{"content":"a156f6a6"},{"content":"56c0a343"},{"content":"89caf623"},{"content":"967beaa8"},{"content":"1a6d3985"},{"content":"ff0cde69"},{"content":"cbcbf0e3"},{"content":"50bab564"},{"content":"2cb76395"},{"content":"3088ad98"},{"content":"df1c18d8"},{"content":"1b633bfd"},{"content":"bc592dc7"},{"content":"acaf40e9"},{"content":"5b95bed2"},{"content":"3986a7a9"},{"content":"de0a75d9"},{"content":"bdd6d8c6"},{"content":"b565c464"},{"content":"a960914c"},{"content":"40ec3bc1"},{"content":"fb1d0a83"},{"content":"9107e302"},{"content":"a1fea8fb"},{"content":"e06f2af5"},{"content":"8d146bfd"},{"content":"bbfbe73c"},{"content":"60296d59"},{"content":"e1becc8e"},{"content":"b5eab6bb"},{"content":"072d4c63"},{"content":"6ce627d6"},{"content":"ba43933d"},{"content":"c8223350"},{"content":"f7098925"},{"content":"7952d159"},{"content":"c0ab55e0"},{"content":"cbb976f4"},{"content":"f3d8c143"},{"content":"0c18cf89"}],"metadata":"af9ec14b"},"/guides/tutorial/aws-sqs-lambda-with-qovery":{"component":"1c13b173","content":"bbedfc29"},"/guides/tutorial/aws-vpc-peering-with-qovery":{"component":"1c13b173","content":"e9c994cf"},"/guides/tutorial/blazingly-fast-preview-environments-for-nextjs-nodejs-and-mongodb-on-aws":{"component":"1c13b173","content":"94a00d4e"},"/guides/tutorial/build-e2e-testing-ephemeral-environments":{"component":"1c13b173","content":"2121549d"},"/guides/tutorial/cloudwatch-integration":{"component":"1c13b173","content":"83a41d86"},"/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1":{"component":"1c13b173","content":"db372ba8"},"/guides/tutorial/create-a-playground-environment-on-aws":{"component":"1c13b173","content":"2ea1d02e"},"/guides/tutorial/create-your-staging-environment-from-your-production-environment-on-aws":{"component":"1c13b173","content":"410a9ba0"},"/guides/tutorial/customizing-preview-url-with-qovery-cli":{"component":"1c13b173","content":"b76eb9a9"},"/guides/tutorial/data-seeding-in-postgres":{"component":"1c13b173","content":"4592dbe6"},"/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq":{"component":"1c13b173","content":"a3cf753a"},"/guides/tutorial/deploy-temporal-on-kubernetes":{"component":"1c13b173","content":"49a59b02"},"/guides/tutorial/generate-qovery-api-client":{"component":"1c13b173","content":"a4401f0f"},"/guides/tutorial/getting-started-with-preview-environments-on-aws-for-beginners":{"component":"1c13b173","content":"1a3e0044"},"/guides/tutorial/github-organization-repository-access":{"component":"1c13b173","content":"55af4c9e"},"/guides/tutorial/grafana-install":{"component":"1c13b173","content":"5b8d4026"},"/guides/tutorial/how-to-activate-sso-to-connect-to-your-eks-cluster":{"component":"1c13b173","content":"06e8d299"},"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-1":{"component":"1c13b173","content":"10dee872"},"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-2":{"component":"1c13b173","content":"a4c8ecc0"},"/guides/tutorial/how-to-build-a-cloud-version-of-your-open-source-software-part-3":{"component":"1c13b173","content":"b74d0aaa"},"/guides/tutorial/how-to-connect-to-a-managed-mongodb-instance-on-aws":{"component":"1c13b173","content":"eb0c7ce5"},"/guides/tutorial/how-to-connect-to-your-eks-cluster-with-kubectl":{"component":"1c13b173","content":"7aa59ca3"},"/guides/tutorial/how-to-create-an-rds-instance-through-aws-console":{"component":"1c13b173","content":"e4768112"},"/guides/tutorial/how-to-deploy-a-rust-rest-api-application-on-aws-with-ease":{"component":"1c13b173","content":"3da71a70"},"/guides/tutorial/how-to-deploy-helm-charts":{"component":"1c13b173","content":"4fed1128"},"/guides/tutorial/how-to-deploy-your-application-on-aws-in-30-minutes":{"component":"1c13b173","content":"97f5d064"},"/guides/tutorial/how-to-integrate-qovery-with-github-actions":{"component":"1c13b173","content":"c7bfb1d3"},"/guides/tutorial/how-to-run-commands-at-application-startup":{"component":"1c13b173","content":"1d3be599"},"/guides/tutorial/how-to-use-cloudfront-with-react-frontend-application-on-qovery":{"component":"1c13b173","content":"311fe203"},"/guides/tutorial/how-to-use-lifecycle-job-to-deploy-any-kind-of-resources":{"component":"1c13b173","content":"6b7a52aa"},"/guides/tutorial/how-to-write-a-dockerfile":{"component":"1c13b173","content":"a9994e72"},"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli":{"component":"1c13b173","content":"bb89e1a0"},"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog":{"component":"1c13b173","content":"b479fc9a"},"/guides/tutorial/managing-env-variables-in-create-react-app":{"component":"1c13b173","content":"a4459aa8"},"/guides/tutorial/migrate-your-application-from-heroku-to-aws":{"component":"1c13b173","content":"03dbc155"},"/guides/tutorial/setting-up-cloudflare-and-custom-domain-on-qovery":{"component":"1c13b173","content":"e5653b8d"},"/guides/tutorial/url-shortener-api-with-kotlin":{"component":"1c13b173","content":"ab8f5b83"},"/guides/tutorial/use-an-api-gateway-in-front-of-multiple-services":{"component":"1c13b173","content":"35d9179e"},"/guides/tutorial/use-aws-iam-roles-with-qovery":{"component":"1c13b173","content":"5b5f8b70"},"/guides/tutorial/working-with-git-submodules":{"component":"1c13b173","content":"f26e55ec"},"/mailing_list":{"component":"48912b2c"},"/docs/:route":{"component":"1be78505","docsMetadata":"20ac7829"},"/docs/getting-started":{"component":"17896441","content":"d589d3a7"},"/docs/getting-started/basic-concepts":{"component":"17896441","content":"d85dc1ef"},"/docs/getting-started/deploy-my-app":{"component":"17896441","content":"4354960d"},"/docs/getting-started/how-qovery-works":{"component":"17896441","content":"cb2208c1"},"/docs/getting-started/install-qovery":{"component":"17896441","content":"1a1dfe25"},"/docs/getting-started/what-is-qovery":{"component":"17896441","content":"68b95634"},"/docs/getting-started/whats-next":{"component":"17896441","content":"543e268a"},"/docs/security-and-compliance":{"component":"17896441","content":"fcb698a1"},"/docs/security-and-compliance/backup-and-restore":{"component":"17896441","content":"b98931a2"},"/docs/security-and-compliance/encryption":{"component":"17896441","content":"2486bcfc"},"/docs/security-and-compliance/gdpr":{"component":"17896441","content":"7278678a"},"/docs/security-and-compliance/soc2":{"component":"17896441","content":"cf490432"},"/docs/useful-resources/faq":{"component":"17896441","content":"59157ba2"},"/docs/useful-resources/help-and-support":{"component":"17896441","content":"d2075f7f"},"/docs/using-qovery":{"component":"17896441","content":"56cfbe62"},"/docs/using-qovery/audit-logs":{"component":"17896441","content":"b8490823"},"/docs/using-qovery/configuration":{"component":"17896441","content":"fc376fea"},"/docs/using-qovery/configuration/advanced-settings":{"component":"17896441","content":"4f6caeac"},"/docs/using-qovery/configuration/application":{"component":"17896441","content":"8d5726d6"},"/docs/using-qovery/configuration/application-health-checks":{"component":"17896441","content":"91473650"},"/docs/using-qovery/configuration/cloud-service-provider":{"component":"17896441","content":"33b1fe0f"},"/docs/using-qovery/configuration/cloud-service-provider/amazon-web-services":{"component":"17896441","content":"43a5f55b"},"/docs/using-qovery/configuration/cloud-service-provider/digital-ocean":{"component":"17896441","content":"0806b243"},"/docs/using-qovery/configuration/cloud-service-provider/google-cloud-platform":{"component":"17896441","content":"9ab61bc5"},"/docs/using-qovery/configuration/cloud-service-provider/microsoft-azure":{"component":"17896441","content":"e61780f0"},"/docs/using-qovery/configuration/cloud-service-provider/other-csps":{"component":"17896441","content":"b8d420d8"},"/docs/using-qovery/configuration/cloud-service-provider/scaleway":{"component":"17896441","content":"d3437d81"},"/docs/using-qovery/configuration/cluster-advanced-settings":{"component":"17896441","content":"2f1afd92"},"/docs/using-qovery/configuration/clusters":{"component":"17896441","content":"dc00a797"},"/docs/using-qovery/configuration/cronjob":{"component":"17896441","content":"54ad54c7"},"/docs/using-qovery/configuration/database":{"component":"17896441","content":"9feef5a0"},"/docs/using-qovery/configuration/database/mongodb":{"component":"17896441","content":"9ddfc3dc"},"/docs/using-qovery/configuration/database/mysql":{"component":"17896441","content":"accdb2b4"},"/docs/using-qovery/configuration/database/postgresql":{"component":"17896441","content":"baf9cc25"},"/docs/using-qovery/configuration/database/redis":{"component":"17896441","content":"c536ba8c"},"/docs/using-qovery/configuration/deployment-rule":{"component":"17896441","content":"db96bb7d"},"/docs/using-qovery/configuration/environment":{"component":"17896441","content":"a4a09dfe"},"/docs/using-qovery/configuration/environment-variable":{"component":"17896441","content":"07c2f310"},"/docs/using-qovery/configuration/lifecycle-job":{"component":"17896441","content":"16557ade"},"/docs/using-qovery/configuration/object-storage":{"component":"17896441","content":"9d3c5a68"},"/docs/using-qovery/configuration/organization":{"component":"17896441","content":"ff91a867"},"/docs/using-qovery/configuration/organization/api-token":{"component":"17896441","content":"1d187ae3"},"/docs/using-qovery/configuration/organization/container-registry":{"component":"17896441","content":"6b0e113a"},"/docs/using-qovery/configuration/organization/git-repository-access":{"component":"17896441","content":"9406f053"},"/docs/using-qovery/configuration/organization/members-rbac":{"component":"17896441","content":"b2880863"},"/docs/using-qovery/configuration/project":{"component":"17896441","content":"bd10520b"},"/docs/using-qovery/configuration/provider":{"component":"17896441","content":"89de14d0"},"/docs/using-qovery/configuration/provider/kubernetes":{"component":"17896441","content":"30e307eb"},"/docs/using-qovery/configuration/service-health-checks":{"component":"17896441","content":"073aa0b0"},"/docs/using-qovery/configuration/user-account":{"component":"17896441","content":"376f4c3b"},"/docs/using-qovery/deployment":{"component":"17896441","content":"8ca6d3cf"},"/docs/using-qovery/deployment/deploying-with-auto-deploy":{"component":"17896441","content":"39686ad9"},"/docs/using-qovery/deployment/deploying-with-ci-cd":{"component":"17896441","content":"36b4c04d"},"/docs/using-qovery/deployment/deployment-actions":{"component":"17896441","content":"8ae34d0a"},"/docs/using-qovery/deployment/deployment-history":{"component":"17896441","content":"47a329cb"},"/docs/using-qovery/deployment/deployment-pipeline":{"component":"17896441","content":"55ef6d6a"},"/docs/using-qovery/deployment/deployment-strategies":{"component":"17896441","content":"b79e7411"},"/docs/using-qovery/deployment/image-mirroring":{"component":"17896441","content":"6308ca27"},"/docs/using-qovery/deployment/logs":{"component":"17896441","content":"6ebd4d49"},"/docs/using-qovery/deployment/running-and-deployment-statuses":{"component":"17896441","content":"e3c664e0"},"/docs/using-qovery/integration":{"component":"17896441","content":"8d1c77c1"},"/docs/using-qovery/integration/api-integration":{"component":"17896441","content":"d28d5470"},"/docs/using-qovery/integration/container-registry":{"component":"17896441","content":"7f79072b"},"/docs/using-qovery/integration/continuous-integration":{"component":"17896441","content":"1772e35f"},"/docs/using-qovery/integration/continuous-integration/circle-ci":{"component":"17896441","content":"1aa86e56"},"/docs/using-qovery/integration/continuous-integration/github-actions":{"component":"17896441","content":"3a11bd48"},"/docs/using-qovery/integration/continuous-integration/gitlab-ci":{"component":"17896441","content":"120e882c"},"/docs/using-qovery/integration/continuous-integration/jenkins":{"component":"17896441","content":"4dcdbf34"},"/docs/using-qovery/integration/git-repository":{"component":"17896441","content":"2a88660b"},"/docs/using-qovery/integration/monitoring":{"component":"17896441","content":"592d28ca"},"/docs/using-qovery/integration/monitoring/datadog":{"component":"17896441","content":"d471c358"},"/docs/using-qovery/integration/monitoring/new-relic":{"component":"17896441","content":"e1e0a511"},"/docs/using-qovery/integration/secret-manager":{"component":"17896441","content":"888595cd"},"/docs/using-qovery/integration/secret-manager/aws-secrets-manager":{"component":"17896441","content":"dab3a2be"},"/docs/using-qovery/integration/secret-manager/doppler":{"component":"17896441","content":"5e60e078"},"/docs/using-qovery/integration/slack":{"component":"17896441","content":"40a919e7"},"/docs/using-qovery/integration/terraform":{"component":"17896441","content":"deef6d59"},"/docs/using-qovery/integration/webhook":{"component":"17896441","content":"7df50433"},"/docs/using-qovery/interface":{"component":"17896441","content":"3a03b8f9"},"/docs/using-qovery/interface/cli":{"component":"17896441","content":"d9a4c8ef"},"/docs/using-qovery/interface/rest-api":{"component":"17896441","content":"c3f02c14"},"/docs/using-qovery/interface/terraform-interface":{"component":"17896441","content":"f0f90e68"},"/docs/using-qovery/interface/web-interface":{"component":"17896441","content":"58379094"},"/docs/using-qovery/maintenance":{"component":"17896441","content":"ac2c90fd"},"/docs/using-qovery/troubleshoot":{"component":"17896441","content":"b4dda200"},"/docs/using-qovery/troubleshoot/application-troubleshoot":{"component":"17896441","content":"fcd9bd5b"},"/docs/using-qovery/troubleshoot/cluster-troubleshoot":{"component":"17896441","content":"3cfde410"},"/docs/using-qovery/troubleshoot/database-troubleshoot":{"component":"17896441","content":"10ff7003"},"/docs/using-qovery/troubleshoot/lifecycle-troubleshoot":{"component":"17896441","content":"ca4f5154"}}')},function(e,t,n){var o,r;void 0===(r="function"==typeof(o=function(){var e,t,n={version:"0.2.0"},o=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'
                                                                              '};function r(e,t,n){return en?n:e}function i(e){return 100*(-1+e)}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(o[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=r(e,o.minimum,1),n.status=1===e?null:e;var l=n.render(!t),s=l.querySelector(o.barSelector),c=o.speed,d=o.easing;return l.offsetWidth,a((function(t){""===o.positionUsing&&(o.positionUsing=n.getPositioningCSS()),u(s,function(e,t,n){var r;return(r="translate3d"===o.positionUsing?{transform:"translate3d("+i(e)+"%,0,0)"}:"translate"===o.positionUsing?{transform:"translate("+i(e)+"%,0)"}:{"margin-left":i(e)+"%"}).transition="all "+t+"ms "+n,r}(e,c,d)),1===e?(u(l,{transition:"none",opacity:1}),l.offsetWidth,setTimeout((function(){u(l,{transition:"all "+c+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),c)}),c)):setTimeout(t,c)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),o.trickleSpeed)};return o.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*r(Math.random()*t,.1,.95)),t=r(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*o.trickleRate)},e=0,t=0,n.promise=function(o){return o&&"resolved"!==o.state()?(0===t&&n.start(),e++,t++,o.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");s(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=o.template;var r,a=t.querySelector(o.barSelector),l=e?"-100":i(n.status||0),c=document.querySelector(o.parent);return u(a,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),o.showSpinner||(r=t.querySelector(o.spinnerSelector))&&p(r),c!=document.body&&s(c,"nprogress-custom-parent"),c.appendChild(t),t},n.remove=function(){c(document.documentElement,"nprogress-busy"),c(document.querySelector(o.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&p(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var a=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),u=function(){var e=["Webkit","O","Moz","ms"],t={};function n(n){return n=n.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()})),t[n]||(t[n]=function(t){var n=document.body.style;if(t in n)return t;for(var o,r=e.length,i=t.charAt(0).toUpperCase()+t.slice(1);r--;)if((o=e[r]+i)in n)return o;return t}(n))}function o(e,t,o){t=n(t),e.style[t]=o}return function(e,t){var n,r,i=arguments;if(2==i.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&o(e,n,r);else o(e,i[1],i[2])}}();function l(e,t){return("string"==typeof e?e:d(e)).indexOf(" "+t+" ")>=0}function s(e,t){var n=d(e),o=n+t;l(n,t)||(e.className=o.substring(1))}function c(e,t){var n,o=d(e);l(e,t)&&(n=o.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function d(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function p(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n})?o.call(t,n,t,e):o)||(e.exports=r)},function(e,t,n){"use strict";n.d(t,"a",(function(){return d})),n.d(t,"b",(function(){return w}));var o=n(3);n.d(t,"c",(function(){return o.a})),n.d(t,"d",(function(){return o.f})),n.d(t,"e",(function(){return o.g})),n.d(t,"f",(function(){return o.h}));var r=n(6),i=n(0),a=n.n(i),u=n(7),l=(n(15),n(1)),s=n(9),c=n(4),d=function(e){function t(){for(var t,n=arguments.length,o=new Array(n),r=0;r1&&u.call(o[0],n,(function(){for(r=1;re.length)return;if(!(k instanceof l)){if(m&&y!=t.length-1){if(p.lastIndex=w,!(P=p.exec(e)))break;for(var x=P.index+(g?P[1].length:0),E=P.index+P[0].length,_=y,S=w,T=t.length;_=(S+=t[_].length)&&(++y,w=S);if(t[y]instanceof l)continue;C=_-y,k=e.slice(w,S),P.index-=w}else{p.lastIndex=0;var P=p.exec(k),C=1}if(P){g&&(h=P[1]?P[1].length:0),E=(x=P.index+h)+(P=P[0].slice(h)).length;var O=k.slice(0,x),A=k.slice(E),q=[y,C];O&&(++y,w+=O.length,q.push(O));var R=new l(s,f?r.tokenize(P,f):P,b,P,m);if(q.push(R),A&&q.push(A),Array.prototype.splice.apply(t,q),1!=C&&r.matchGrammar(e,t,n,y,w,!0,s),a)break}else if(a)break}}}}},hooks:{add:function(){}},tokenize:function(e,t,n){var o=[e],i=t.rest;if(i){for(var a in i)t[a]=i[a];delete t.rest}return r.matchGrammar(e,o,t,0,0,!1),o}},(i=r.Token=function(e,t,n,o,r){this.type=e,this.content=t,this.alias=n,this.length=0|(o||"").length,this.greedy=!!r}).stringify=function(e,t,n){if("string"==typeof e)return e;if("Array"===r.util.type(e))return e.map((function(n){return i.stringify(n,t,e)})).join("");var o={type:e.type,content:i.stringify(e.content,t,n),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:n};if(e.alias){var a="Array"===r.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(o.classes,a)}var u=Object.keys(o.attributes).map((function(e){return e+'="'+(o.attributes[e]||"").replace(/"/g,""")+'"'})).join(" ");return"<"+o.tag+' class="'+o.classes.join(" ")+'"'+(u?" "+u:"")+">"+o.content+""},r);a.languages.markup={comment://,prolog:/<\?[\s\S]+?\?>/,doctype://i,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/i,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/i,inside:{punctuation:[/^=/,{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},a.languages.markup.tag.inside["attr-value"].inside.entity=a.languages.markup.entity,a.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(a.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^$)/i,lookbehind:!0,inside:a.languages[t]},n.cdata=/^$/i;var o={"included-cdata":{pattern://i,inside:n}};o["language-"+t]={pattern:/[\s\S]+/,inside:a.languages[t]};var r={};r[e]={pattern:RegExp(/(<__[\s\S]*?>)(?:\s*|[\s\S])*?(?=<\/__>)/.source.replace(/__/g,e),"i"),lookbehind:!0,greedy:!0,inside:o},a.languages.insertBefore("markup","cdata",r)}}),a.languages.xml=a.languages.extend("markup",{}),a.languages.html=a.languages.markup,a.languages.mathml=a.languages.markup,a.languages.svg=a.languages.markup,function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|x[0-9a-fA-F]{1,2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)\w+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b\w+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+?)\s*(?:\r?\n|\r)(?:[\s\S])*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:n},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s*(?:\r?\n|\r)(?:[\s\S])*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0},{pattern:/(["'])(?:\\[\s\S]|\$\([^)]+\)|`[^`]+`|(?!\1)[^\\])*\1/,greedy:!0,inside:n}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:n.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|aptitude|apt-cache|apt-get|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:if|then|else|elif|fi|for|while|in|case|esac|function|select|do|done|until)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|break|cd|continue|eval|exec|exit|export|getopts|hash|pwd|readonly|return|shift|test|times|trap|umask|unset|alias|bind|builtin|caller|command|declare|echo|enable|help|let|local|logout|mapfile|printf|read|readarray|source|type|typeset|ulimit|unalias|set|shopt)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:true|false)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|==?|!=?|=~|<<[<-]?|[&\d]?>>|\d?[<>]&?|&[>&]?|\|[&|]?|<=?|>=?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}};for(var o=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],r=n.variable[1].inside,i=0;i=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/},a.languages.c=a.languages.extend("clike",{"class-name":{pattern:/(\b(?:enum|struct)\s+)\w+/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/,number:/(?:\b0x(?:[\da-f]+\.?[\da-f]*|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?)[ful]*/i}),a.languages.insertBefore("c","string",{macro:{pattern:/(^\s*)#\s*[a-z]+(?:[^\r\n\\]|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,alias:"property",inside:{string:{pattern:/(#\s*include\s*)(?:<.+?>|("|')(?:\\?.)+?\2)/,lookbehind:!0},directive:{pattern:/(#\s*)\b(?:define|defined|elif|else|endif|error|ifdef|ifndef|if|import|include|line|pragma|undef|using)\b/,lookbehind:!0,alias:"keyword"}}},constant:/\b(?:__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|stdin|stdout|stderr)\b/}),delete a.languages.c.boolean,a.languages.cpp=a.languages.extend("c",{"class-name":{pattern:/(\b(?:class|enum|struct)\s+)\w+/,lookbehind:!0},keyword:/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+\.?[\da-f']*|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+\.?[\d']*|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]*/i,greedy:!0},operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:true|false)\b/}),a.languages.insertBefore("cpp","string",{"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),function(e){var t=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-]+[\s\S]*?(?:;|(?=\s*\{))/,inside:{rule:/@[\w-]+/}},url:{pattern:RegExp("url\\((?:"+t.source+"|[^\n\r()]*)\\)","i"),inside:{function:/^url/i,punctuation:/^\(|\)$/}},selector:RegExp("[^{}\\s](?:[^{};\"']|"+t.source+")*?(?=\\s*\\{)"),string:{pattern:t,greedy:!0},property:/[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,important:/!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),e.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:n.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:e.languages.css}},alias:"language-css"}},n.tag))}(a),a.languages.css.selector={pattern:a.languages.css.selector,inside:{"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-:.\w]+/,id:/#[-:.\w]+/,attribute:{pattern:/\[(?:[^[\]"']|("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1)*\]/,greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)[-*\w\xA0-\uFFFF]*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},attribute:{pattern:/^(\s*)[-\w\xA0-\uFFFF]+/,lookbehind:!0},value:[/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,{pattern:/(=\s*)[-\w\xA0-\uFFFF]+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],punctuation:/[()]/}},a.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*/i,lookbehind:!0}}),a.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:/#[\da-f]{3,8}/i,entity:/\\[\da-f]{1,8}/i,unit:{pattern:/(\d)(?:%|[a-z]+)/,lookbehind:!0},number:/-?[\d.]+/}),a.languages.javascript=a.languages.extend("clike",{"class-name":[a.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|})\s*)(?:catch|finally)\b/,lookbehind:!0},{pattern:/(^|[^.])\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],number:/\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/,function:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,operator:/-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/}),a.languages.javascript["class-name"][0].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,a.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=\s*($|[\r\n,.;})\]]))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/,lookbehind:!0,inside:a.languages.javascript},{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i,inside:a.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/,lookbehind:!0,inside:a.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/,lookbehind:!0,inside:a.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),a.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:a.languages.javascript}},string:/[\s\S]+/}}}),a.languages.markup&&a.languages.markup.tag.addInlined("script","javascript"),a.languages.js=a.languages.javascript,function(e){var t=e.util.clone(e.languages.javascript);e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=/<\/?(?:[\w.:-]+\s*(?:\s+(?:[\w.:-]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s{'">=]+|\{(?:\{(?:\{[^}]*\}|[^{}])*\}|[^{}])+\}))?|\{\.{3}[a-z_$][\w$]*(?:\.[a-z_$][\w$]*)*\}))*\s*\/?)?>/i,e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/i,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">]+)/i,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.insertBefore("inside","attr-name",{spread:{pattern:/\{\.{3}[a-z_$][\w$]*(?:\.[a-z_$][\w$]*)*\}/,inside:{punctuation:/\.{3}|[{}.]/,"attr-value":/\w+/}}},e.languages.jsx.tag),e.languages.insertBefore("inside","attr-value",{script:{pattern:/=(\{(?:\{(?:\{[^}]*\}|[^}])*\}|[^}])+\})/i,inside:{"script-punctuation":{pattern:/^=(?={)/,alias:"punctuation"},rest:e.languages.jsx},alias:"language-javascript"}},e.languages.jsx.tag);var n=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(n).join(""):""},o=function(t){for(var r=[],i=0;i0&&r[r.length-1].tagName===n(a.content[0].content[1])&&r.pop():"/>"===a.content[a.content.length-1].content||r.push({tagName:n(a.content[0].content[1]),openedBraces:0}):r.length>0&&"punctuation"===a.type&&"{"===a.content?r[r.length-1].openedBraces++:r.length>0&&r[r.length-1].openedBraces>0&&"punctuation"===a.type&&"}"===a.content?r[r.length-1].openedBraces--:u=!0),(u||"string"==typeof a)&&r.length>0&&0===r[r.length-1].openedBraces){var l=n(a);i0&&("string"==typeof t[i-1]||"plain-text"===t[i-1].type)&&(l=n(t[i-1])+l,t.splice(i-1,1),i--),t[i]=new e.Token("plain-text",l,null,l)}a.content&&"string"!=typeof a.content&&o(a.content)}};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||o(e.tokens)}))}(a),function(e){var t=e.languages.javadoclike={parameter:{pattern:/(^\s*(?:\/{3}|\*|\/\*\*)\s*@(?:param|arg|arguments)\s+)\w+/m,lookbehind:!0},keyword:{pattern:/(^\s*(?:\/{3}|\*|\/\*\*)\s*|\{)@[a-z][a-zA-Z-]+\b/m,lookbehind:!0},punctuation:/[{}]/};Object.defineProperty(t,"addSupport",{value:function(t,n){"string"==typeof t&&(t=[t]),t.forEach((function(t){!function(t,n){var o=e.languages[t];if(o){var r=o["doc-comment"];if(!r){var i={"doc-comment":{pattern:/(^|[^\\])\/\*\*[^/][\s\S]*?(?:\*\/|$)/,alias:"comment"}};r=(o=e.languages.insertBefore(t,"comment",i))["doc-comment"]}if(r instanceof RegExp&&(r=o["doc-comment"]={pattern:r}),Array.isArray(r))for(var a=0,u=r.length;a>>?=?|->|([-+&|])\2|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),e.languages.insertBefore("java","class-name",{annotation:{alias:"punctuation",pattern:/(^|[^.])@\w+/,lookbehind:!0},namespace:{pattern:/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)[a-z]\w*(\.[a-z]\w*)+/,lookbehind:!0,inside:{punctuation:/\./}},generics:{pattern:/<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/,inside:{"class-name":n,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}}})}(a),function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,o,r,i){if(n.language===o){var a=n.tokenStack=[];n.code=n.code.replace(r,(function(e){if("function"==typeof i&&!i(e))return e;for(var r,u=a.length;-1!==n.code.indexOf(r=t(o,u));)++u;return a[u]=e,r})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,o){if(n.language===o&&n.tokenStack){n.grammar=e.languages[o];var r=0,i=Object.keys(n.tokenStack);!function a(u){for(var l=0;l=i.length);l++){var s=u[l];if("string"==typeof s||s.content&&"string"==typeof s.content){var c=i[r],d=n.tokenStack[c],p="string"==typeof s?s:s.content,f=t(o,c),g=p.indexOf(f);if(g>-1){++r;var m=p.substring(0,g),h=new e.Token(o,e.tokenize(d,n.grammar),"language-"+o,d),b=p.substring(g+f.length),v=[];m&&v.push.apply(v,a([m])),v.push(h),b&&v.push.apply(v,a([b])),"string"==typeof s?u.splice.apply(u,[l,1].concat(v)):s.content=v}}else s.content&&a(s.content)}return u}(n.tokens)}}}})}(a),function(e){e.languages.php=e.languages.extend("clike",{keyword:/\b(?:__halt_compiler|abstract|and|array|as|break|callable|case|catch|class|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|eval|exit|extends|final|finally|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|namespace|new|or|parent|print|private|protected|public|require|require_once|return|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\b/i,boolean:{pattern:/\b(?:false|true)\b/i,alias:"constant"},constant:[/\b[A-Z_][A-Z0-9_]*\b/,/\b(?:null)\b/i],comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0}}),e.languages.insertBefore("php","string",{"shell-comment":{pattern:/(^|[^\\])#.*/,lookbehind:!0,alias:"comment"}}),e.languages.insertBefore("php","comment",{delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"}}),e.languages.insertBefore("php","keyword",{variable:/\$+(?:\w+\b|(?={))/i,package:{pattern:/(\\|namespace\s+|use\s+)[\w\\]+/,lookbehind:!0,inside:{punctuation:/\\/}}}),e.languages.insertBefore("php","operator",{property:{pattern:/(->)[\w]+/,lookbehind:!0}});var t={pattern:/{\$(?:{(?:{[^{}]+}|[^{}]+)}|[^{}])+}|(^|[^\\{])\$+(?:\w+(?:\[.+?]|->\w+)*)/,lookbehind:!0,inside:{rest:e.languages.php}};e.languages.insertBefore("php","string",{"nowdoc-string":{pattern:/<<<'([^']+)'(?:\r\n?|\n)(?:.*(?:\r\n?|\n))*?\1;/,greedy:!0,alias:"string",inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},"heredoc-string":{pattern:/<<<(?:"([^"]+)"(?:\r\n?|\n)(?:.*(?:\r\n?|\n))*?\1;|([a-z_]\w*)(?:\r\n?|\n)(?:.*(?:\r\n?|\n))*?\2;)/i,greedy:!0,alias:"string",inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:t}},"single-quoted-string":{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0,alias:"string"},"double-quoted-string":{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,alias:"string",inside:{interpolation:t}}}),delete e.languages.php.string,e.hooks.add("before-tokenize",(function(t){if(/<\?/.test(t.code)){e.languages["markup-templating"].buildPlaceholders(t,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#)(?:[^?\n\r]|\?(?!>))*|\/\*[\s\S]*?(?:\*\/|$))*?(?:\?>|$)/gi)}})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"php")}))}(a),function(e){var t=e.languages.javascript,n=/{(?:[^{}]|{(?:[^{}]|{[^{}]*})*})+}/.source,o="(@(?:param|arg|argument|property)\\s+(?:"+n+"\\s+)?)";e.languages.jsdoc=e.languages.extend("javadoclike",{parameter:{pattern:RegExp(o+/[$\w\xA0-\uFFFF.]+(?=\s|$)/.source),lookbehind:!0,inside:{punctuation:/\./}}}),e.languages.insertBefore("jsdoc","keyword",{"optional-parameter":{pattern:RegExp(o+/\[[$\w\xA0-\uFFFF.]+(?:=[^[\]]+)?\](?=\s|$)/.source),lookbehind:!0,inside:{parameter:{pattern:/(^\[)[$\w\xA0-\uFFFF\.]+/,lookbehind:!0,inside:{punctuation:/\./}},code:{pattern:/(=)[\s\S]*(?=\]$)/,lookbehind:!0,inside:t,alias:"language-javascript"},punctuation:/[=[\]]/}},"class-name":[{pattern:RegExp("(@[a-z]+\\s+)"+n),lookbehind:!0,inside:{punctuation:/[.,:?=<>|{}()[\]]/}},{pattern:/(@(?:augments|extends|class|interface|memberof!?|this)\s+)[A-Z]\w*(?:\.[A-Z]\w*)*/,lookbehind:!0,inside:{punctuation:/\./}}],example:{pattern:/(@example\s+)[^@]+?(?=\s*(?:\*\s*)?(?:@\w|\*\/))/,lookbehind:!0,inside:{code:{pattern:/^(\s*(?:\*\s*)?).+$/m,lookbehind:!0,inside:t,alias:"language-javascript"}}}}),e.languages.javadoclike.addSupport("javascript",e.languages.jsdoc)}(a),a.languages.actionscript=a.languages.extend("javascript",{keyword:/\b(?:as|break|case|catch|class|const|default|delete|do|else|extends|finally|for|function|if|implements|import|in|instanceof|interface|internal|is|native|new|null|package|private|protected|public|return|super|switch|this|throw|try|typeof|use|var|void|while|with|dynamic|each|final|get|include|namespace|native|override|set|static)\b/,operator:/\+\+|--|(?:[+\-*\/%^]|&&?|\|\|?|<>?>?|[!=]=?)=?|[~?@]/}),a.languages.actionscript["class-name"].alias="function",a.languages.markup&&a.languages.insertBefore("actionscript","string",{xml:{pattern:/(^|[^.])<\/?\w+(?:\s+[^\s>\/=]+=("|')(?:\\[\s\S]|(?!\2)[^\\])*\2)*\s*\/?>/,lookbehind:!0,inside:{rest:a.languages.markup}}}),function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},rest:e.languages.javascript}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(a),function(e){e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:(?:Uint|Int)(?:8|16|32)|Uint8Clamped|Float(?:32|64))?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|(?:Weak)?(?:Set|Map)|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:/(\.\s*)#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*/,lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|location|navigator|performance|(?:local|session)Storage|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var t=["function","function-variable","method","method-variable","property-access"],n=0;n))/i,delete e.languages.flow.parameter,e.languages.insertBefore("flow","operator",{"flow-punctuation":{pattern:/\{\||\|\}/,alias:"punctuation"}}),Array.isArray(e.languages.flow.keyword)||(e.languages.flow.keyword=[e.languages.flow.keyword]),e.languages.flow.keyword.unshift({pattern:/(^|[^$]\b)(?:type|opaque|declare|Class)\b(?!\$)/,lookbehind:!0},{pattern:/(^|[^$]\B)\$(?:await|Diff|Exact|Keys|ObjMap|PropertyType|Shape|Record|Supertype|Subtype|Enum)\b(?!\$)/,lookbehind:!0})}(a),a.languages.n4js=a.languages.extend("javascript",{keyword:/\b(?:any|Array|boolean|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|module|new|null|number|package|private|protected|public|return|set|static|string|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/}),a.languages.insertBefore("n4js","constant",{annotation:{pattern:/@+\w+/,alias:"operator"}}),a.languages.n4jsd=a.languages.n4js,a.languages.typescript=a.languages.extend("javascript",{keyword:/\b(?:abstract|as|async|await|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|is|keyof|let|module|namespace|new|null|of|package|private|protected|public|readonly|return|require|set|static|super|switch|this|throw|try|type|typeof|var|void|while|with|yield)\b/,builtin:/\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/}),a.languages.ts=a.languages.typescript,function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,o=t.inside.interpolation,r=o.inside["interpolation-punctuation"],i=o.pattern.source;function a(t,o){if(e.languages[t])return{pattern:RegExp("((?:"+o+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function u(e,t){return"___"+t.toUpperCase()+"_"+e+"___"}function l(t,n,o){var r={code:t,grammar:n,language:o};return e.hooks.run("before-tokenize",r),r.tokens=e.tokenize(r.code,r.grammar),e.hooks.run("after-tokenize",r),r.tokens}function s(t){var n={};n["interpolation-punctuation"]=r;var i=e.tokenize(t,n);if(3===i.length){var a=[1,1];a.push.apply(a,l(i[1],e.languages.javascript,"javascript")),i.splice.apply(i,a)}return new e.Token("interpolation",i,o.alias,t)}function c(t,n,o){var r=e.tokenize(t,{interpolation:{pattern:RegExp(i),lookbehind:!0}}),a=0,c={},d=l(r.map((function(e){if("string"==typeof e)return e;for(var n,r=e.content;-1!==t.indexOf(n=u(a++,o)););return c[n]=r,n})).join(""),n,o),p=Object.keys(c);return a=0,function e(t){for(var n=0;n=p.length)return;var o=t[n];if("string"==typeof o||"string"==typeof o.content){var r=p[a],i="string"==typeof o?o:o.content,u=i.indexOf(r);if(-1!==u){++a;var l=i.substring(0,u),d=s(c[r]),f=i.substring(u+r.length),g=[];if(l&&g.push(l),g.push(d),f){var m=[f];e(m),g.push.apply(g,m)}"string"==typeof o?(t.splice.apply(t,[n,1].concat(g)),n+=g.length-1):o.content=g}}else{var h=o.content;Array.isArray(h)?e(h):e([h])}}}(d),new e.Token(o,d,"language-"+o,t)}e.languages.javascript["template-string"]=[a("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),a("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),a("svg",/\bsvg/.source),a("markdown",/\b(?:md|markdown)/.source),a("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),t].filter(Boolean);var d={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function p(e){return"string"==typeof e?e:Array.isArray(e)?e.map(p).join(""):p(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in d&&function t(n){for(var o=0,r=n.length;o/g,t),n&&(e=e+"|"+e.replace(/_/g,"\\*")),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var o=/(?:\\.|``.+?``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,r=/\|?__(?:\|__)+\|?(?:(?:\r?\n|\r)|$)/.source.replace(/__/g,o),i=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\r?\n|\r)/.source;e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+r+i+"(?:"+r+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+r+i+")(?:"+r+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(o),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+r+")"+i+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+r+"$"),inside:{"table-header":{pattern:RegExp(o),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/(^[ \t]*(?:\r?\n|\r))(?: {4}|\t).+(?:(?:\r?\n|\r)(?: {4}|\t).+)*/m,lookbehind:!0,alias:"keyword"},{pattern:/``.+?``|`[^`\r\n]+`/,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\r?\n|\r))[\s\S]+?(?=(?:\r?\n|\r)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\r?\n|\r)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#+.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/__(?:(?!_)|_(?:(?!_))+_)+__/.source,!0),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/_(?:(?!_)|__(?:(?!_))+__)+_/.source,!0),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~))+?\2/.source,!1),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},url:{pattern:n(/!?\[(?:(?!\]))+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)| ?\[(?:(?!\]))+\])/.source,!1),lookbehind:!0,greedy:!0,inside:{variable:{pattern:/(\[)[^\]]+(?=\]$)/,lookbehind:!0},content:{pattern:/(^!?\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},string:{pattern:/"(?:\\.|[^"\\])*"(?=\)$)/}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,o=t.length;n",unchanged:" ",diff:"!"};Object.keys(t).forEach((function(n){var o=t[n],r=[];/^\w+$/.test(n)||r.push(/\w+/.exec(n)[0]),"diff"===n&&r.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+o+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:r}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t})}(a),a.languages.git={comment:/^#.*/m,deleted:/^[-\u2013].*/m,inserted:/^\+.*/m,string:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/m,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s--?\w+/m}},coord:/^@@.*@@$/m,commit_sha1:/^commit \w{40}$/m},a.languages.go=a.languages.extend("clike",{keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,builtin:/\b(?:bool|byte|complex(?:64|128)|error|float(?:32|64)|rune|string|u?int(?:8|16|32|64)?|uintptr|append|cap|close|complex|copy|delete|imag|len|make|new|panic|print(?:ln)?|real|recover)\b/,boolean:/\b(?:_|iota|nil|true|false)\b/,operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,number:/(?:\b0x[a-f\d]+|(?:\b\d+\.?\d*|\B\.\d+)(?:e[-+]?\d+)?)i?/i,string:{pattern:/(["'`])(\\[\s\S]|(?!\1)[^\\])*\1/,greedy:!0}}),delete a.languages.go["class-name"],function(e){e.languages.handlebars={comment:/\{\{![\s\S]*?\}\}/,delimiter:{pattern:/^\{\{\{?|\}\}\}?$/i,alias:"punctuation"},string:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/,boolean:/\b(?:true|false)\b/,block:{pattern:/^(\s*~?\s*)[#\/]\S+?(?=\s*~?\s*$|\s)/i,lookbehind:!0,alias:"keyword"},brackets:{pattern:/\[[^\]]+\]/,inside:{punctuation:/\[|\]/,variable:/[\s\S]+/}},punctuation:/[!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~\s]+/},e.hooks.add("before-tokenize",(function(t){e.languages["markup-templating"].buildPlaceholders(t,"handlebars",/\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\}/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"handlebars")}))}(a),a.languages.json={property:{pattern:/"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,greedy:!0},string:{pattern:/"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,greedy:!0},comment:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,number:/-?\d+\.?\d*(e[+-]?\d+)?/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:true|false)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},a.languages.less=a.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-]+?(?:\([^{}]+\)|[^(){};])*?(?=\s*\{)/i,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\([^{}]*\)|[^{};@])*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/i,operator:/[+\-*\/]/}),a.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-]+.*?(?=[(;])/,lookbehind:!0,alias:"function"}}),a.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|[^\\\r\n])*/,lookbehind:!0},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},builtin:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,symbol:{pattern:/^[^:=\r\n]+(?=\s*:(?!=))/m,inside:{variable:/\$+(?:[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:[/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,{pattern:/(\()(?:addsuffix|abspath|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:s|list)?)(?=[ \t])/,lookbehind:!0}],operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/},a.languages.objectivec=a.languages.extend("c",{keyword:/\b(?:asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while|in|self|super)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,string:/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|@"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,operator:/-[->]?|\+\+?|!=?|<>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete a.languages.objectivec["class-name"],a.languages.ocaml={comment:/\(\*[\s\S]*?\*\)/,string:[{pattern:/"(?:\\.|[^\\\r\n"])*"/,greedy:!0},{pattern:/(['`])(?:\\(?:\d+|x[\da-f]+|.)|(?!\1)[^\\\r\n])\1/i,greedy:!0}],number:/\b(?:0x[\da-f][\da-f_]+|(?:0[bo])?\d[\d_]*\.?[\d_]*(?:e[+-]?[\d_]+)?)/i,type:{pattern:/\B['`]\w*/,alias:"variable"},directive:{pattern:/\B#\w+/,alias:"function"},keyword:/\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|object|of|open|prefix|private|rec|then|sig|struct|to|try|type|val|value|virtual|where|while|with)\b/,boolean:/\b(?:false|true)\b/,operator:/:=|[=<>@^|&+\-*\/$%!?~][!$%&*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lxor|lsl|lsr|mod|nor|or)\b/,punctuation:/[(){}\[\]|_.,:;]/},a.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0},"string-interpolation":{pattern:/(?:f|rf|fr)(?:("""|''')[\s\S]+?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:{{)*){(?!{)(?:[^{}]|{(?!{)(?:[^{}]|{(?!{)(?:[^{}])+})+})+}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|rb|br)?("""|''')[\s\S]+?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|rb|br)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^\s*)@\w+(?:\.\w+)*/i,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:and|as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:True|False|None)\b/,number:/(?:\b(?=\d)|\B(?=\.))(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*\.?\d*|\.\d+)(?:e[+-]?\d+)?j?\b/i,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},a.languages.python["string-interpolation"].inside.interpolation.inside.rest=a.languages.python,a.languages.py=a.languages.python,a.languages.reason=a.languages.extend("clike",{comment:{pattern:/(^|[^\\])\/\*[\s\S]*?\*\//,lookbehind:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:mod|land|lor|lxor|lsl|lsr|asr)\b/}),a.languages.insertBefore("reason","class-name",{character:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,alias:"string"},constructor:{pattern:/\b[A-Z]\w*\b(?!\s*\.)/,alias:"variable"},label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete a.languages.reason.function,function(e){e.languages.sass=e.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t]+.+)*/m,lookbehind:!0}}),e.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,inside:{atrule:/(?:@[\w-]+|[+=])/m}}}),delete e.languages.sass.atrule;var t=/\$[-\w]+|#\{\$[-\w]+\}/,n=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|or|not)\b/,{pattern:/(\s+)-(?=\s)/,lookbehind:!0}];e.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,inside:{punctuation:/:/,variable:t,operator:n}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s]+.*)/m,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:t,operator:n,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,e.languages.insertBefore("sass","punctuation",{selector:{pattern:/([ \t]*)\S(?:,?[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,?[^,\r\n]+)*)*/,lookbehind:!0}})}(a),a.languages.scss=a.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-]+(?:\([^()]+\)|[^(])*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()]|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}]+[:{][^}]+))/m,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[\w-]|\$[-\w]+|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),a.languages.insertBefore("scss","atrule",{keyword:[/@(?:if|else(?: if)?|for|each|while|import|extend|debug|warn|mixin|include|function|return|content)/i,{pattern:/( +)(?:from|through)(?= )/,lookbehind:!0}]}),a.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),a.languages.insertBefore("scss","function",{placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:true|false)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|or|not)(?=\s)/,lookbehind:!0}}),a.languages.scss.atrule.inside.rest=a.languages.scss,a.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:_INSERT|COL)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURNS?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:TRUE|FALSE|NULL)\b/i,number:/\b0x[\da-f]+\b|\b\d+\.?\d*|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|IN|LIKE|NOT|OR|IS|DIV|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t={url:/url\((["']?).*?\1\)/i,string:{pattern:/("|')(?:(?!\1)[^\\\r\n]|\\(?:\r\n|[\s\S]))*\1/,greedy:!0},interpolation:null,func:null,important:/\B!(?:important|optional)\b/i,keyword:{pattern:/(^|\s+)(?:(?:if|else|for|return|unless)(?=\s+|$)|@[\w-]+)/,lookbehind:!0},hexcode:/#[\da-f]{3,6}/i,number:/\b\d+(?:\.\d+)?%?/,boolean:/\b(?:true|false)\b/,operator:[/~|[+!\/%<>?=]=?|[-:]=|\*[*=]?|\.+|&&|\|\||\B-\B|\b(?:and|in|is(?: a| defined| not|nt)?|not|or)\b/],punctuation:/[{}()\[\];:,]/};t.interpolation={pattern:/\{[^\r\n}:]+\}/,alias:"variable",inside:{delimiter:{pattern:/^{|}$/,alias:"punctuation"},rest:t}},t.func={pattern:/[\w-]+\([^)]*\).*/,inside:{function:/^[^(]+/,rest:t}},e.languages.stylus={comment:{pattern:/(^|[^\\])(\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},"atrule-declaration":{pattern:/(^\s*)@.+/m,lookbehind:!0,inside:{atrule:/^@[\w-]+/,rest:t}},"variable-declaration":{pattern:/(^[ \t]*)[\w$-]+\s*.?=[ \t]*(?:(?:\{[^}]*\}|.+)|$)/m,lookbehind:!0,inside:{variable:/^\S+/,rest:t}},statement:{pattern:/(^[ \t]*)(?:if|else|for|return|unless)[ \t]+.+/m,lookbehind:!0,inside:{keyword:/^\S+/,rest:t}},"property-declaration":{pattern:/((?:^|\{)([ \t]*))(?:[\w-]|\{[^}\r\n]+\})+(?:\s*:\s*|[ \t]+)[^{\r\n]*(?:;|[^{\r\n,](?=$)(?!(\r?\n|\r)(?:\{|\2[ \t]+)))/m,lookbehind:!0,inside:{property:{pattern:/^[^\s:]+/,inside:{interpolation:t.interpolation}},rest:t}},selector:{pattern:/(^[ \t]*)(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\))?|\{[^}\r\n]+\})+)(?:(?:\r?\n|\r)(?:\1(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\))?|\{[^}\r\n]+\})+)))*(?:,$|\{|(?=(?:\r?\n|\r)(?:\{|\1[ \t]+)))/m,lookbehind:!0,inside:{interpolation:t.interpolation,punctuation:/[{},]/}},func:t.func,string:t.string,interpolation:t.interpolation,punctuation:/[{}()\[\];:.]/}}(a);var u=a.util.clone(a.languages.typescript);a.languages.tsx=a.languages.extend("jsx",u),a.languages.wasm={comment:[/\(;[\s\S]*?;\)/,{pattern:/;;.*/,greedy:!0}],string:{pattern:/"(?:\\[\s\S]|[^"\\])*"/,greedy:!0},keyword:[{pattern:/\b(?:align|offset)=/,inside:{operator:/=/}},{pattern:/\b(?:(?:f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|nearest|neg?|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|store(?:8|16|32)?|sqrt|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))?|memory\.(?:grow|size))\b/,inside:{punctuation:/\./}},/\b(?:anyfunc|block|br(?:_if|_table)?|call(?:_indirect)?|data|drop|elem|else|end|export|func|get_(?:global|local)|global|if|import|local|loop|memory|module|mut|nop|offset|param|result|return|select|set_(?:global|local)|start|table|tee_local|then|type|unreachable)\b/],variable:/\$[\w!#$%&'*+\-./:<=>?@\\^_`|~]+/i,number:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/,punctuation:/[()]/},a.languages.yaml={scalar:{pattern:/([\-:]\s*(?:![^\s]+)?[ \t]*[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)[^\r\n]+(?:\2[^\r\n]+)*)/,lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:/(\s*(?:^|[:\-,[{\r\n?])[ \t]*(?:![^\s]+)?[ \t]*)[^\r\n{[\]},#\s]+?(?=\s*:\s)/,lookbehind:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:/([:\-,[{]\s*(?:![^\s]+)?[ \t]*)(?:\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?)?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?)(?=[ \t]*(?:$|,|]|}))/m,lookbehind:!0,alias:"number"},boolean:{pattern:/([:\-,[{]\s*(?:![^\s]+)?[ \t]*)(?:true|false)[ \t]*(?=$|,|]|})/im,lookbehind:!0,alias:"important"},null:{pattern:/([:\-,[{]\s*(?:![^\s]+)?[ \t]*)(?:null|~)[ \t]*(?=$|,|]|})/im,lookbehind:!0,alias:"important"},string:{pattern:/([:\-,[{]\s*(?:![^\s]+)?[ \t]*)("|')(?:(?!\2)[^\\\r\n]|\\.)*\2(?=[ \t]*(?:$|,|]|}|\s*#))/m,lookbehind:!0,greedy:!0},number:{pattern:/([:\-,[{]\s*(?:![^\s]+)?[ \t]*)[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+\.?\d*|\.?\d+)(?:e[+-]?\d+)?|\.inf|\.nan)[ \t]*(?=$|,|]|})/im,lookbehind:!0},tag:/![^\s]+/,important:/[&*][\w]+/,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},a.languages.yml=a.languages.yaml,t.a=a},function(e,t,n){var o=n(23);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==o(e)?e.split(""):Object(e)}},function(e,t,n){"use strict";var o=n(36),r=RegExp.prototype.exec;e.exports=function(e,t){var n=e.exec;if("function"==typeof n){var i=n.call(e,t);if("object"!=typeof i)throw new TypeError("RegExp exec method returned something other than an Object or null");return i}if("RegExp"!==o(e))throw new TypeError("RegExp#exec called on incompatible receiver");return r.call(e,t)}},function(e,t,n){"use strict";n(103);var o=n(16),r=n(11),i=n(14),a=n(34),u=n(2),l=n(45),s=u("species"),c=!i((function(){var e=/./;return e.exec=function(){var e=[];return e.groups={a:"7"},e},"7"!=="".replace(e,"$")})),d=function(){var e=/(?:)/,t=e.exec;e.exec=function(){return t.apply(this,arguments)};var n="ab".split(e);return 2===n.length&&"a"===n[0]&&"b"===n[1]}();e.exports=function(e,t,n){var p=u(e),f=!i((function(){var t={};return t[p]=function(){return 7},7!=""[e](t)})),g=f?!i((function(){var t=!1,n=/a/;return n.exec=function(){return t=!0,null},"split"===e&&(n.constructor={},n.constructor[s]=function(){return n}),n[p](""),!t})):void 0;if(!f||!g||"replace"===e&&!c||"split"===e&&!d){var m=/./[p],h=n(a,p,""[e],(function(e,t,n,o,r){return t.exec===l?f&&!r?{done:!0,value:m.call(t,n,o)}:{done:!0,value:e.call(n,t,o)}:{done:!1}})),b=h[0],v=h[1];o(String.prototype,e,b),r(RegExp.prototype,p,2==t?function(e,t){return v.call(e,this,t)}:function(e){return v.call(e,this)})}}},function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t,n){"use strict";var o,r,i,a,u=n(44),l=n(5),s=n(30),c=n(36),d=n(12),p=n(13),f=n(32),g=n(80),m=n(81),h=n(63),b=n(70).set,v=n(122)(),y=n(71),w=n(123),k=n(124),x=n(125),E=l.TypeError,_=l.process,S=_&&_.versions,T=S&&S.v8||"",P=l.Promise,C="process"==c(_),O=function(){},A=r=y.f,q=!!function(){try{var e=P.resolve(1),t=(e.constructor={})[n(2)("species")]=function(e){e(O,O)};return(C||"function"==typeof PromiseRejectionEvent)&&e.then(O)instanceof t&&0!==T.indexOf("6.6")&&-1===k.indexOf("Chrome/66")}catch(o){}}(),R=function(e){var t;return!(!p(e)||"function"!=typeof(t=e.then))&&t},N=function(e,t){if(!e._n){e._n=!0;var n=e._c;v((function(){for(var o=e._v,r=1==e._s,i=0,a=function(t){var n,i,a,u=r?t.ok:t.fail,l=t.resolve,s=t.reject,c=t.domain;try{u?(r||(2==e._h&&j(e),e._h=1),!0===u?n=o:(c&&c.enter(),n=u(o),c&&(c.exit(),a=!0)),n===t.promise?s(E("Promise-chain cycle")):(i=R(n))?i.call(n,l,s):l(n)):s(o)}catch(d){c&&!a&&c.exit(),s(d)}};n.length>i;)a(n[i++]);e._c=[],e._n=!1,t&&!e._h&&I(e)}))}},I=function(e){b.call(l,(function(){var t,n,o,r=e._v,i=z(e);if(i&&(t=w((function(){C?_.emit("unhandledRejection",r,e):(n=l.onunhandledrejection)?n({promise:e,reason:r}):(o=l.console)&&o.error&&o.error("Unhandled promise rejection",r)})),e._h=C||z(e)?2:1),e._a=void 0,i&&t.e)throw t.v}))},z=function(e){return 1!==e._h&&0===(e._a||e._c).length},j=function(e){b.call(l,(function(){var t;C?_.emit("rejectionHandled",e):(t=l.onrejectionhandled)&&t({promise:e,reason:e._v})}))},L=function(e){var t=this;t._d||(t._d=!0,(t=t._w||t)._v=e,t._s=2,t._a||(t._a=t._c.slice()),N(t,!0))},F=function(e){var t,n=this;if(!n._d){n._d=!0,n=n._w||n;try{if(n===e)throw E("Promise can't be resolved itself");(t=R(e))?v((function(){var o={_w:n,_d:!1};try{t.call(e,s(F,o,1),s(L,o,1))}catch(r){L.call(o,r)}})):(n._v=e,n._s=1,N(n,!1))}catch(o){L.call({_w:n,_d:!1},o)}}};q||(P=function(e){g(this,P,"Promise","_h"),f(e),o.call(this);try{e(s(F,this,1),s(L,this,1))}catch(t){L.call(this,t)}},(o=function(e){this._c=[],this._a=void 0,this._s=0,this._d=!1,this._v=void 0,this._h=0,this._n=!1}).prototype=n(82)(P.prototype,{then:function(e,t){var n=A(h(this,P));return n.ok="function"!=typeof e||e,n.fail="function"==typeof t&&t,n.domain=C?_.domain:void 0,this._c.push(n),this._a&&this._a.push(n),this._s&&N(this,!1),n.promise},catch:function(e){return this.then(void 0,e)}}),i=function(){var e=new o;this.promise=e,this.resolve=s(F,e,1),this.reject=s(L,e,1)},y.f=A=function(e){return e===P||e===a?new i(e):r(e)}),d(d.G+d.W+d.F*!q,{Promise:P}),n(41)(P,"Promise"),n(94)("Promise"),a=n(17).Promise,d(d.S+d.F*!q,"Promise",{reject:function(e){var t=A(this);return(0,t.reject)(e),t.promise}}),d(d.S+d.F*(u||!q),"Promise",{resolve:function(e){return x(u&&this===a?P:this,e)}}),d(d.S+d.F*!(q&&n(83)((function(e){P.all(e).catch(O)}))),"Promise",{all:function(e){var t=this,n=A(t),o=n.resolve,r=n.reject,i=w((function(){var n=[],i=0,a=1;m(e,!1,(function(e){var u=i++,l=!1;n.push(void 0),a++,t.resolve(e).then((function(e){l||(l=!0,n[u]=e,--a||o(n))}),r)})),--a||o(n)}));return i.e&&r(i.v),n.promise},race:function(e){var t=this,n=A(t),o=n.reject,r=w((function(){m(e,!1,(function(e){t.resolve(e).then(n.resolve,o)}))}));return r.e&&o(r.v),n.promise}})},function(e,t,n){"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE){0;try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}}(),e.exports=n(99)},function(e,t,n){"use strict";var o=n(64)(!0);e.exports=function(e,t,n){return t+(n?o(e,t).length:1)}},function(e,t,n){"use strict";var o=n(44),r=n(12),i=n(16),a=n(11),u=n(24),l=n(105),s=n(41),c=n(108),d=n(2)("iterator"),p=!([].keys&&"next"in[].keys()),f=function(){return this};e.exports=function(e,t,n,g,m,h,b){l(n,t,g);var v,y,w,k=function(e){if(!p&&e in S)return S[e];switch(e){case"keys":case"values":return function(){return new n(this,e)}}return function(){return new n(this,e)}},x=t+" Iterator",E="values"==m,_=!1,S=e.prototype,T=S[d]||S["@@iterator"]||m&&S[m],P=T||k(m),C=m?E?k("entries"):P:void 0,O="Array"==t&&S.entries||T;if(O&&(w=c(O.call(new e)))!==Object.prototype&&w.next&&(s(w,x,!0),o||"function"==typeof w[d]||a(w,d,f)),E&&T&&"values"!==T.name&&(_=!0,P=function(){return T.call(this)}),o&&!b||!p&&!_&&S[d]||a(S,d,P),u[t]=P,u[x]=f,m)if(v={values:E?P:k("values"),keys:h?P:k("keys"),entries:C},b)for(y in v)y in S||i(S,y,v[y]);else r(r.P+r.F*(p||_),t,v);return v}},function(e,t){t.f={}.propertyIsEnumerable},function(e,t,n){var o=n(8),r=n(32),i=n(2)("species");e.exports=function(e,t){var n,a=o(e).constructor;return void 0===a||null==(n=o(a)[i])?t:r(n)}},function(e,t,n){var o=n(35),r=n(34);e.exports=function(e){return function(t,n){var i,a,u=String(r(t)),l=o(n),s=u.length;return l<0||l>=s?e?"":void 0:(i=u.charCodeAt(l))<55296||i>56319||l+1===s||(a=u.charCodeAt(l+1))<56320||a>57343?e?u.charAt(l):i:e?u.slice(l,l+2):a-56320+(i-55296<<10)+65536}}},function(e,t){e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(e,t,n){var o=n(5).document;e.exports=o&&o.documentElement},function(e,t,n){"use strict";var o=n(19);t.a=o.b},function(e,t,n){"use strict";e.exports=n(113)},function(e,t,n){"use strict";var o=n(0),r=n.n(o);t.a=r.a.createContext({})},function(e,t,n){var o,r,i,a=n(30),u=n(121),l=n(66),s=n(46),c=n(5),d=c.process,p=c.setImmediate,f=c.clearImmediate,g=c.MessageChannel,m=c.Dispatch,h=0,b={},v=function(){var e=+this;if(b.hasOwnProperty(e)){var t=b[e];delete b[e],t()}},y=function(e){v.call(e.data)};p&&f||(p=function(e){for(var t=[],n=1;arguments.length>n;)t.push(arguments[n++]);return b[++h]=function(){u("function"==typeof e?e:Function(e),t)},o(h),h},f=function(e){delete b[e]},"process"==n(23)(d)?o=function(e){d.nextTick(a(v,e,1))}:m&&m.now?o=function(e){m.now(a(v,e,1))}:g?(i=(r=new g).port2,r.port1.onmessage=y,o=a(i.postMessage,i,1)):c.addEventListener&&"function"==typeof postMessage&&!c.importScripts?(o=function(e){c.postMessage(e+"","*")},c.addEventListener("message",y,!1)):o="onreadystatechange"in s("script")?function(e){l.appendChild(s("script")).onreadystatechange=function(){l.removeChild(this),v.call(e)}}:function(e){setTimeout(a(v,e,1),0)}),e.exports={set:p,clear:f}},function(e,t,n){"use strict";var o=n(32);function r(e){var t,n;this.promise=new e((function(e,o){if(void 0!==t||void 0!==n)throw TypeError("Bad Promise constructor");t=e,n=o})),this.resolve=o(t),this.reject=o(n)}e.exports.f=function(e){return new r(e)}},function(e,t,n){"use strict";(function(t){var n="__global_unique_id__";e.exports=function(){return t[n]=(t[n]||0)+1}}).call(this,n(76))},function(e,t,n){"use strict";var o=n(68),r={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},i={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},a={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},u={};function l(e){return o.isMemo(e)?a:u[e.$$typeof]||r}u[o.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},u[o.Memo]=a;var s=Object.defineProperty,c=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,p=Object.getOwnPropertyDescriptor,f=Object.getPrototypeOf,g=Object.prototype;e.exports=function e(t,n,o){if("string"!=typeof n){if(g){var r=f(n);r&&r!==g&&e(t,r,o)}var a=c(n);d&&(a=a.concat(d(n)));for(var u=l(t),m=l(n),h=0;h]*>)/g,f=/\$([$&`']|\d\d?)/g;n(56)("replace",2,(function(e,t,n,g){return[function(o,r){var i=e(this),a=null==o?void 0:o[t];return void 0!==a?a.call(o,i,r):n.call(String(i),o,r)},function(e,t){var r=g(n,e,this,t);if(r.done)return r.value;var d=o(e),p=String(this),f="function"==typeof t;f||(t=String(t));var h=d.global;if(h){var b=d.unicode;d.lastIndex=0}for(var v=[];;){var y=l(d,p);if(null===y)break;if(v.push(y),!h)break;""===String(y[0])&&(d.lastIndex=u(p,i(d.lastIndex),b))}for(var w,k="",x=0,E=0;E=x&&(k+=p.slice(x,S)+A,x=S+_.length)}return k+p.slice(x)}];function m(e,t,o,i,a,u){var l=o+e.length,s=i.length,c=f;return void 0!==a&&(a=r(a),c=p),n.call(u,c,(function(n,r){var u;switch(r.charAt(0)){case"$":return"$";case"&":return e;case"`":return t.slice(0,o);case"'":return t.slice(l);case"<":u=a[r.slice(1,-1)];break;default:var c=+r;if(0===c)return n;if(c>s){var p=d(c/10);return 0===p?n:p<=s?void 0===i[p-1]?r.charAt(1):i[p-1]+r.charAt(1):n}u=i[c-1]}return void 0===u?"":u}))}}))},function(e,t,n){"use strict";var o=n(95),r=n(8),i=n(63),a=n(60),u=n(26),l=n(55),s=n(45),c=n(14),d=Math.min,p=[].push,f="length",g=!c((function(){RegExp(4294967295,"y")}));n(56)("split",2,(function(e,t,n,c){var m;return m="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1)[f]||2!="ab".split(/(?:ab)*/)[f]||4!=".".split(/(.?)(.?)/)[f]||".".split(/()()/)[f]>1||"".split(/.?/)[f]?function(e,t){var r=String(this);if(void 0===e&&0===t)return[];if(!o(e))return n.call(r,e,t);for(var i,a,u,l=[],c=(e.ignoreCase?"i":"")+(e.multiline?"m":"")+(e.unicode?"u":"")+(e.sticky?"y":""),d=0,g=void 0===t?4294967295:t>>>0,m=new RegExp(e.source,c+"g");(i=s.call(m,r))&&!((a=m.lastIndex)>d&&(l.push(r.slice(d,i.index)),i[f]>1&&i.index=g));)m.lastIndex===i.index&&m.lastIndex++;return d===r[f]?!u&&m.test("")||l.push(""):l.push(r.slice(d)),l[f]>g?l.slice(0,g):l}:"0".split(void 0,0)[f]?function(e,t){return void 0===e&&0===t?[]:n.call(this,e,t)}:n,[function(n,o){var r=e(this),i=null==n?void 0:n[t];return void 0!==i?i.call(n,r,o):m.call(String(r),n,o)},function(e,t){var o=c(m,e,this,t,m!==n);if(o.done)return o.value;var s=r(e),p=String(this),f=i(s,RegExp),h=s.unicode,b=(s.ignoreCase?"i":"")+(s.multiline?"m":"")+(s.unicode?"u":"")+(g?"y":"g"),v=new f(g?s:"^(?:"+s.source+")",b),y=void 0===t?4294967295:t>>>0;if(0===y)return[];if(0===p.length)return null===l(v,p)?[p]:[];for(var w=0,k=0,x=[];k=t.length?{value:void 0,done:!0}:(e=o(t,n),this._i+=e.length,{value:e,done:!1})}))},function(e,t){e.exports=function(e,t,n,o){if(!(e instanceof t)||void 0!==o&&o in e)throw TypeError(n+": incorrect invocation!");return e}},function(e,t,n){var o=n(30),r=n(91),i=n(92),a=n(8),u=n(26),l=n(93),s={},c={};(t=e.exports=function(e,t,n,d,p){var f,g,m,h,b=p?function(){return e}:l(e),v=o(n,d,t?2:1),y=0;if("function"!=typeof b)throw TypeError(e+" is not iterable!");if(i(b)){for(f=u(e.length);f>y;y++)if((h=t?v(a(g=e[y])[0],g[1]):v(e[y]))===s||h===c)return h}else for(m=b.call(e);!(g=m.next()).done;)if((h=r(m,v,g.value,t))===s||h===c)return h}).BREAK=s,t.RETURN=c},function(e,t,n){var o=n(16);e.exports=function(e,t,n){for(var r in t)o(e,r,t[r],n);return e}},function(e,t,n){var o=n(2)("iterator"),r=!1;try{var i=[7][o]();i.return=function(){r=!0},Array.from(i,(function(){throw 2}))}catch(a){}e.exports=function(e,t){if(!t&&!r)return!1;var n=!1;try{var i=[7],u=i[o]();u.next=function(){return{done:n=!0}},i[o]=function(){return u},e(i)}catch(a){}return n}},function(e,t,n){var o=n(12);o(o.S+o.F,"Object",{assign:n(126)})},function(e,t,n){var o=n(12),r=n(129)(!1);o(o.S,"Object",{values:function(e){return r(e)}})},function(e,t,n){e.exports=!n(10)&&!n(14)((function(){return 7!=Object.defineProperty(n(46)("div"),"a",{get:function(){return 7}}).a}))},function(e,t,n){var o=n(13);e.exports=function(e,t){if(!o(e))return e;var n,r;if(t&&"function"==typeof(n=e.toString)&&!o(r=n.call(e)))return r;if("function"==typeof(n=e.valueOf)&&!o(r=n.call(e)))return r;if(!t&&"function"==typeof(n=e.toString)&&!o(r=n.call(e)))return r;throw TypeError("Can't convert object to primitive value")}},function(e,t){e.exports=function(e,t){return{value:t,done:!!e}}},function(e,t,n){var o=n(8),r=n(106),i=n(65),a=n(47)("IE_PROTO"),u=function(){},l=function(){var e,t=n(46)("iframe"),o=i.length;for(t.style.display="none",n(66).appendChild(t),t.src="javascript:",(e=t.contentWindow.document).open(),e.write("